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