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