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 /* Test to see if a big nested transaction (so big that it's rollbacks spill into a file)
41  * can commit properly.
42  *  Four Tests:
43  *     big child aborts, parent aborts (This test)
44  *     big child aborts, parent commits
45  *     big child commits, parent aborts
46  *     big child commits, parent commits
47  */
48 
49 #include <db.h>
50 #include <sys/stat.h>
51 
52 int N = 50000;
53 
54 static DB_ENV *env;
55 static DB *db;
56 static DB_TXN *xchild, *xparent;
57 
insert(int i,int j)58 static void insert (int i, int j) {
59     char hello[30], there[30];
60     DBT key,data;
61     if (verbose) printf("Insert %d\n", i);
62     snprintf(hello, sizeof(hello), "hello%d", i);
63     snprintf(there, sizeof(there), "there%d", j);
64     int r = db->put(db, xchild,
65 		    dbt_init(&key,  hello, strlen(hello)+1),
66 		    dbt_init(&data, there, strlen(there)+1),
67 		    0);
68     CKERR(r);
69 }
70 
lookup(int i,int expect,int expectj)71 static void lookup (int i, int expect, int expectj) {
72     char hello[30], there[30];
73     DBT key,data;
74     snprintf(hello, sizeof(hello), "hello%d", i);
75     memset(&data, 0, sizeof(data));
76     if (verbose) printf("Looking up %d (expecting %s)\n", i, expect==0 ? "to find" : "not to find");
77     int r = db->get(db, xchild,
78 		    dbt_init(&key,  hello, strlen(hello)+1),
79 		    &data,
80 		    0);
81     assert(expect==r);
82     if (expect==0) {
83 	CKERR(r);
84 	snprintf(there, sizeof(there), "there%d", expectj);
85 	assert(data.size==strlen(there)+1);
86 	assert(strcmp((char*)data.data, there)==0);
87     }
88 }
89 
90 static void
test_abort_abort(void)91 test_abort_abort (void) {
92     int i, r;
93     assert(N%2==0); // this test won't work if N is too small
94     r=env->txn_begin(env, 0, &xchild, 0); CKERR(r);
95     for (i=0; i<N/2; i++) {
96 	insert(i*2,i*4+1);
97     }
98     r=xchild->commit(xchild, 0); CKERR(r);
99     r=env->txn_begin(env, 0, &xparent, 0);  CKERR(r);
100     r=env->txn_begin(env, xparent, &xchild, 0); CKERR(r);
101     for (i=0; i<N; i++) {
102 	insert(i, i);
103     }
104     r=xchild->abort(xchild); CKERR(r);
105     r=env->txn_begin(env, xparent, &xchild, 0); CKERR(r);
106     for (i=0; i<N; i++) {
107 	lookup(i, (i%2==0)?0:DB_NOTFOUND, i*2+1);
108     }
109     r=xchild->commit(xchild, 0); CKERR(r);
110     r=xparent->abort(xparent); CKERR(r);
111     r=env->txn_begin(env, 0, &xchild, 0); CKERR(r);
112     for (i=0; i<N; i++) {
113 	lookup(i, (i%2==0)?0:DB_NOTFOUND, i*2+1);
114     }
115     r=xchild->commit(xchild, 0); CKERR(r);
116 }
117 
118 static void
setup(void)119 setup (void) {
120     DB_TXN *txn;
121     int r;
122     toku_os_recursive_delete(TOKU_TEST_FILENAME);
123     r=toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU+S_IRWXG+S_IRWXO);       CKERR(r);
124 
125     r=db_env_create(&env, 0); CKERR(r);
126 
127     r=env->set_redzone(env, 0);        CKERR(r);
128     env->set_errfile(env, stderr);
129     r=env->open(env, TOKU_TEST_FILENAME, DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_MPOOL|DB_INIT_TXN|DB_CREATE|DB_PRIVATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
130     r=db_create(&db, env, 0); CKERR(r);
131 
132     r=env->txn_begin(env, 0, &txn, 0); assert(r==0);
133     r=db->open(db, txn, "foo.db", 0, DB_BTREE, DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
134     r=txn->commit(txn, 0);    assert(r==0);
135 }
136 
137 static void
test_shutdown(void)138 test_shutdown (void) {
139     int r;
140     r=db->close(db, 0); CKERR(r);
141     r=env->close(env, 0); CKERR(r);
142 }
143 
144 int
test_main(int argc,char * const argv[])145 test_main (int argc, char * const argv[]) {
146     parse_args(argc, argv);
147     setup();
148     test_abort_abort();
149     test_shutdown();
150     return 0;
151 }
152