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 /* The goal of this test: Make sure that when we aggressively promote
40 * that we don't get a fencepost error on the size. (#399, I think)
41
42 *
43 * For various values of I do the following:
44 *
45 * Make a tree of height 3 (that is, the root is of height 2)
46 * use small nodes (say 4KB)
47 * you have this tree:
48 * A
49 * B
50 * C0 C1 C2 .. C15
51 * A has only one child. B has as many children as it can get.
52 * Fill the C nodes (the leaves) all almost full.
53 * Fill B's buffer up with a big message X for C15, and a slightly smaller message Y for C1.
54 * Put into A's buffer a little message Z aimed at C0.
55 * Now when insert a message of size I aimed at C0. I and Z together are too big to fit in A.
56 * First: X will be pushed into C15, resulting in this split
57 * A
58 * B0
59 * C0 C1 ... C8
60 * B1
61 * C9 C10 ... C15 C16
62 * At this point C0 through C14 are full, Y is in B0's buffer, and A's buffer contains I and Z.
63 * So we try to push Z if it fits. Which it does.
64 * So then we try to I if it fits. If we calculated wrong, everything breaks now.
65 *
66 */
67
68 #include "test.h"
69
70
71 static TOKUTXN const null_txn = 0;
72
73 enum { NODESIZE = 1024, KSIZE=NODESIZE-100, TOKU_PSIZE=20 };
74
75 CACHETABLE ct;
76 FT_HANDLE t;
77 const char *fname = TOKU_TEST_FILENAME;
78
79 static void
doit(int ksize)80 doit (int ksize __attribute__((__unused__))) {
81 BLOCKNUM cnodes[16], bnode, anode;
82
83 char *keys[16-1];
84 int keylens[16-1];
85 int i;
86 int r;
87
88 toku_cachetable_create(&ct, 16*1024, ZERO_LSN, nullptr);
89 unlink(fname);
90 r = toku_open_ft_handle(fname, 1, &t, NODESIZE, NODESIZE, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun);
91 assert(r==0);
92
93 toku_testsetup_initialize(); // must precede any other toku_testsetup calls
94
95 for (i=0; i<16; i++) {
96 r=toku_testsetup_leaf(t, &cnodes[i], 1, NULL, NULL);
97 assert(r==0);
98 char key[KSIZE+10];
99 int keylen = 1+snprintf(key, KSIZE, "%08d%0*d", i*10000+1, KSIZE-9, 0);
100 char val[1];
101 char vallen=0;
102 r=toku_testsetup_insert_to_leaf(t, cnodes[i], key, keylen, val, vallen);
103 assert(r==0);
104 }
105
106 // Now we have a bunch of leaves, all of which are with 100 bytes of full.
107 for (i=0; i+1<16; i++) {
108 char key[TOKU_PSIZE];
109 keylens[i]=1+snprintf(key, TOKU_PSIZE, "%08d", (i+1)*10000);
110 keys[i]=toku_strdup(key);
111 }
112
113 r = toku_testsetup_nonleaf(t, 1, &bnode, 16, cnodes, keys, keylens);
114 assert(r==0);
115
116 for (i=0; i+1<16; i++) {
117 toku_free(keys[i]);
118 }
119
120 {
121 const int magic_size = (NODESIZE-toku_testsetup_get_sersize(t, bnode))/2-25;
122 //printf("magic_size=%d\n", magic_size);
123 char key [KSIZE];
124 int keylen = 1+snprintf(key, KSIZE, "%08d%0*d", 150002, magic_size, 0);
125 char val[1];
126 char vallen=0;
127 r=toku_testsetup_insert_to_nonleaf(t, bnode, FT_INSERT, key, keylen, val, vallen);
128
129 keylen = 1+snprintf(key, KSIZE, "%08d%0*d", 2, magic_size-1, 0);
130 r=toku_testsetup_insert_to_nonleaf(t, bnode, FT_INSERT, key, keylen, val, vallen);
131 }
132 //printf("%lld sersize=%d\n", bnode, toku_testsetup_get_sersize(t, bnode));
133 // Now we have an internal node which has full children and the buffers are nearly full
134
135 r = toku_testsetup_nonleaf(t, 2, &anode, 1, &bnode, 0, 0);
136 assert(r==0);
137 {
138 char key[20];
139 int keylen = 1+snprintf(key, 20, "%08d", 3);
140 char val[1];
141 char vallen=0;
142 r=toku_testsetup_insert_to_nonleaf(t, anode, FT_INSERT, key, keylen, val, vallen);
143 }
144 if (0)
145 {
146 const int magic_size = 1; //NODESIZE-toku_testsetup_get_sersize(t, anode)-100;
147 DBT k,v;
148 char key[20];
149 char data[magic_size];
150 int keylen=1+snprintf(key, sizeof(key), "%08d", 4);
151 int vallen=magic_size;
152 snprintf(data, magic_size, "%*s", magic_size-1, " ");
153 toku_ft_insert(t,
154 toku_fill_dbt(&k, key, keylen),
155 toku_fill_dbt(&v, data, vallen),
156 null_txn);
157 }
158
159 r = toku_testsetup_root(t, anode);
160 assert(r==0);
161
162 r = toku_close_ft_handle_nolsn(t, 0); assert(r==0);
163 toku_cachetable_close(&ct);
164
165 //printf("ksize=%d, unused\n", ksize);
166
167 }
168
169 int
test_main(int argc,const char * argv[])170 test_main (int argc __attribute__((__unused__)), const char *argv[] __attribute__((__unused__))) {
171 doit(53);
172 #if 0
173 //Skip remaining tests.
174 {
175 int i;
176
177 for (i=1; i<NODESIZE/2; i++) {
178 printf("extrasize=%d\n", i);
179 doit(i);
180 }
181 }
182 #endif
183
184 return 0;
185 }
186