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 \
38 "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
39
40 #include "test.h"
41 // to verify the DB_LOCKING_READ works to lock the read rows for snapshot
42 // isolaton.
43 // we create a db, then init a read transaction with repeatable-read isolation
44 // and
45 // locking read flag, then we start another transaction to grab the write lock.
46 // DB_LOCKING_READ is defined here to just make the before and after tests work
47 // (before
48 // test did not have DB_LOCKING_READ flag).
49 #if !defined(DB_LOCKING_READ)
50 #define DB_LOCKING_READ 0
51 #endif
prelock_range(DBC * cursor,int left,int right)52 static int prelock_range(DBC *cursor, int left, int right) {
53 DBT key_left;
54 dbt_init(&key_left, &left, sizeof left);
55 DBT key_right;
56 dbt_init(&key_right, &right, sizeof right);
57 int r = cursor->c_set_bounds(cursor, &key_left, &key_right, true, 0);
58 return r;
59 }
60
test_read_write_range(DB_ENV * env,DB * db,uint32_t iso_flags,int expect_r)61 static void test_read_write_range(DB_ENV *env,
62 DB *db,
63 uint32_t iso_flags,
64 int expect_r) {
65 int r;
66
67 DB_TXN *txn_a = NULL;
68 r = env->txn_begin(env, NULL, &txn_a, iso_flags);
69 assert_zero(r);
70 DB_TXN *txn_b = NULL;
71 r = env->txn_begin(env, NULL, &txn_b, iso_flags);
72 assert_zero(r);
73
74 DBC *cursor_a = NULL;
75 r = db->cursor(db, txn_a, &cursor_a, DB_LOCKING_READ);
76 assert_zero(r);
77 DBC *cursor_b = NULL;
78 r = db->cursor(db, txn_b, &cursor_b, DB_RMW);
79 assert_zero(r);
80
81 r = prelock_range(cursor_a, htonl(10), htonl(100));
82 assert_zero(r);
83 r = prelock_range(cursor_b, htonl(50), htonl(200));
84 assert(r == expect_r);
85
86 r = cursor_a->c_close(cursor_a);
87 assert_zero(r);
88 r = cursor_b->c_close(cursor_b);
89 assert_zero(r);
90
91 r = txn_a->commit(txn_a, 0);
92 assert_zero(r);
93 r = txn_b->commit(txn_b, 0);
94 assert_zero(r);
95 }
96
test_read_write_point(DB_ENV * env,DB * db,uint32_t iso_flags,int expect_r)97 static void test_read_write_point(DB_ENV *env,
98 DB *db,
99 uint32_t iso_flags,
100 int expect_r) {
101 int r;
102
103 DB_TXN *txn1 = NULL;
104 r = env->txn_begin(env, NULL, &txn1, iso_flags);
105 assert_zero(r);
106
107 DB_TXN *txn2 = NULL;
108 r = env->txn_begin(env, NULL, &txn2, iso_flags);
109 assert_zero(r);
110
111 DBC *c1 = NULL;
112 r = db->cursor(db, txn1, &c1, DB_LOCKING_READ);
113 assert_zero(r);
114
115 DBC *c2 = NULL;
116 r = db->cursor(db, txn2, &c2, DB_RMW);
117 assert_zero(r);
118
119 int k = htonl(42);
120 DBT key;
121 dbt_init(&key, &k, sizeof k);
122 DBT val;
123 memset(&val, 0, sizeof val);
124 r = c1->c_get(c1, &key, &val, DB_SET);
125 assert_zero(r);
126
127 r = c2->c_get(c2, &key, &val, DB_SET);
128 assert(r == expect_r);
129
130 r = c1->c_close(c1);
131 assert_zero(r);
132 r = c2->c_close(c2);
133 assert_zero(r);
134
135 r = txn1->commit(txn1, 0);
136 assert_zero(r);
137 r = txn2->commit(txn2, 0);
138 assert_zero(r);
139 }
140
test_main(int argc,char * const argv[])141 int test_main(int argc, char *const argv[]) {
142 int r;
143
144 const char *env_dir = TOKU_TEST_FILENAME;
145 const char *db_filename = "lockingreadtest";
146
147 parse_args(argc, argv);
148
149 char rm_cmd[strlen(env_dir) + strlen("rm -rf ") + 1];
150 snprintf(rm_cmd, sizeof(rm_cmd), "rm -rf %s", env_dir);
151 r = system(rm_cmd);
152 assert_zero(r);
153
154 r = toku_os_mkdir(env_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
155 assert_zero(r);
156
157 DB_ENV *env = NULL;
158 r = db_env_create(&env, 0);
159 assert_zero(r);
160 int env_open_flags = DB_CREATE | DB_PRIVATE | DB_INIT_MPOOL | DB_INIT_TXN |
161 DB_INIT_LOCK | DB_INIT_LOG;
162 r = env->open(
163 env, env_dir, env_open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
164 assert_zero(r);
165
166 // create the db
167 DB *db = NULL;
168 r = db_create(&db, env, 0);
169 assert_zero(r);
170 DB_TXN *create_txn = NULL;
171 r = env->txn_begin(env, NULL, &create_txn, 0);
172 assert_zero(r);
173 r = db->open(db,
174 create_txn,
175 db_filename,
176 NULL,
177 DB_BTREE,
178 DB_CREATE,
179 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
180 assert_zero(r);
181 r = create_txn->commit(create_txn, 0);
182 assert_zero(r);
183
184 // add a record
185
186 DB_TXN *write_txn = NULL;
187 r = env->txn_begin(env, NULL, &write_txn, 0);
188 assert_zero(r);
189
190 int k = htonl(42);
191 int v = 42;
192 DBT key;
193 dbt_init(&key, &k, sizeof k);
194 DBT val;
195 dbt_init(&val, &v, sizeof v);
196 r = db->put(db, write_txn, &key, &val, DB_NOOVERWRITE);
197 assert_zero(r);
198 r = write_txn->commit(write_txn, 0);
199 assert_zero(r);
200
201 test_read_write_range(env, db, DB_TXN_SNAPSHOT, DB_LOCK_NOTGRANTED);
202 test_read_write_point(env, db, DB_TXN_SNAPSHOT, DB_LOCK_NOTGRANTED);
203
204 r = db->close(db, 0);
205 assert_zero(r);
206
207 r = env->close(env, 0);
208 assert_zero(r);
209 return 0;
210 }
211