LCOV - code coverage report
Current view: top level - funk - test_funk_common.hpp (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 333 381 87.4 %
Date: 2024-11-13 11:58:15 Functions: 25 29 86.2 %

          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             : };

Generated by: LCOV version 1.14