1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4: 3 4 // test the race between start, release, and wait. since start does not put 5 // its lock request into the pending set, the blocking txn could release its 6 // lock before the first txn waits. this will block the first txn because its 7 // lock request is not known when the lock is released. the bug fix is to try 8 // again when lock retries are locked out. 9 10 #include "lock_request.h" 11 #include <atomic> 12 #include <thread> 13 #include "locktree.h" 14 #include "locktree_unit_test.h" 15 #include "test.h" 16 17 namespace toku { 18 19 const uint64_t my_lock_wait_time = 1000 * 1000; // ms 20 const uint64_t my_killed_time = 1 * 1000; // ms 21 22 static uint64_t t_wait; 23 24 static int my_killed_callback(void) { 25 uint64_t t_now = toku_current_time_microsec(); 26 assert(t_now >= t_wait); 27 if (t_now - t_wait >= my_killed_time * 1000) 28 abort(); 29 return 0; 30 } 31 32 static void locktree_release_lock(locktree *lt, 33 TXNID txn_id, 34 const DBT *left, 35 const DBT *right) { 36 range_buffer buffer; 37 buffer.create(); 38 buffer.append(left, right); 39 lt->release_locks(txn_id, &buffer); 40 buffer.destroy(); 41 } 42 43 static void test_start_release_wait(void) { 44 int r; 45 46 locktree_manager mgr; 47 mgr.create(nullptr, nullptr, nullptr, nullptr); 48 49 DICTIONARY_ID dict_id = {1}; 50 locktree *lt = mgr.get_lt(dict_id, dbt_comparator, nullptr); 51 52 const DBT *one = get_dbt(1); 53 54 // a locks one 55 lock_request a; 56 a.create(); 57 a.set(lt, 1, one, one, lock_request::type::WRITE, false); 58 r = a.start(); 59 assert(r == 0); 60 61 // b tries to lock one, fails 62 lock_request b; 63 b.create(); 64 b.set(lt, 2, one, one, lock_request::type::WRITE, false); 65 r = b.start(); 66 assert(r == DB_LOCK_NOTGRANTED); 67 CFStack__anon6359c33a0111::CFStack68 // a releases its lock 69 locktree_release_lock(lt, 1, one, one); 70 71 // b waits for one, gets locks immediately 72 t_wait = toku_current_time_microsec(); 73 r = b.wait(my_lock_wait_time, my_killed_time, my_killed_callback); 74 assert(r == 0); 75 76 // b releases its lock so we can exit cleanly 77 locktree_release_lock(lt, 2, one, one); 78 79 a.destroy(); 80 b.destroy(); 81 82 mgr.release_lt(lt); getLoopDepth()83 mgr.destroy(); 84 } 85 86 } /* namespace toku */ branchStackContains(CFStack::StackItem Item)87 88 int main(void) { 89 toku::test_start_release_wait(); 90 return 0; 91 } 92