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