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 // verify that table locks used by multiple transactions suspend the conflicting thread rather than just return DB_LOCK_NOTGRANTED.
40
41 #include "test.h"
42 #include "toku_pthread.h"
43
blocking_table_lock(DB_ENV * db_env,DB * db,uint64_t nrows,long sleeptime)44 static void blocking_table_lock(DB_ENV *db_env, DB *db, uint64_t nrows, long sleeptime) {
45 int r;
46
47 for (uint64_t i = 0; i < nrows; i++) {
48 DB_TXN *txn = NULL;
49 r = db_env->txn_begin(db_env, NULL, &txn, 0); assert(r == 0);
50
51 r = db->pre_acquire_table_lock(db, txn); assert(r == 0);
52
53 usleep(sleeptime);
54
55 r = txn->commit(txn, 0); assert(r == 0);
56 if (verbose)
57 printf("%lu %" PRIu64 "\n", (unsigned long) toku_pthread_self(), i);
58 }
59 }
60
61 struct blocking_table_lock_args {
62 DB_ENV *db_env;
63 DB *db;
64 uint64_t nrows;
65 long sleeptime;
66 };
67
blocking_table_lock_thread(void * arg)68 static void *blocking_table_lock_thread(void *arg) {
69 struct blocking_table_lock_args *a = (struct blocking_table_lock_args *) arg;
70 blocking_table_lock(a->db_env, a->db, a->nrows, a->sleeptime);
71 return arg;
72 }
73
test_main(int argc,char * const argv[])74 int test_main(int argc, char * const argv[]) {
75 uint64_t cachesize = 0;
76 uint32_t pagesize = 0;
77 uint64_t nrows = 100;
78 int nthreads = 2;
79 long sleeptime = 100000;
80 const char *db_env_dir = TOKU_TEST_FILENAME;
81 const char *db_filename = "test.db";
82 int db_env_open_flags = DB_CREATE | DB_PRIVATE | DB_INIT_MPOOL | DB_INIT_TXN | DB_INIT_LOCK | DB_INIT_LOG | DB_THREAD;
83
84 // parse_args(argc, argv);
85 for (int i = 1; i < argc; i++) {
86 if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) {
87 verbose++;
88 continue;
89 }
90 if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0) {
91 if (verbose > 0)
92 verbose--;
93 continue;
94 }
95 if (strcmp(argv[i], "--nrows") == 0 && i+1 < argc) {
96 nrows = atoll(argv[++i]);
97 continue;
98 }
99 if (strcmp(argv[i], "--nthreads") == 0 && i+1 < argc) {
100 nthreads = atoi(argv[++i]);
101 continue;
102 }
103 if (strcmp(argv[i], "--sleeptime") == 0 && i+1 < argc) {
104 sleeptime = atol(argv[++i]);
105 continue;
106 }
107 assert(0);
108 }
109
110 // setup env
111 int r;
112 char rm_cmd[strlen(db_env_dir) + strlen("rm -rf ") + 1];
113 snprintf(rm_cmd, sizeof(rm_cmd), "rm -rf %s", db_env_dir);
114 r = system(rm_cmd); assert(r == 0);
115
116 r = toku_os_mkdir(db_env_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); assert(r == 0);
117
118 DB_ENV *db_env = NULL;
119 r = db_env_create(&db_env, 0); assert(r == 0);
120 if (cachesize) {
121 const uint64_t gig = 1 << 30;
122 r = db_env->set_cachesize(db_env, cachesize / gig, cachesize % gig, 1); assert(r == 0);
123 }
124 r = db_env->open(db_env, db_env_dir, db_env_open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); assert(r == 0);
125 r = db_env->set_lock_timeout(db_env, 30 * 1000, nullptr); assert(r == 0);
126
127 // create the db
128 DB *db = NULL;
129 r = db_create(&db, db_env, 0); assert(r == 0);
130 if (pagesize) {
131 r = db->set_pagesize(db, pagesize); assert(r == 0);
132 }
133 r = db->open(db, NULL, db_filename, NULL, DB_BTREE, DB_CREATE|DB_AUTO_COMMIT|DB_THREAD, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); assert(r == 0);
134
135 toku_pthread_t tids[nthreads];
136 struct blocking_table_lock_args a = {db_env, db, nrows, sleeptime};
137 for (int i = 0; i < nthreads - 1; i++) {
138 r = toku_pthread_create(toku_uninstrumented,
139 &tids[i],
140 nullptr,
141 blocking_table_lock_thread,
142 &a);
143 assert(r == 0);
144 }
145 blocking_table_lock(db_env, db, nrows, sleeptime);
146 for (int i = 0; i < nthreads - 1; i++) {
147 void *ret;
148 r = toku_pthread_join(tids[i], &ret); assert(r == 0);
149 }
150
151 // close env
152 r = db->close(db, 0); assert(r == 0); db = NULL;
153 r = db_env->close(db_env, 0); assert(r == 0); db_env = NULL;
154
155 return 0;
156 }
157