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