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