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