Line data Source code
1 : extern "C" {
2 : #include "fd_funk.h"
3 : }
4 : #include <map>
5 : #include <vector>
6 : #include <stdlib.h>
7 : #include <assert.h>
8 : #include <unistd.h>
9 :
10 : static const long ROOT_KEY = 0;
11 : static const ulong MAX_TXNS = 100;
12 : static const ulong MAX_CHILDREN = 100;
13 : static const uint MAX_PARTS = 8;
14 :
15 : struct fake_rec {
16 : ulong _key;
17 : std::vector<long> _data;
18 : bool _erased = false;
19 : bool _touched = false;
20 : uint _part = FD_FUNK_PART_NULL;
21 :
22 : fake_rec() = delete;
23 78000 : fake_rec(ulong key) : _key(key) { }
24 :
25 78000 : static fake_rec * make_random() {
26 78000 : auto * rec = new fake_rec(((ulong)lrand48())%MAX_CHILDREN);
27 78000 : auto len = ((ulong)lrand48())%8UL;
28 78000 : rec->_data.resize(len);
29 350754 : for (ulong i = 0; i < len; ++i)
30 272754 : rec->_data[i] = lrand48();
31 78000 : return rec;
32 78000 : }
33 :
34 107340 : fd_funk_rec_key_t real_id() const {
35 107340 : fd_funk_rec_key_t i;
36 107340 : memset(&i, 0, sizeof(i));
37 107340 : i.ul[0] = _key;
38 107340 : return i;
39 107340 : }
40 :
41 1799538 : ulong size() const {
42 1799538 : return _data.size()*sizeof(long);
43 1799538 : }
44 :
45 850038 : const uchar* data() const {
46 850038 : return (const uchar*)_data.data();
47 850038 : }
48 : };
49 :
50 : struct fake_txn {
51 : ulong _key;
52 : std::map<ulong,fake_rec*> _recs;
53 : std::map<ulong,fake_txn*> _children;
54 : fake_txn * _parent = NULL;
55 : bool _touched = false;
56 :
57 12006 : fake_txn(ulong key) : _key(key) { }
58 12006 : ~fake_txn() {
59 12006 : for (auto i : _recs)
60 56913 : delete i.second;
61 12006 : }
62 :
63 101301 : fd_funk_txn_xid_t real_id() const {
64 101301 : fd_funk_txn_xid_t i;
65 101301 : memset(&i, 0, sizeof(i));
66 101301 : i.ul[0] = _key;
67 101301 : return i;
68 101301 : }
69 :
70 84987 : void insert(fake_rec* rec) {
71 84987 : auto i = _recs.find(rec->_key);
72 84987 : if (i != _recs.end())
73 21087 : delete i->second;
74 84987 : _recs[rec->_key] = rec;
75 84987 : }
76 : };
77 :
78 : struct fake_funk {
79 : fd_wksp_t * _wksp;
80 : fd_funk_t * _real;
81 : std::map<ulong,fake_txn*> _txns;
82 : ulong _lastxid = 0;
83 : #ifdef TEST_FUNK_FILE
84 : fd_funk_close_file_args_t close_args;
85 : #endif
86 :
87 12 : fake_funk(int * argc, char *** argv) {
88 12 : fd_boot( argc, argv );
89 12 : ulong txn_max = 128;
90 12 : ulong rec_max = 1<<16;
91 :
92 : #ifdef TEST_FUNK_FILE
93 6 : _real = fd_funk_open_file( "funk_test_file", 1, 1234U, txn_max, rec_max, FD_SHMEM_GIGANTIC_PAGE_SZ, FD_FUNK_OVERWRITE, &close_args );
94 : _wksp = fd_funk_wksp( _real );
95 :
96 : #else
97 : ulong numa_idx = fd_shmem_numa_idx( 0 );
98 6 : _wksp = fd_wksp_new_anonymous( FD_SHMEM_GIGANTIC_PAGE_SZ, 1U, fd_shmem_cpu_idx( numa_idx ), "wksp", 0UL );
99 6 : void * mem = fd_wksp_alloc_laddr( _wksp, fd_funk_align(), fd_funk_footprint(), FD_FUNK_MAGIC );
100 : _real = fd_funk_join( fd_funk_new( mem, 1, 1234U, txn_max, rec_max ) );
101 : #endif
102 :
103 12 : fd_funk_set_num_partitions( _real, MAX_PARTS );
104 :
105 12 : _txns[ROOT_KEY] = new fake_txn(ROOT_KEY);
106 12 : }
107 6 : ~fake_funk() {
108 6 : for (auto i : _txns)
109 87 : delete i.second;
110 : #ifdef TEST_FUNK_FILE
111 : fd_funk_close_file( &close_args );
112 : unlink( "funk_test_file" );
113 : #endif
114 6 : }
115 :
116 : #ifdef TEST_FUNK_FILE
117 0 : void reopen_file() {
118 0 : fd_funk_close_file( &close_args );
119 0 : _real = fd_funk_open_file( "funk_test_file", 1, 0, 0, 0, 0, FD_FUNK_READ_WRITE, &close_args );
120 0 : _wksp = fd_funk_wksp( _real );
121 0 : }
122 : #endif
123 :
124 108000 : fake_txn * pick_unfrozen_txn() {
125 108000 : fake_txn* list[MAX_TXNS];
126 108000 : uint listlen = 0;
127 108000 : for (auto i : _txns)
128 1886760 : if (i.second->_children.size() == 0)
129 950850 : list[listlen++] = i.second;
130 108000 : return list[((uint)lrand48())%listlen];
131 108000 : }
132 :
133 120540 : fd_funk_txn_t * get_real_txn(fake_txn * txn) {
134 120540 : if (txn->_key == ROOT_KEY)
135 31239 : return NULL;
136 89301 : fd_funk_txn_t * txn_map = fd_funk_txn_map( _real, _wksp );
137 89301 : auto xid = txn->real_id();
138 89301 : return fd_funk_txn_query(&xid, txn_map);
139 120540 : }
140 :
141 78000 : void random_insert() {
142 78000 : fake_txn * txn = pick_unfrozen_txn();
143 78000 : fake_rec * rec = fake_rec::make_random();
144 78000 : txn->insert(rec);
145 :
146 78000 : fd_funk_start_write(_real);
147 78000 : fd_funk_txn_t * txn2 = get_real_txn(txn);
148 78000 : auto key = rec->real_id();
149 78000 : fd_funk_rec_t * rec2 = fd_funk_rec_write_prepare(_real, txn2, &key, rec->size(), 1, NULL, NULL);
150 78000 : if (fd_funk_val_sz(rec2) > rec->size())
151 21462 : rec2 = fd_funk_val_truncate(rec2, rec->size(), fd_funk_alloc(_real, _wksp), _wksp, NULL);
152 78000 : memcpy(fd_funk_val(rec2, _wksp), rec->data(), rec->size());
153 78000 : rec->_part = rec2->part;
154 78000 : fd_funk_end_write(_real);
155 78000 : }
156 :
157 24000 : void random_remove() {
158 24000 : fake_txn * txn = pick_unfrozen_txn();
159 24000 : auto& recs = txn->_recs;
160 24000 : fake_rec* list[MAX_CHILDREN];
161 24000 : uint listlen = 0;
162 24000 : for (auto i : recs)
163 988335 : if (!i.second->_erased)
164 442677 : list[listlen++] = i.second;
165 24000 : if (!listlen) return;
166 23340 : auto* rec = list[((uint)lrand48())%listlen];
167 :
168 23340 : fd_funk_start_write(_real);
169 23340 : fd_funk_txn_t * txn2 = get_real_txn(txn);
170 23340 : auto key = rec->real_id();
171 23340 : auto* rec2 = fd_funk_rec_query(_real, txn2, &key);
172 23340 : assert(rec2 != NULL);
173 23340 : assert(fd_funk_rec_remove(_real, (fd_funk_rec_t *)rec2, 1) == FD_FUNK_SUCCESS);
174 :
175 23340 : rec->_erased = true;
176 23340 : rec->_data.clear();
177 23340 : fd_funk_end_write(_real);
178 23340 : }
179 :
180 6000 : void random_repart() {
181 6000 : fake_txn * txn = pick_unfrozen_txn();
182 6000 : auto& recs = txn->_recs;
183 6000 : fake_rec* list[MAX_CHILDREN];
184 6000 : uint listlen = 0;
185 6000 : for (auto i : recs)
186 589080 : if (!i.second->_erased)
187 141900 : list[listlen++] = i.second;
188 6000 : if (!listlen) return;
189 6000 : auto* rec = list[((uint)lrand48())%listlen];
190 :
191 6000 : fd_funk_start_write(_real);
192 6000 : fd_funk_txn_t * txn2 = get_real_txn(txn);
193 6000 : auto key = rec->real_id();
194 6000 : auto* rec2 = fd_funk_rec_query(_real, txn2, &key);
195 6000 : assert(rec2 != NULL);
196 6000 : uint part = ((uint)lrand48())%MAX_PARTS;
197 6000 : assert(!fd_funk_part_set(_real, (fd_funk_rec*)rec2, part));
198 6000 : rec->_part = part;
199 6000 : fd_funk_end_write(_real);
200 6000 : }
201 :
202 12000 : void random_new_txn() {
203 12000 : if (_txns.size() == MAX_TXNS)
204 0 : return;
205 :
206 12000 : fd_funk_start_write(_real);
207 12000 : fake_txn* list[MAX_TXNS];
208 12000 : uint listlen = 0;
209 12000 : for (auto i : _txns)
210 213690 : list[listlen++] = i.second;
211 12000 : auto * parent = list[((uint)lrand48())%listlen];
212 :
213 12000 : ulong key = ++_lastxid;
214 12000 : auto * txn = _txns[key] = new fake_txn(key);
215 :
216 12000 : txn->_parent = parent;
217 12000 : parent->_children[key] = txn;
218 :
219 12000 : fd_funk_txn_t * parent2 = get_real_txn(parent);
220 12000 : auto xid = txn->real_id();
221 12000 : assert(fd_funk_txn_prepare(_real, parent2, &xid, 1) != NULL);
222 12000 : fd_funk_end_write(_real);
223 12000 : }
224 :
225 10275 : void fake_cancel_family(fake_txn* txn) {
226 10275 : assert(txn->_key != ROOT_KEY);
227 17754 : while (!txn->_children.empty())
228 7479 : fake_cancel_family(txn->_children.begin()->second);
229 10275 : fd_funk_start_write(_real);
230 10275 : txn->_parent->_children.erase(txn->_key);
231 10275 : _txns.erase(txn->_key);
232 10275 : delete txn;
233 10275 : fd_funk_end_write(_real);
234 10275 : }
235 :
236 1251 : void fake_publish_to_parent(fake_txn* txn) {
237 1251 : fd_funk_start_write(_real);
238 : // Move records into parent
239 1251 : auto* parent = txn->_parent;
240 1251 : for (auto i : txn->_recs)
241 4848 : parent->insert(i.second);
242 1251 : txn->_recs.clear();
243 :
244 : // Cancel siblings
245 3747 : for (;;) {
246 3747 : bool repeat = false;
247 3747 : for (auto i : parent->_children)
248 5403 : if (txn != i.second) {
249 2496 : fd_funk_end_write(_real);
250 2496 : fake_cancel_family(i.second);
251 2496 : fd_funk_start_write(_real);
252 2496 : repeat = true;
253 2496 : break;
254 2496 : }
255 3747 : if (!repeat) break;
256 3747 : }
257 1251 : assert(parent->_children.size() == 1 && parent->_children[txn->_key] == txn);
258 :
259 : // Move children up
260 1251 : parent->_children.clear();
261 2241 : for (auto i : txn->_children) {
262 2241 : auto* child = i.second;
263 2241 : child->_parent = parent;
264 2241 : parent->_children[child->_key] = child;
265 2241 : }
266 :
267 1251 : _txns.erase(txn->_key);
268 1251 : delete txn;
269 1251 : fd_funk_end_write(_real);
270 1251 : }
271 :
272 951 : void fake_publish(fake_txn* txn) {
273 951 : assert(txn->_key != ROOT_KEY);
274 951 : if (txn->_parent->_key != ROOT_KEY)
275 651 : fake_publish(txn->_parent);
276 951 : assert(txn->_parent->_key == ROOT_KEY);
277 951 : fake_publish_to_parent(txn);
278 951 : }
279 :
280 300 : void fake_merge(fake_txn* txn) {
281 300 : fd_funk_start_write(_real);
282 393 : for (auto i : txn->_children) {
283 393 : auto* child = i.second;
284 393 : for (auto i : child->_recs)
285 2139 : txn->insert(i.second);
286 393 : child->_recs.clear();
287 393 : _txns.erase(child->_key);
288 393 : delete child;
289 393 : }
290 300 : txn->_children.clear();
291 300 : fd_funk_end_write(_real);
292 300 : }
293 :
294 0 : void random_publish() {
295 0 : fd_funk_start_write(_real);
296 0 : fake_txn* list[MAX_TXNS];
297 0 : uint listlen = 0;
298 0 : for (auto i : _txns)
299 0 : if (i.second->_key != ROOT_KEY)
300 0 : list[listlen++] = i.second;
301 0 : if (!listlen) return;
302 0 : auto * txn = list[((uint)lrand48())%listlen];
303 0 :
304 0 : fd_funk_txn_t * txn2 = get_real_txn(txn);
305 0 : assert(fd_funk_txn_publish(_real, txn2, 1) > 0);
306 0 : fd_funk_end_write(_real);
307 0 :
308 0 : // Simulate publication
309 0 : fake_publish(txn);
310 0 : }
311 :
312 300 : void random_publish_into_parent() {
313 300 : fd_funk_start_write(_real);
314 300 : fake_txn* list[MAX_TXNS];
315 300 : uint listlen = 0;
316 300 : for (auto i : _txns)
317 3975 : if (i.second->_key != ROOT_KEY)
318 3675 : list[listlen++] = i.second;
319 300 : if (!listlen) return;
320 300 : auto * txn = list[((uint)lrand48())%listlen];
321 :
322 300 : fd_funk_txn_t * txn2 = get_real_txn(txn);
323 300 : assert(fd_funk_txn_publish_into_parent(_real, txn2, 1) == FD_FUNK_SUCCESS);
324 300 : fd_funk_end_write(_real);
325 :
326 : // Simulate publication
327 300 : fake_publish_to_parent(txn);
328 300 : }
329 :
330 0 : void random_cancel() {
331 0 : fd_funk_start_write(_real);
332 0 : fake_txn* list[MAX_TXNS];
333 0 : uint listlen = 0;
334 0 : for (auto i : _txns)
335 0 : if (i.second->_key != ROOT_KEY)
336 0 : list[listlen++] = i.second;
337 0 : if (!listlen) return;
338 0 : auto * txn = list[((uint)lrand48())%listlen];
339 0 :
340 0 : fd_funk_txn_t * txn2 = get_real_txn(txn);
341 0 : assert(fd_funk_txn_cancel(_real, txn2, 1) > 0);
342 0 : fd_funk_end_write(_real);
343 0 :
344 0 : // Simulate cancel
345 0 : fake_cancel_family(txn);
346 0 : }
347 :
348 300 : void random_merge() {
349 300 : fd_funk_start_write(_real);
350 : // Look for transactions with children but no grandchildren
351 300 : fake_txn* list[MAX_TXNS];
352 300 : uint listlen = 0;
353 7905 : for (auto i : _txns) {
354 7905 : auto* txn = i.second;
355 7905 : if (txn->_children.empty()) continue;
356 4005 : for (auto j : txn->_children)
357 4809 : if (!j.second->_children.empty())
358 2262 : goto no_good;
359 1743 : list[listlen++] = i.second;
360 4005 : no_good: continue;
361 1743 : }
362 300 : if (!listlen) return;
363 300 : auto * txn = list[((uint)lrand48())%listlen];
364 :
365 300 : fd_funk_txn_t * txn2 = get_real_txn(txn);
366 300 : assert(fd_funk_txn_merge_all_children(_real, txn2, 1) == FD_FUNK_SUCCESS);
367 300 : fd_funk_end_write(_real);
368 :
369 : // Simulate merge
370 300 : fake_merge(txn);
371 300 : }
372 :
373 0 : void random_safe_read() {
374 0 : fd_funk_rec_key_t i;
375 0 : memset(&i, 0, sizeof(i));
376 0 : i.ul[0] = ((ulong)lrand48())%MAX_CHILDREN;
377 0 : ulong datalen;
378 0 : auto* data = fd_funk_rec_query_safe(_real, &i, fd_libc_alloc_virtual(), &datalen);
379 0 : if( data ) free(data);
380 0 : }
381 :
382 300 : void archive() {
383 300 : assert(!fd_funk_archive(_real, "/tmp/tmparchive"));
384 :
385 300 : fd_wksp_detach( _wksp );
386 :
387 300 : ulong numa_idx = fd_shmem_numa_idx( 0 );
388 300 : _wksp = fd_wksp_new_anonymous( FD_SHMEM_GIGANTIC_PAGE_SZ, 1U, fd_shmem_cpu_idx( numa_idx ), "wksp", 0UL );
389 300 : void * mem = fd_wksp_alloc_laddr( _wksp, fd_funk_align(), fd_funk_footprint(), FD_FUNK_MAGIC );
390 300 : ulong txn_max = 128;
391 300 : ulong rec_max = 1<<16;
392 300 : _real = fd_funk_join( fd_funk_new( mem, 1, 1234U, txn_max, rec_max ) );
393 :
394 300 : assert(!fd_funk_unarchive(_real, "/tmp/tmparchive"));
395 300 : unlink("/tmp/tmparchive");
396 300 : }
397 :
398 6300 : void verify() {
399 6300 : assert(fd_funk_verify(_real) == FD_FUNK_SUCCESS);
400 :
401 108588 : for (auto i : _txns) {
402 108588 : assert(i.first == i.second->_key);
403 1050579 : for (auto j : i.second->_recs) {
404 1050579 : assert(j.first == j.second->_key);
405 1050579 : j.second->_touched = false;
406 1050579 : }
407 108588 : }
408 :
409 6300 : fd_funk_rec_t * rec_map = fd_funk_rec_map( _real, _wksp );
410 6300 : for( fd_funk_rec_map_iter_t iter = fd_funk_rec_map_iter_init( rec_map );
411 838194 : !fd_funk_rec_map_iter_done( rec_map, iter );
412 831894 : iter = fd_funk_rec_map_iter_next( rec_map, iter ) ) {
413 831894 : fd_funk_rec_t * rec = fd_funk_rec_map_iter_ele( rec_map, iter );
414 831894 : auto const * xid = fd_funk_rec_xid( rec );
415 831894 : auto i = _txns.find(xid->ul[0]);
416 831894 : assert(i != _txns.end());
417 831894 : auto const * key = fd_funk_rec_key( rec );
418 831894 : auto& recs = i->second->_recs;
419 831894 : auto j = recs.find(key->ul[0]);
420 831894 : assert(j != recs.end());
421 831894 : auto * rec2 = j->second;
422 831894 : if (rec2->_erased) {
423 59856 : assert(rec->flags & FD_FUNK_REC_FLAG_ERASE);
424 59856 : assert(fd_funk_val_sz(rec) == 0);
425 772038 : } else {
426 772038 : assert(!(rec->flags & FD_FUNK_REC_FLAG_ERASE));
427 772038 : assert(fd_funk_val_sz(rec) == rec2->size());
428 772038 : assert(memcmp(fd_funk_val(rec, _wksp), rec2->data(), rec2->size()) == 0);
429 772038 : assert(rec->part == rec2->_part);
430 772038 : }
431 831894 : assert(!rec2->_touched);
432 831894 : rec2->_touched = true;
433 831894 : }
434 :
435 108588 : for (auto i : _txns) {
436 1050579 : for (auto j : i.second->_recs) {
437 1050579 : assert(j.second->_touched || j.second->_erased);
438 1050579 : }
439 108588 : }
440 :
441 108588 : for (auto i : _txns) {
442 108588 : auto * txn = i.second;
443 108588 : assert(i.first == txn->_key);
444 108588 : if (txn->_key == ROOT_KEY) {
445 6300 : assert(txn->_parent == NULL);
446 102288 : } else {
447 102288 : assert(txn->_parent->_children.find(txn->_key)->second == txn);
448 102288 : }
449 108588 : txn->_touched = false;
450 108588 : }
451 :
452 6300 : {
453 : // Root transaction
454 6300 : auto * txn2 = _txns[ROOT_KEY];
455 6300 : assert(!txn2->_touched);
456 6300 : txn2->_touched = true;
457 :
458 6300 : auto& recs = txn2->_recs;
459 6300 : for( auto const * rec = fd_funk_txn_first_rec(_real, NULL);
460 401160 : rec;
461 394860 : rec = fd_funk_txn_next_rec(_real, rec) ) {
462 394860 : auto const * key = fd_funk_rec_key( rec );
463 394860 : auto j = recs.find(key->ul[0]);
464 394860 : assert(j != recs.end());
465 394860 : }
466 6300 : }
467 :
468 6300 : fd_funk_txn_t * txn_map = fd_funk_txn_map( _real, _wksp );
469 6300 : for( fd_funk_txn_map_iter_t iter = fd_funk_txn_map_iter_init( txn_map );
470 108588 : !fd_funk_txn_map_iter_done( txn_map, iter );
471 102288 : iter = fd_funk_txn_map_iter_next( txn_map, iter ) ) {
472 102288 : fd_funk_txn_t * txn = fd_funk_txn_map_iter_ele( txn_map, iter );
473 102288 : auto i = _txns.find(txn->xid.ul[0]);
474 102288 : assert(i != _txns.end());
475 102288 : auto * txn2 = i->second;
476 102288 : assert(!txn2->_touched);
477 102288 : txn2->_touched = true;
478 :
479 102288 : auto * parent = fd_funk_txn_parent(txn, txn_map);
480 102288 : if (parent == NULL)
481 17742 : assert(ROOT_KEY == txn2->_parent->_key);
482 84546 : else
483 84546 : assert(parent->xid.ul[0] == txn2->_parent->_key);
484 :
485 102288 : auto& recs = txn2->_recs;
486 102288 : for( auto const * rec = fd_funk_txn_first_rec(_real, txn);
487 539322 : rec;
488 437034 : rec = fd_funk_txn_next_rec(_real, rec) ) {
489 437034 : auto const * key = fd_funk_rec_key( rec );
490 437034 : auto j = recs.find(key->ul[0]);
491 437034 : assert(j != recs.end());
492 437034 : }
493 102288 : }
494 :
495 108588 : for (auto i : _txns) {
496 108588 : assert(i.second->_touched);
497 108588 : }
498 6300 : }
499 : };
|