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