xref: /6.6.0/couchstore/src/views/reductions.cc (revision f798e0b7)
1/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
3#include "reductions.h"
4
5#include "../bitfield.h"
6#include "../couch_btree.h"
7
8#include <platform/cb_malloc.h>
9#include <stdlib.h>
10#include <string.h>
11#include <platform/cbassert.h>
12
13#define BITMASK_BYTE_SIZE      (1024 / CHAR_BIT)
14
15#define dec_uint16(b) (decode_raw16(*((raw_16 *) b)))
16#define dec_uint48(b) (decode_raw48(*((raw_48 *) b)))
17#define dec_uint40(b) (decode_raw40(*((raw_40 *) b)))
18
19static void enc_uint16(uint16_t u, char **buf);
20
21static void enc_raw40(uint64_t u, char **buf);
22
23uint64_t decode_view_btree_reduction_partitions_bitmap(
24        const char* bytes, size_t len, bitmap_t& partitions_bitmap) {
25    cb_assert(len >= 5);
26    uint64_t kv_count = dec_uint40(bytes);
27    bytes += 5;
28    len -= 5;
29
30    cb_assert(len >= BITMASK_BYTE_SIZE);
31    memcpy(&partitions_bitmap, bytes, BITMASK_BYTE_SIZE);
32    return kv_count;
33}
34
35couchstore_error_t decode_view_btree_reduction(const char* bytes,
36                                               size_t len,
37                                               view_btree_reduction_t& r) {
38    uint8_t  i, j;
39    uint16_t sz;
40    const char *bs;
41    size_t length;
42
43    // Get the count and bitmap and advance bytes
44    r.kv_count = decode_view_btree_reduction_partitions_bitmap(
45            bytes, len, r.partitions_bitmap);
46    bytes += (5 + BITMASK_BYTE_SIZE);
47    len -= (5 + BITMASK_BYTE_SIZE);
48
49    bs = bytes;
50    length = len;
51
52    r.num_values = 0;
53    size_t buffer_size = 0;
54    while (len > 0) {
55
56        cb_assert(len >= 2);
57        sz = dec_uint16(bs);
58        bs += 2;
59        len -= 2;
60
61        cb_assert(len >= sz);
62        bs += sz;
63        len -= sz;
64        r.num_values++;
65        buffer_size += sz;
66    }
67
68    if (len > 0) {
69        return COUCHSTORE_ERROR_CORRUPT;
70    }
71
72    if (r.num_values > 0) {
73        try {
74            r.buffer.resize((r.num_values * sizeof(sized_buf)) + buffer_size);
75        } catch (const std::bad_alloc&) {
76            return COUCHSTORE_ERROR_ALLOC_FAIL;
77        }
78        r.reduce_values = reinterpret_cast<sized_buf*>(r.buffer.data());
79    } else {
80        return COUCHSTORE_SUCCESS;
81    }
82
83    for (j = 0; j < r.num_values; ++j) {
84        r.reduce_values[j].buf = NULL;
85    }
86
87    i = 0;
88    len = length;
89    char* currentBuffer = r.buffer.data() + (r.num_values * sizeof(sized_buf));
90    while (len > 0) {
91
92        sz = dec_uint16(bytes);
93        bytes += 2;
94        len -= 2;
95
96        r.reduce_values[i].size = sz;
97        r.reduce_values[i].buf = currentBuffer;
98
99        memcpy(r.reduce_values[i].buf, bytes, sz);
100        bytes += sz;
101        len -= sz;
102        i++;
103        currentBuffer += sz;
104    }
105
106    return COUCHSTORE_SUCCESS;
107}
108
109couchstore_error_t encode_view_btree_reduction(const view_btree_reduction_t *reduction,
110                                               char *buffer,
111                                               size_t *buffer_size)
112{
113    char *b = NULL;
114    size_t sz = 0;
115    int i;
116
117    sz += 5;                     /* kv_count */
118    sz += BITMASK_BYTE_SIZE; /* partitions bitmap */
119    /* reduce values */
120    for (i = 0; i < reduction->num_values; ++i) {
121        sz += 2;             /* size_t */
122        sz += reduction->reduce_values[i].size;
123    }
124
125    if (sz > MAX_REDUCTION_SIZE) {
126        return COUCHSTORE_ERROR_REDUCTION_TOO_LARGE;
127    }
128
129    b = buffer;
130
131    enc_raw40(reduction->kv_count, &b);
132
133    memcpy(b, &reduction->partitions_bitmap, BITMASK_BYTE_SIZE);
134    b += BITMASK_BYTE_SIZE;
135
136    for (i = 0; i < reduction->num_values; ++i) {
137        enc_uint16(reduction->reduce_values[i].size, &b);
138
139        memcpy(b, reduction->reduce_values[i].buf, reduction->reduce_values[i].size);
140        b += reduction->reduce_values[i].size;
141    }
142
143    *buffer_size = sz;
144
145    return COUCHSTORE_SUCCESS;
146}
147
148
149void free_view_btree_reduction(view_btree_reduction_t *reduction)
150{
151    int i;
152
153    if (reduction == NULL) {
154        return;
155    }
156
157    if (reduction->reduce_values != NULL){
158        for (i = 0; i < reduction->num_values; ++i) {
159            cb_free(reduction->reduce_values[i].buf);
160        }
161        cb_free(reduction->reduce_values);
162    }
163
164    cb_free(reduction);
165}
166
167
168couchstore_error_t decode_view_id_btree_reduction(const char *bytes,
169                                                  view_id_btree_reduction_t **reduction)
170{
171    view_id_btree_reduction_t *r = NULL;
172
173    r = (view_id_btree_reduction_t *) cb_malloc(sizeof(view_id_btree_reduction_t));
174    if (r == NULL) {
175        goto alloc_error;
176    }
177
178    r->kv_count = dec_uint40(bytes);
179    bytes += 5;
180
181    memcpy(&r->partitions_bitmap, bytes, BITMASK_BYTE_SIZE);
182
183    *reduction = r;
184
185    return COUCHSTORE_SUCCESS;
186
187 alloc_error:
188    free_view_id_btree_reduction(r);
189    return COUCHSTORE_ERROR_ALLOC_FAIL;
190}
191
192
193couchstore_error_t encode_view_id_btree_reduction(const view_id_btree_reduction_t *reduction,
194                                                  char *buffer,
195                                                  size_t *buffer_size)
196{
197    char *b = NULL;
198    size_t sz = 0;
199
200    sz += 5;                     /* kv_count */
201    sz += BITMASK_BYTE_SIZE; /* partitions bitmap */
202
203    if (sz > MAX_REDUCTION_SIZE) {
204        return COUCHSTORE_ERROR_REDUCTION_TOO_LARGE;
205    }
206
207    b = buffer;
208
209    enc_raw40(reduction->kv_count, &b);
210
211    memcpy(b, &reduction->partitions_bitmap, BITMASK_BYTE_SIZE);
212
213    *buffer_size = sz;
214
215    return COUCHSTORE_SUCCESS;
216}
217
218
219void free_view_id_btree_reduction(view_id_btree_reduction_t *reduction)
220{
221    if (reduction == NULL) {
222        return;
223    }
224
225    cb_free(reduction);
226}
227
228static void enc_uint16(uint16_t u, char **buf)
229{
230    raw_16 r = encode_raw16(u);
231    memcpy(*buf, &r, 2);
232    *buf += 2;
233}
234
235
236static void enc_raw40(uint64_t u, char **buf)
237{
238    raw_40 r;
239    encode_raw40(u, &r);
240    memcpy(*buf, &r, 5);
241    *buf += 5;
242}
243