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