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 // test the LE_CURSOR next function with provisionally deleted rows
40
41
42 #include "cachetable/checkpoint.h"
43 #include "le-cursor.h"
44 #include "test.h"
45
46
47 static int
get_next_callback(uint32_t keylen,const void * key,uint32_t vallen UU (),const void * val UU (),void * extra,bool lock_only)48 get_next_callback(uint32_t keylen, const void *key, uint32_t vallen UU(), const void *val UU(), void *extra, bool lock_only) {
49 DBT *CAST_FROM_VOIDP(key_dbt, extra);
50 if (!lock_only) {
51 toku_dbt_set(keylen, key, key_dbt, NULL);
52 }
53 return 0;
54 }
55
56 static int
le_cursor_get_next(LE_CURSOR cursor,DBT * key)57 le_cursor_get_next(LE_CURSOR cursor, DBT *key) {
58 int r = toku_le_cursor_next(cursor, get_next_callback, key);
59 return r;
60 }
61
test_ft_cursor_keycompare(DB * desc,const DBT * a,const DBT * b)62 static int test_ft_cursor_keycompare(DB *desc __attribute__((unused)), const DBT *a, const DBT *b) {
63 return toku_keycompare(a->data, a->size, b->data, b->size);
64 }
65
66 // create a tree and populate it with n rows
67 static void
create_populate_tree(const char * logdir,const char * fname,int n)68 create_populate_tree(const char *logdir, const char *fname, int n) {
69 if (verbose) fprintf(stderr, "%s %s %s %d\n", __FUNCTION__, logdir, fname, n);
70 int error;
71
72 TOKULOGGER logger = NULL;
73 error = toku_logger_create(&logger);
74 assert(error == 0);
75 error = toku_logger_open(logdir, logger);
76 assert(error == 0);
77 CACHETABLE ct = NULL;
78 toku_cachetable_create(&ct, 0, ZERO_LSN, logger);
79 toku_logger_set_cachetable(logger, ct);
80 error = toku_logger_open_rollback(logger, ct, true);
81 assert(error == 0);
82
83 TOKUTXN txn = NULL;
84 error = toku_txn_begin_txn(NULL, NULL, &txn, logger, TXN_SNAPSHOT_NONE, false);
85 assert(error == 0);
86
87 FT_HANDLE ft = NULL;
88 error = toku_open_ft_handle(fname, 1, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, txn, test_ft_cursor_keycompare);
89 assert(error == 0);
90
91 error = toku_txn_commit_txn(txn, true, NULL, NULL);
92 assert(error == 0);
93 toku_txn_close_txn(txn);
94
95 txn = NULL;
96 error = toku_txn_begin_txn(NULL, NULL, &txn, logger, TXN_SNAPSHOT_NONE, false);
97 assert(error == 0);
98
99 // insert keys 0, 1, 2, .. (n-1)
100 for (int i = 0; i < n; i++) {
101 int k = toku_htonl(i);
102 int v = i;
103 DBT key;
104 toku_fill_dbt(&key, &k, sizeof k);
105 DBT val;
106 toku_fill_dbt(&val, &v, sizeof v);
107 toku_ft_insert(ft, &key, &val, txn);
108 assert(error == 0);
109 }
110
111 error = toku_txn_commit_txn(txn, true, NULL, NULL);
112 assert(error == 0);
113 toku_txn_close_txn(txn);
114
115 error = toku_close_ft_handle_nolsn(ft, NULL);
116 assert(error == 0);
117
118 CHECKPOINTER cp = toku_cachetable_get_checkpointer(ct);
119 error = toku_checkpoint(cp, logger, NULL, NULL, NULL, NULL, CLIENT_CHECKPOINT);
120 assert(error == 0);
121
122 toku_logger_close_rollback(logger);
123
124 error = toku_checkpoint(cp, logger, NULL, NULL, NULL, NULL, CLIENT_CHECKPOINT);
125 assert(error == 0);
126
127 toku_logger_shutdown(logger);
128
129 error = toku_logger_close(&logger);
130 assert(error == 0);
131
132 toku_cachetable_close(&ct);
133 }
134
135 // provionally delete all of the even keys
136 // the LE_CURSOR should see all of the leaf entries
137 static void
test_provdel(const char * logdir,const char * fname,int n)138 test_provdel(const char *logdir, const char *fname, int n) {
139 if (verbose) fprintf(stderr, "%s %s %s %d\n", __FUNCTION__, logdir, fname, n);
140 int error;
141
142 TOKULOGGER logger = NULL;
143 error = toku_logger_create(&logger);
144 assert(error == 0);
145 error = toku_logger_open(logdir, logger);
146 assert(error == 0);
147 CACHETABLE ct = NULL;
148 toku_cachetable_create(&ct, 0, ZERO_LSN, logger);
149 toku_logger_set_cachetable(logger, ct);
150 error = toku_logger_open_rollback(logger, ct, false);
151 assert(error == 0);
152
153 TOKUTXN txn = NULL;
154 error = toku_txn_begin_txn(NULL, NULL, &txn, logger, TXN_SNAPSHOT_NONE, false);
155 assert(error == 0);
156
157 FT_HANDLE ft = NULL;
158 error = toku_open_ft_handle(fname, 1, &ft, 1<<12, 1<<9, TOKU_DEFAULT_COMPRESSION_METHOD, ct, txn, test_ft_cursor_keycompare);
159 assert(error == 0);
160
161 error = toku_txn_commit_txn(txn, true, NULL, NULL);
162 assert(error == 0);
163 toku_txn_close_txn(txn);
164
165 txn = NULL;
166 error = toku_txn_begin_txn(NULL, NULL, &txn, logger, TXN_SNAPSHOT_NONE, false);
167 assert(error == 0);
168
169 // del keys 0, 2, 4, ...
170 for (int i = 0; i < n; i += 2) {
171 int k = toku_htonl(i);
172 DBT key;
173 toku_fill_dbt(&key, &k, sizeof k);
174 toku_ft_delete(ft, &key, txn);
175 assert(error == 0);
176 }
177
178 TOKUTXN cursortxn = NULL;
179 error = toku_txn_begin_txn(NULL, NULL, &cursortxn, logger, TXN_SNAPSHOT_NONE, false);
180 assert(error == 0);
181
182 LE_CURSOR cursor = NULL;
183 error = toku_le_cursor_create(&cursor, ft, cursortxn);
184 assert(error == 0);
185
186 DBT key;
187 toku_init_dbt(&key); key.flags = DB_DBT_REALLOC;
188 DBT val;
189 toku_init_dbt(&val); val.flags = DB_DBT_REALLOC;
190
191 int i;
192 for (i=0; ; i++) {
193 error = le_cursor_get_next(cursor, &key);
194 if (error != 0)
195 break;
196
197 assert(key.size == sizeof (int));
198 int ii = *(int *)key.data;
199 assert((int) toku_htonl(n-i-1) == ii);
200 }
201 assert(i == n);
202
203 toku_destroy_dbt(&key);
204 toku_destroy_dbt(&val);
205
206 toku_le_cursor_close(cursor);
207
208 error = toku_txn_commit_txn(cursortxn, true, NULL, NULL);
209 assert(error == 0);
210 toku_txn_close_txn(cursortxn);
211
212 error = toku_txn_commit_txn(txn, true, NULL, NULL);
213 assert(error == 0);
214 toku_txn_close_txn(txn);
215
216 error = toku_close_ft_handle_nolsn(ft, NULL);
217 assert(error == 0);
218 CHECKPOINTER cp = toku_cachetable_get_checkpointer(ct);
219 error = toku_checkpoint(cp, logger, NULL, NULL, NULL, NULL, CLIENT_CHECKPOINT);
220 assert(error == 0);
221
222 toku_logger_close_rollback(logger);
223 error = toku_logger_close(&logger);
224 assert(error == 0);
225
226 toku_cachetable_close(&ct);
227 }
228
229 static void
init_logdir(const char * logdir)230 init_logdir(const char *logdir) {
231 int error;
232
233 toku_os_recursive_delete(logdir);
234 error = toku_os_mkdir(logdir, 0777);
235 assert(error == 0);
236 }
237
238 int
test_main(int argc,const char * argv[])239 test_main (int argc , const char *argv[]) {
240 default_parse_args(argc, argv);
241 toku_os_recursive_delete(TOKU_TEST_FILENAME);
242 int r = toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU);
243 assert_zero(r);
244
245 char logdir[TOKU_PATH_MAX+1];
246 toku_path_join(logdir, 2, TOKU_TEST_FILENAME, "logdir");
247 init_logdir(logdir);
248 int error = chdir(logdir);
249 assert(error == 0);
250
251 const int n = 10;
252 create_populate_tree(".", "ftfile", n);
253 test_provdel(".", "ftfile", n);
254
255 return 0;
256 }
257