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 // generate a tree with a single leaf node containing unsorted keys
40 // check that ft verify finds them
41 
42 
43 #include <ft-cachetable-wrappers.h>
44 #include "test.h"
45 
46 static FTNODE
make_node(FT_HANDLE ft,int height)47 make_node(FT_HANDLE ft, int height) {
48     FTNODE node = NULL;
49     int n_children = (height == 0) ? 1 : 0;
50     toku_create_new_ftnode(ft, &node, height, n_children);
51     if (n_children) BP_STATE(node,0) = PT_AVAIL;
52     return node;
53 }
54 
55 static void
append_leaf(FTNODE leafnode,void * key,size_t keylen,void * val,size_t vallen)56 append_leaf(FTNODE leafnode, void *key, size_t keylen, void *val, size_t vallen) {
57     assert(leafnode->height == 0);
58 
59     DBT thekey;
60     toku_fill_dbt(&thekey, key, keylen);
61     DBT theval;
62     toku_fill_dbt(&theval, val, vallen);
63 
64     // get an index that we can use to create a new leaf entry
65     uint32_t idx = BLB_DATA(leafnode, 0)->num_klpairs();
66 
67     // apply an insert to the leaf node
68     MSN msn = next_dummymsn();
69     ft_msg msg(&thekey, &theval, FT_INSERT, msn, toku_xids_get_root_xids());
70     txn_gc_info gc_info(nullptr, TXNID_NONE, TXNID_NONE, false);
71     toku_ft_bn_apply_msg_once(
72         BLB(leafnode, 0),
73         msg,
74         idx,
75         keylen,
76         NULL,
77         &gc_info,
78         NULL,
79         NULL,
80         NULL);
81 
82     // don't forget to dirty the node
83     leafnode->set_dirty();
84 }
85 
86 static void
populate_leaf(FTNODE leafnode,int k,int v)87 populate_leaf(FTNODE leafnode, int k, int v) {
88     append_leaf(leafnode, &k, sizeof k, &v, sizeof v);
89 }
90 
91 static void
test_dup_in_leaf(int do_verify)92 test_dup_in_leaf(int do_verify) {
93     int r;
94 
95     // cleanup
96     const char *fname = TOKU_TEST_FILENAME;
97     r = unlink(fname);
98     assert(r == 0 || (r == -1 && errno == ENOENT));
99 
100     // create a cachetable
101     CACHETABLE ct = NULL;
102     toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
103 
104     // create the ft
105     TOKUTXN null_txn = NULL;
106     FT_HANDLE ft = NULL;
107     r = toku_open_ft_handle(fname, 1, &ft, 1024, 256, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun);
108     assert(r == 0);
109 
110     // discard the old root block
111     FTNODE newroot = make_node(ft, 0);
112     populate_leaf(newroot, htonl(2), 1);
113     populate_leaf(newroot, htonl(1), 2);
114 
115     // set the new root to point to the new tree
116     toku_ft_set_new_root_blocknum(ft->ft, newroot->blocknum);
117 
118     // unpin the new root
119     toku_unpin_ftnode(ft->ft, newroot);
120 
121     if (do_verify) {
122         r = toku_verify_ft(ft);
123         assert(r != 0);
124     }
125 
126     // flush to the file system
127     r = toku_close_ft_handle_nolsn(ft, 0);
128     assert(r == 0);
129 
130     // shutdown the cachetable
131     toku_cachetable_close(&ct);
132 }
133 
134 static int
usage(void)135 usage(void) {
136     return 1;
137 }
138 
139 int
test_main(int argc,const char * argv[])140 test_main (int argc , const char *argv[]) {
141     int do_verify = 1;
142     initialize_dummymsn();
143     for (int i = 1; i < argc; i++) {
144         const char *arg = argv[i];
145         if (strcmp(arg, "-v") == 0) {
146             verbose++;
147             continue;
148         }
149         if (strcmp(arg, "-q") == 0) {
150             verbose = 0;
151             continue;
152         }
153         if (strcmp(arg, "--verify") == 0 && i+1 < argc) {
154             do_verify = atoi(argv[++i]);
155             continue;
156         }
157         return usage();
158     }
159     test_dup_in_leaf(do_verify);
160     return 0;
161 }
162