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 #include <stdio.h>
42 #include <stdlib.h>
43
44 #include <unistd.h>
45 #include <memory.h>
46 #include <errno.h>
47 #include <sys/stat.h>
48 #include <db.h>
49
50
51 static int
db_put(DB * db,DB_TXN * txn,int k,int v)52 db_put (DB *db, DB_TXN *txn, int k, int v) {
53 DBT key, val;
54 return db->put(db, txn, dbt_init(&key, &k, sizeof k), dbt_init(&val, &v, sizeof v), DB_NOOVERWRITE);
55 }
56
db_error(int error)57 static const char *db_error(int error) {
58 static char errorbuf[32];
59 switch (error) {
60 case DB_NOTFOUND: return "DB_NOTFOUND";
61 case DB_LOCK_DEADLOCK: return "DB_LOCK_DEADLOCK";
62 case DB_LOCK_NOTGRANTED: return "DB_LOCK_NOTGRANTED";
63 case DB_KEYEXIST: return "DB_KEYEXIST";
64 default:
65 sprintf(errorbuf, "%d", error);
66 return errorbuf;
67 }
68 }
69
70 /* t1 t2 l1 l2 p1 p2 c1 c2 */
71 static void
test_txn_cursor_last_1(int nrows)72 test_txn_cursor_last_1 (int nrows) {
73 if (verbose) printf("test_txn_cursor_last_1:%d\n", nrows);
74
75 int r;
76 toku_os_recursive_delete(TOKU_TEST_FILENAME);
77 toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU+S_IRWXG+S_IRWXO);
78
79 DB_ENV *env;
80 DB *db;
81 DB_TXN * const null_txn = 0;
82 const char * const fname = "test.txn.cursor.last.1.ft_handle";
83
84 /* create the dup database file */
85 r = db_env_create(&env, 0); assert(r == 0);
86 env->set_errfile(env, stderr);
87 r = env->open(env, TOKU_TEST_FILENAME, DB_CREATE|DB_INIT_MPOOL|DB_INIT_TXN|DB_INIT_LOCK|DB_INIT_LOG |DB_THREAD |DB_PRIVATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
88 r = db_create(&db, env, 0); assert(r == 0);
89 db->set_errfile(db,stderr); // Turn off those annoying errors
90 r = db->open(db, null_txn, fname, "main", DB_BTREE, DB_CREATE+DB_AUTO_COMMIT, 0666); assert(r == 0);
91 int i;
92 for (i=0; i<nrows; i++) {
93 int k = htonl(i);
94 int v = htonl(i);
95 DBT key, val;
96 r = db->put(db, null_txn, dbt_init(&key, &k, sizeof k), dbt_init(&val, &v, sizeof v), 0);
97 assert(r == 0);
98 }
99
100 DB_TXN *t1;
101 r = env->txn_begin(env, null_txn, &t1, 0); assert(r == 0);
102 if (verbose) printf("t1:begin\n");
103
104 DBC *c1;
105 r = db->cursor(db, t1, &c1, 0); assert(r == 0);
106
107 DB_TXN *t2;
108 r = env->txn_begin(env, null_txn, &t2, 0); assert(r == 0);
109 if (verbose) printf("t2:begin\n");
110
111 DBC *c2;
112 r = db->cursor(db, t2, &c2, 0); assert(r == 0);
113
114 DBT k1; memset(&k1, 0, sizeof k1);
115 DBT v1; memset(&v1, 0, sizeof v1);
116 r = c1->c_get(c1, &k1, &v1, DB_LAST);
117 if (verbose) printf("c1:last:%s\n", db_error(r));
118
119 r = c1->c_close(c1); assert(r == 0);
120
121 DBT k2; memset(&k2, 0, sizeof k2);
122 DBT v2; memset(&v2, 0, sizeof v2);
123 r = c2->c_get(c2, &k2, &v2, DB_LAST);
124 if (verbose) printf("c2:last:%s\n", db_error(r));
125
126 r = c2->c_close(c2); assert(r == 0);
127
128 int r1 = db_put(db, t1, htonl(nrows), htonl(nrows));
129 if (verbose) printf("t1:put:%s\n", db_error(r1));
130
131 int r2 = db_put(db, t2, htonl(nrows), htonl(nrows));
132 if (verbose) printf("t2:put:%s\n", db_error(r2));
133
134 if (r1 == 0) {
135 r = t1->commit(t1, 0);
136 if (verbose) printf("t1:commit:%s\n", db_error(r));
137 } else {
138 r = t1->abort(t1);
139 if (verbose) printf("t1:abort:%s\n", db_error(r));
140 }
141
142 if (r2 == 0) {
143 r = t2->commit(t2, 0);
144 if (verbose) printf("t2:commit:%s\n", db_error(r));
145 } else {
146 r = t2->abort(t2);
147 if (verbose) printf("t2:abort:%s\n", db_error(r));
148 }
149
150 r = db->close(db, 0); assert(r == 0);
151 r = env->close(env, 0); assert(r == 0);
152 }
153
154 /* t1 t2 l1 p1 l2 c1 p2 c2 */
155 static void
test_txn_cursor_last_2(int nrows)156 test_txn_cursor_last_2 (int nrows) {
157 if (verbose) printf("test_txn_cursor_last_2:%d\n", nrows);
158
159 int r;
160 toku_os_recursive_delete(TOKU_TEST_FILENAME);
161 toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU+S_IRWXG+S_IRWXO);
162
163 DB_ENV *env;
164 DB *db;
165 DB_TXN * const null_txn = 0;
166 const char * const fname = "test.txn.cursor.last.1.ft_handle";
167
168 /* create the dup database file */
169 r = db_env_create(&env, 0); assert(r == 0);
170 env->set_errfile(env, stderr);
171 r = env->open(env, TOKU_TEST_FILENAME, DB_CREATE|DB_INIT_MPOOL|DB_INIT_TXN|DB_INIT_LOCK|DB_INIT_LOG|DB_THREAD|DB_PRIVATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
172 r = db_create(&db, env, 0); assert(r == 0);
173 db->set_errfile(db,stderr); // Turn off those annoying errors
174 r = db->open(db, null_txn, fname, "main", DB_BTREE, DB_CREATE+DB_AUTO_COMMIT, 0666); assert(r == 0);
175 int i;
176 for (i=0; i<nrows; i++) {
177 int k = htonl(i);
178 int v = htonl(i);
179 DBT key, val;
180 r = db->put(db, null_txn, dbt_init(&key, &k, sizeof k), dbt_init(&val, &v, sizeof v), 0);
181 assert(r == 0);
182 }
183
184 DB_TXN *t1;
185 r = env->txn_begin(env, null_txn, &t1, 0); assert(r == 0);
186 if (verbose) printf("t1:begin\n");
187
188 DBC *c1;
189 r = db->cursor(db, t1, &c1, 0); assert(r == 0);
190
191 DB_TXN *t2;
192 r = env->txn_begin(env, null_txn, &t2, 0); assert(r == 0);
193 if (verbose) printf("t2:begin\n");
194
195 DBC *c2;
196 r = db->cursor(db, t2, &c2, 0); assert(r == 0);
197
198 DBT k1; memset(&k1, 0, sizeof k1);
199 DBT v1; memset(&v1, 0, sizeof v1);
200 r = c1->c_get(c1, &k1, &v1, DB_LAST);
201 if (verbose) printf("c1:last:%s\n", db_error(r));
202
203 r = c1->c_close(c1); assert(r == 0);
204
205 int r1 = db_put(db, t1, htonl(nrows), htonl(nrows));
206 if (verbose) printf("t1:put:%s\n", db_error(r1));
207
208 DBT k2; memset(&k2, 0, sizeof k2);
209 DBT v2; memset(&v2, 0, sizeof v2);
210 r = c2->c_get(c2, &k2, &v2, DB_LAST);
211 if (verbose) printf("c2:last:%s\n", db_error(r));
212
213 r = c2->c_close(c2); assert(r == 0);
214
215 if (r1 == 0) {
216 r = t1->commit(t1, 0);
217 if (verbose) printf("t1:commit:%s\n", db_error(r));
218 } else {
219 r = t1->abort(t1);
220 if (verbose) printf("t1:abort:%s\n", db_error(r));
221 }
222
223 int r2 = db_put(db, t2, htonl(nrows), htonl(nrows));
224 if (verbose) printf("t2:put:%s\n", db_error(r2));
225
226 if (r2 == 0) {
227 r = t2->commit(t2, 0);
228 if (verbose) printf("t2:commit:%s\n", db_error(r));
229 } else {
230 r = t2->abort(t2);
231 if (verbose) printf("t2:abort:%s\n", db_error(r));
232 }
233
234 r = db->close(db, 0); assert(r == 0);
235 r = env->close(env, 0); assert(r == 0);
236 }
237
238 int
test_main(int argc,char * const argv[])239 test_main(int argc, char *const argv[]) {
240
241 parse_args(argc, argv);
242
243 test_txn_cursor_last_1(0);
244 test_txn_cursor_last_1(1);
245 test_txn_cursor_last_2(0);
246 test_txn_cursor_last_2(1);
247
248 return 0;
249 }
250