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 #include "test.h"
40 #include "bndata.h"
41
42 static void
le_add_to_bn(bn_data * bn,uint32_t idx,const char * key,int keysize,const char * val,int valsize)43 le_add_to_bn(bn_data* bn, uint32_t idx, const char *key, int keysize, const char *val, int valsize)
44 {
45 LEAFENTRY r = NULL;
46 uint32_t size_needed = LE_CLEAN_MEMSIZE(valsize);
47 void *maybe_free = nullptr;
48 bn->get_space_for_insert(
49 idx,
50 key,
51 keysize,
52 size_needed,
53 &r,
54 &maybe_free
55 );
56 if (maybe_free) {
57 toku_free(maybe_free);
58 }
59 resource_assert(r);
60 r->type = LE_CLEAN;
61 r->u.clean.vallen = valsize;
62 memcpy(r->u.clean.val, val, valsize);
63 }
64
65 static void
le_overwrite(bn_data * bn,uint32_t idx,const char * key,int keysize,const char * val,int valsize)66 le_overwrite(bn_data* bn, uint32_t idx, const char *key, int keysize, const char *val, int valsize) {
67 LEAFENTRY r = NULL;
68 uint32_t size_needed = LE_CLEAN_MEMSIZE(valsize);
69 void *maybe_free = nullptr;
70 bn->get_space_for_overwrite(
71 idx,
72 key,
73 keysize,
74 keysize, // old_keylen
75 size_needed, // old_le_size
76 size_needed,
77 &r,
78 &maybe_free
79 );
80 if (maybe_free) {
81 toku_free(maybe_free);
82 }
83 resource_assert(r);
84 r->type = LE_CLEAN;
85 r->u.clean.vallen = valsize;
86 memcpy(r->u.clean.val, val, valsize);
87 }
88
89
90 class bndata_bugfix_test {
91 public:
92 void
run_test(void)93 run_test(void) {
94 // struct ft_handle source_ft;
95 struct ftnode sn;
96
97 // just copy this code from a previous test
98 // don't care what it does, just want to get a node up and running
99 sn.flags = 0x11223344;
100 sn.blocknum.b = 20;
101 sn.layout_version = FT_LAYOUT_VERSION;
102 sn.layout_version_original = FT_LAYOUT_VERSION;
103 sn.height = 0;
104 sn.n_children = 2;
105 sn.set_dirty();
106 sn.oldest_referenced_xid_known = TXNID_NONE;
107 MALLOC_N(sn.n_children, sn.bp);
108 DBT pivotkey;
109 sn.pivotkeys.create_from_dbts(toku_fill_dbt(&pivotkey, "b", 2), 1);
110 BP_STATE(&sn,0) = PT_AVAIL;
111 BP_STATE(&sn,1) = PT_AVAIL;
112 set_BLB(&sn, 0, toku_create_empty_bn());
113 set_BLB(&sn, 1, toku_create_empty_bn());
114 le_add_to_bn(BLB_DATA(&sn, 0), 0, "a", 2, "aval", 5);
115 le_add_to_bn(BLB_DATA(&sn, 0), 1, "b", 2, "bval", 5);
116 le_add_to_bn(BLB_DATA(&sn, 1), 0, "x", 2, "xval", 5);
117
118 // now this is the test. If I keep getting space for overwrite
119 // like crazy, it should expose the bug
120 bn_data* bnd = BLB_DATA(&sn, 0);
121 size_t old_size = bnd->m_buffer_mempool.size;
122 if (verbose) printf("frag size: %zu\n", bnd->m_buffer_mempool.frag_size);
123 if (verbose) printf("size: %zu\n", bnd->m_buffer_mempool.size);
124 for (uint32_t i = 0; i < 1000000; i++) {
125 le_overwrite(bnd, 0, "a", 2, "aval", 5);
126 }
127 if (verbose) printf("frag size: %zu\n", bnd->m_buffer_mempool.frag_size);
128 if (verbose) printf("size: %zu\n", bnd->m_buffer_mempool.size);
129 size_t new_size = bnd->m_buffer_mempool.size;
130 // just a crude test to make sure we did not grow unbounded.
131 // if this assert ever fails, revisit the code and see what is going
132 // on. It may be that some algorithm has changed.
133 assert(new_size < 5*old_size);
134
135 toku_destroy_ftnode_internals(&sn);
136 }
137 };
138
139 int
test_main(int argc,const char * argv[])140 test_main (int argc __attribute__((__unused__)), const char *argv[] __attribute__((__unused__))) {
141 bndata_bugfix_test t;
142 t.run_test();
143 return 0;
144 }
145