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