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 "locktree_unit_test.h"
40 
41 namespace toku {
42 
43 // test simple, non-overlapping read locks and then write locks
test_simple_lock(void)44 void locktree_unit_test::test_simple_lock(void) {
45     locktree_manager mgr;
46     mgr.create(nullptr, nullptr, nullptr, nullptr);
47 
48     DICTIONARY_ID dict_id = { .dictid = 1 };
49     locktree *lt = mgr.get_lt(dict_id, dbt_comparator, nullptr);
50 
51     int r;
52     TXNID txnid_a = 1001;
53     TXNID txnid_b = 2001;
54     TXNID txnid_c = 3001;
55     TXNID txnid_d = 4001;
56     const DBT *one = get_dbt(1);
57     const DBT *two = get_dbt(2);
58     const DBT *three = get_dbt(3);
59     const DBT *four = get_dbt(4);
60 
61     for (int test_run = 0; test_run < 2; test_run++) {
62         // test_run == 0 means test with read lock
63         // test_run == 1 means test with write lock
64 #define ACQUIRE_LOCK(txn, left, right, conflicts) \
65         test_run == 0 ? lt->acquire_read_lock(txn, left, right, conflicts, false) \
66             : lt->acquire_write_lock(txn, left, right, conflicts, false)
67 
68         // four txns, four points
69         r = ACQUIRE_LOCK(txnid_a, one, one, nullptr);
70         invariant(r == 0);
71         r = ACQUIRE_LOCK(txnid_b, two, two, nullptr);
72         invariant(r == 0);
73         r = ACQUIRE_LOCK(txnid_c, three, three, nullptr);
74         invariant(r == 0);
75         r = ACQUIRE_LOCK(txnid_d, four, four, nullptr);
76         invariant(r == 0);
77         locktree_test_release_lock(lt, txnid_a, one, one);
78         locktree_test_release_lock(lt, txnid_b, two, two);
79         locktree_test_release_lock(lt, txnid_c, three, three);
80         locktree_test_release_lock(lt, txnid_d, four, four);
81         invariant(no_row_locks(lt));
82 
83         // two txns, two ranges
84         r = ACQUIRE_LOCK(txnid_c, one, two, nullptr);
85         invariant(r == 0);
86         r = ACQUIRE_LOCK(txnid_b, three, four, nullptr);
87         invariant(r == 0);
88         locktree_test_release_lock(lt, txnid_c, one, two);
89         locktree_test_release_lock(lt, txnid_b, three, four);
90         invariant(no_row_locks(lt));
91 
92         // two txns, one range, one point
93         r = ACQUIRE_LOCK(txnid_c, three, four, nullptr);
94         invariant(r == 0);
95         r = ACQUIRE_LOCK(txnid_d, one, one, nullptr);
96         invariant(r == 0);
97         locktree_test_release_lock(lt, txnid_c, three, four);
98         locktree_test_release_lock(lt, txnid_d, one, one);
99         invariant(no_row_locks(lt));
100 
101 #undef ACQUIRE_LOCK
102     }
103 
104     const int64_t num_locks = 10000;
105 
106     int64_t *keys = (int64_t *) toku_malloc(num_locks * sizeof(int64_t));
107     for (int64_t i = 0; i < num_locks; i++) {
108         keys[i] = i;
109     }
110     for (int64_t i = 0; i < num_locks; i++) {
111         int64_t k = rand() % num_locks;
112         int64_t tmp = keys[k];
113         keys[k] = keys[i];
114         keys[i] = tmp;
115     }
116 
117 
118     r = mgr.set_max_lock_memory((num_locks + 1) * 500);
119     invariant_zero(r);
120 
121     DBT k;
122     k.ulen = 0;
123     k.size = sizeof(keys[0]);
124     k.flags = DB_DBT_USERMEM;
125 
126     for (int64_t i = 0; i < num_locks; i++) {
127         k.data = (void *) &keys[i];
128         r = lt->acquire_read_lock(txnid_a, &k, &k, nullptr, false);
129         invariant(r == 0);
130     }
131 
132     for (int64_t i = 0; i < num_locks; i++) {
133         k.data = (void *) &keys[i];
134         locktree_test_release_lock(lt, txnid_a, &k, &k);
135     }
136 
137     toku_free(keys);
138 
139     mgr.release_lt(lt);
140     mgr.destroy();
141 }
142 
143 } /* namespace toku */
144 
main(void)145 int main(void) {
146     toku::locktree_unit_test test;
147     test.test_simple_lock();
148     return 0;
149 }
150