1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
3 #ident "$Id$"
4 /*======
5 This file is part of PerconaFT.
6
7
8 Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
9
10 PerconaFT is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License, version 2,
12 as published by the Free Software Foundation.
13
14 PerconaFT is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with PerconaFT. If not, see <http://www.gnu.org/licenses/>.
21
22 ----------------------------------------
23
24 PerconaFT is free software: you can redistribute it and/or modify
25 it under the terms of the GNU Affero General Public License, version 3,
26 as published by the Free Software Foundation.
27
28 PerconaFT is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 GNU Affero General Public License for more details.
32
33 You should have received a copy of the GNU Affero General Public License
34 along with PerconaFT. If not, see <http://www.gnu.org/licenses/>.
35 ======= */
36
37 #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
38
39 #include "test.h"
40
41 #include <util/dmt.h>
42
43 static void
parse_args(int argc,const char * argv[])44 parse_args (int argc, const char *argv[]) {
45 const char *argv0=argv[0];
46 while (argc>1) {
47 int resultcode=0;
48 if (strcmp(argv[1], "-v")==0) {
49 verbose++;
50 } else if (strcmp(argv[1], "-q")==0) {
51 verbose = 0;
52 } else if (strcmp(argv[1], "-h")==0) {
53 do_usage:
54 fprintf(stderr, "Usage:\n%s [-v|-h]\n", argv0);
55 exit(resultcode);
56 } else {
57 resultcode=1;
58 goto do_usage;
59 }
60 argc--;
61 argv++;
62 }
63 }
64 /* End ".h like" stuff. */
65
66 struct value {
67 uint32_t number;
68 };
69 #define V(x) ((struct value *)(x))
70
71
72
73 const uint32_t MAXNUM = 1024;
74 const uint32_t MAXLEN = 32;
75 char data[MAXNUM][MAXLEN];
76
77 struct val_type {
78 char c[MAXLEN];
79 };
80
81 namespace toku {
82 class vwriter {
83 public:
get_size(void) const84 size_t get_size(void) const {
85 size_t len = strlen(v.c);
86 invariant(len < sizeof(val_type));
87 return len + 1;
88 }
write_to(val_type * const dest) const89 void write_to(val_type *const dest) const {
90 strcpy(dest->c, v.c);
91 }
92
vwriter(const char * c)93 vwriter(const char* c) {
94 invariant(strlen(c) < sizeof(val_type));
95 strcpy(v.c, c);
96 }
97
vwriter(const uint32_t klpair_len,val_type * const src)98 vwriter(const uint32_t klpair_len, val_type *const src) {
99 invariant(strlen(src->c) < sizeof(val_type));
100 strcpy(v.c, src->c);
101 invariant(klpair_len == get_size());
102 }
103 private:
104 val_type v;
105 };
106 }
107
108 /* Globals */
109 typedef toku::dmt<val_type, val_type*, toku::vwriter> vdmt;
110
111 const unsigned int random_seed = 0xFEADACBA;
112
113 ///////////////
114
115
fail_one_verify(uint32_t len,uint32_t num,vdmt * v)116 static void fail_one_verify(uint32_t len, uint32_t num, vdmt *v) {
117 val_type* fetched_data;
118 int count = 0;
119 v->verify();
120 for (uint32_t i = 0; i < num; i++) {
121 uint32_t fetched_len;
122 int r = v->fetch(i-count, &fetched_len, &fetched_data);
123 if (r != 0 || fetched_len != len || strcmp(fetched_data->c, data[i])) {
124 count++;
125 continue;
126 }
127 }
128 invariant(count == 1);
129 }
130
verify(uint32_t len,uint32_t num,vdmt * v)131 static void verify(uint32_t len, uint32_t num, vdmt *v) {
132 v->verify();
133 val_type* fetched_data;
134 for (uint32_t i = 0; i < num; i++) {
135 uint32_t fetched_len;
136 int r = v->fetch(i, &fetched_len, &fetched_data);
137 CKERR(r);
138 invariant(fetched_len == len);
139 invariant(!strcmp(fetched_data->c, data[i]));
140 }
141 }
142
143
test_builder_fixed(uint32_t len,uint32_t num)144 static void test_builder_fixed(uint32_t len, uint32_t num) {
145 srandom(random_seed);
146 assert(len > 1);
147 assert(len <= MAXLEN);
148 assert(num <= MAXNUM);
149 for (uint32_t i = 0; i < num; i++) {
150 for (uint32_t j = 0; j < len-1; j++) {
151 data[i][j] = random() % 255 + 1; //This way it doesn't end up being 0 and thought of as NUL
152 }
153 data[i][len-1] = '\0'; //cap it
154 }
155
156 vdmt::builder builder;
157 builder.create(num, num * len);
158
159 for (uint32_t i = 0; i < num; i++) {
160 vwriter vfun(data[i]);
161 builder.append(vfun);
162 }
163 invariant(builder.value_length_is_fixed());
164 vdmt v;
165 builder.build(&v);
166 invariant(v.value_length_is_fixed());
167 invariant(v.get_fixed_length() == len || num == 0);
168
169 invariant(v.size() == num);
170
171 verify(len, num, &v);
172
173 for (uint32_t change = 0; change < num; change++) {
174 vdmt v2;
175 v2.clone(v);
176 v2.delete_at(change);
177 fail_one_verify(len, num, &v2);
178
179 vwriter vfun(data[change]);
180 v2.insert_at(vfun, change);
181 verify(len, num, &v2);
182 v2.destroy();
183 }
184
185 v.destroy();
186 }
187
test_builder_variable(uint32_t len,uint32_t len2,uint32_t num)188 static void test_builder_variable(uint32_t len, uint32_t len2, uint32_t num) {
189 srandom(random_seed);
190 assert(len > 1);
191 assert(len <= MAXLEN);
192 assert(num <= MAXNUM);
193 assert(num > 3);
194 uint32_t which2 = random() % num;
195 for (uint32_t i = 0; i < num; i++) {
196 uint32_t thislen = i == which2 ? len2 : len;
197 for (uint32_t j = 0; j < thislen-1; j++) {
198 data[i][j] = random() % 255 + 1; //This way it doesn't end up being 0 and thought of as NUL
199 }
200 data[i][thislen-1] = '\0'; //cap it
201 }
202
203 vdmt::builder builder;
204 builder.create(num, (num-1) * len + len2);
205
206 for (uint32_t i = 0; i < num; i++) {
207 vwriter vfun(data[i]);
208 builder.append(vfun);
209 }
210 invariant(!builder.value_length_is_fixed());
211 vdmt v;
212 builder.build(&v);
213 invariant(!v.value_length_is_fixed());
214
215 invariant(v.size() == num);
216
217 val_type* fetched_data;
218 for (uint32_t i = 0; i < num; i++) {
219 uint32_t fetched_len;
220 int r = v.fetch(i, &fetched_len, &fetched_data);
221 CKERR(r);
222 if (i == which2) {
223 invariant(fetched_len == len2);
224 invariant(!strcmp(fetched_data->c, data[i]));
225 } else {
226 invariant(fetched_len == len);
227 invariant(!strcmp(fetched_data->c, data[i]));
228 }
229 }
230
231 v.destroy();
232 }
233
test_create_from_sorted_memory_of_fixed_sized_elements_and_serialize(uint32_t len,uint32_t num)234 static void test_create_from_sorted_memory_of_fixed_sized_elements_and_serialize(uint32_t len, uint32_t num) {
235 srandom(random_seed);
236 assert(len <= MAXLEN);
237 assert(num <= MAXNUM);
238 for (uint32_t i = 0; i < num; i++) {
239 for (uint32_t j = 0; j < len-1; j++) {
240 data[i][j] = random() % 255 + 1; //This way it doesn't end up being 0 and thought of as NUL
241 }
242 data[i][len-1] = '\0'; //cap it
243 }
244
245 char *flat = (char*)toku_xmalloc(len * num);
246 char *p = flat;
247 for (uint32_t i = 0; i < num; i++) {
248 memcpy(p, data[i], len);
249 p += len;
250 }
251 vdmt v;
252
253 v.create_from_sorted_memory_of_fixed_size_elements(flat, num, len*num, len);
254 invariant(v.value_length_is_fixed());
255 invariant(v.get_fixed_length() == len);
256
257 invariant(v.size() == num);
258
259 val_type* fetched_data;
260 for (uint32_t i = 0; i < num; i++) {
261 uint32_t fetched_len;
262 int r = v.fetch(i, &fetched_len, &fetched_data);
263 CKERR(r);
264 invariant(fetched_len == len);
265 invariant(!strcmp(fetched_data->c, data[i]));
266 }
267
268 char *serialized_flat = (char*)toku_xmalloc(len*num);
269 struct wbuf wb;
270 wbuf_nocrc_init(&wb, serialized_flat, len*num);
271 v.prepare_for_serialize();
272 v.serialize_values(len*num, &wb);
273 invariant(!memcmp(serialized_flat, flat, len*num));
274
275
276 if (num > 1) {
277 //Currently converting to dtree treats the entire thing as NOT fixed length.
278 //Optional additional perf here.
279 uint32_t which = (random() % (num-1)) + 1; // Not last, not first
280 invariant(which > 0 && which < num-1);
281 v.delete_at(which);
282
283 memmove(flat + which*len, flat+(which+1)*len, (num-which-1) * len);
284 v.prepare_for_serialize();
285 wbuf_nocrc_init(&wb, serialized_flat, len*(num-1));
286 v.serialize_values(len*(num-1), &wb);
287 invariant(!memcmp(serialized_flat, flat, len*(num-1)));
288 }
289
290 toku_free(flat);
291 toku_free(serialized_flat);
292
293 v.destroy();
294 }
295
296 int
test_main(int argc,const char * argv[])297 test_main(int argc, const char *argv[]) {
298 parse_args(argc, argv);
299 // Do test with size divisible by 4 and not
300 test_builder_fixed(4, 0);
301 test_builder_fixed(5, 0);
302 test_builder_fixed(4, 1);
303 test_builder_fixed(5, 1);
304 test_builder_fixed(4, 100);
305 test_builder_fixed(5, 100);
306 // Do test with zero, one, or both sizes divisible
307 test_builder_variable(4, 8, 100);
308 test_builder_variable(4, 5, 100);
309 test_builder_variable(5, 8, 100);
310 test_builder_variable(5, 10, 100);
311
312 test_create_from_sorted_memory_of_fixed_sized_elements_and_serialize(4, 0);
313 test_create_from_sorted_memory_of_fixed_sized_elements_and_serialize(5, 0);
314 test_create_from_sorted_memory_of_fixed_sized_elements_and_serialize(4, 1);
315 test_create_from_sorted_memory_of_fixed_sized_elements_and_serialize(5, 1);
316 test_create_from_sorted_memory_of_fixed_sized_elements_and_serialize(4, 100);
317 test_create_from_sorted_memory_of_fixed_sized_elements_and_serialize(5, 100);
318
319 return 0;
320 }
321
322