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