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 "test.h"
40 
41 // verify that the DB_RMW flag on cursor create grabs write locks for cursor set operations
42 
test_create_rmw(DB_ENV * env,DB * db,int k,uint32_t txn1_flags,uint32_t txn2_flags,int expect_r)43 static void test_create_rmw(DB_ENV *env, DB *db, int k, uint32_t txn1_flags, uint32_t txn2_flags, int expect_r) {
44     int r;
45 
46     DB_TXN *txn1 = NULL;
47     r = env->txn_begin(env, NULL, &txn1, 0); assert_zero(r);
48 
49     DB_TXN *txn2 = NULL;
50     r = env->txn_begin(env, NULL, &txn2, 0); assert_zero(r);
51 
52     DBC *c1 = NULL;
53     r = db->cursor(db, txn1, &c1, txn1_flags); assert_zero(r);
54 
55     DBC *c2 = NULL;
56     r = db->cursor(db, txn2, &c2, txn2_flags); assert_zero(r);
57 
58     DBT key; dbt_init(&key, &k, sizeof k);
59     DBT val; memset(&val, 0, sizeof val);
60     r = c1->c_get(c1, &key, &val, DB_SET); assert_zero(r);
61 
62     r = c2->c_get(c2, &key, &val, DB_SET); assert(r == expect_r);
63 
64     r = c1->c_close(c1); assert_zero(r);
65     r = c2->c_close(c2); assert_zero(r);
66 
67     r = txn1->commit(txn1, 0); assert_zero(r);
68     r = txn2->commit(txn2, 0); assert_zero(r);
69 }
70 
71 // verify that the DB_RMW flag to the cursor set operations grabs write locks
72 
test_set_rmw(DB_ENV * env,DB * db,int k,uint32_t txn1_flags,uint32_t txn2_flags,int expect_r)73 static void test_set_rmw(DB_ENV *env, DB *db, int k, uint32_t txn1_flags, uint32_t txn2_flags, int expect_r) {
74     int r;
75 
76     DB_TXN *txn1 = NULL;
77     r = env->txn_begin(env, NULL, &txn1, 0); assert_zero(r);
78 
79     DB_TXN *txn2 = NULL;
80     r = env->txn_begin(env, NULL, &txn2, 0); assert_zero(r);
81 
82     DBC *c1 = NULL;
83     r = db->cursor(db, txn1, &c1, 0); assert_zero(r);
84 
85     DBC *c2 = NULL;
86     r = db->cursor(db, txn2, &c2, 0); assert_zero(r);
87 
88     DBT key; dbt_init(&key, &k, sizeof k);
89     DBT val; memset(&val, 0, sizeof val);
90     r = c1->c_get(c1, &key, &val, DB_SET + txn1_flags); assert_zero(r);
91 
92     r = c2->c_get(c2, &key, &val, DB_SET + txn2_flags); assert(r == expect_r);
93 
94     r = c1->c_close(c1); assert_zero(r);
95     r = c2->c_close(c2); assert_zero(r);
96 
97     r = txn1->commit(txn1, 0); assert_zero(r);
98     r = txn2->commit(txn2, 0); assert_zero(r);
99 }
100 
test_main(int argc,char * const argv[])101 int test_main(int argc, char * const argv[]) {
102     int r;
103 
104     const char *env_dir = TOKU_TEST_FILENAME;
105     const char *db_filename = "rmwtest";
106 
107     parse_args(argc, argv);
108 
109     char rm_cmd[strlen(env_dir) + strlen("rm -rf ") + 1];
110     snprintf(rm_cmd, sizeof(rm_cmd), "rm -rf %s", env_dir);
111     r = system(rm_cmd); assert_zero(r);
112 
113     r = toku_os_mkdir(env_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); assert_zero(r);
114 
115     DB_ENV *env = NULL;
116     r = db_env_create(&env, 0); assert_zero(r);
117     int env_open_flags = DB_CREATE | DB_PRIVATE | DB_INIT_MPOOL | DB_INIT_TXN | DB_INIT_LOCK | DB_INIT_LOG;
118     r = env->open(env, env_dir, env_open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); assert_zero(r);
119 
120     // create the db
121     DB *db = NULL;
122     r = db_create(&db, env, 0); assert_zero(r);
123     DB_TXN *create_txn = NULL;
124     r = env->txn_begin(env, NULL, &create_txn, 0); assert_zero(r);
125     r = db->open(db, create_txn, db_filename, NULL, DB_BTREE, DB_CREATE, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); assert_zero(r);
126     r = create_txn->commit(create_txn, 0); assert_zero(r);
127 
128     DB_TXN *write_txn = NULL;
129     r = env->txn_begin(env, NULL, &write_txn, 0); assert_zero(r);
130 
131     int k = htonl(42); int v = 42;
132     DBT key; dbt_init(&key, &k, sizeof k);
133     DBT val; dbt_init(&val, &v, sizeof v);
134     r = db->put(db, write_txn, &key, &val, DB_NOOVERWRITE); assert_zero(r);
135     r = write_txn->commit(write_txn, 0); assert_zero(r);
136 
137 #ifdef BLOCKING_ROW_LOCKS_READS_NOT_SHARED
138     test_set_rmw(env, db, k, 0, 0, DB_LOCK_NOTGRANTED);
139 #else
140     test_set_rmw(env, db, k, 0, 0, 0);
141 #endif
142     test_set_rmw(env, db, k, 0, DB_RMW, DB_LOCK_NOTGRANTED);
143     test_set_rmw(env, db, k, DB_RMW, 0, DB_LOCK_NOTGRANTED);
144     test_set_rmw(env, db, k, DB_RMW, DB_RMW, DB_LOCK_NOTGRANTED);
145 
146 #ifdef BLOCKING_ROW_LOCKS_READS_NOT_SHARED
147     test_create_rmw(env, db, k, 0, 0, DB_LOCK_NOTGRANTED);
148 #else
149     test_create_rmw(env, db, k, 0, 0, 0);
150 #endif
151     test_create_rmw(env, db, k, 0, DB_RMW, DB_LOCK_NOTGRANTED);
152     test_create_rmw(env, db, k, DB_RMW, 0, DB_LOCK_NOTGRANTED);
153     test_create_rmw(env, db, k, DB_RMW, DB_RMW, DB_LOCK_NOTGRANTED);
154 
155 
156     r = db->close(db, 0); assert_zero(r);
157 
158     r = env->close(env, 0); assert_zero(r);
159     return 0;
160 }
161