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 #pragma once
40 
41 #include <toku_portability.h>
42 #include <toku_htonl.h>
43 #include <toku_assert.h>
44 #include <toku_stdlib.h>
45 
46 #include <stdio.h>
47 #include <memory.h>
48 #include <string.h>
49 #include <portability/toku_path.h>
50 
51 #include "ft/serialize/block_allocator.h"
52 #include "ft/serialize/block_table.h"
53 #include "ft/cachetable/cachetable.h"
54 #include "ft/cachetable/cachetable-internal.h"
55 #include "ft/cursor.h"
56 #include "ft/ft.h"
57 #include "ft/ft-ops.h"
58 #include "ft/serialize/ft-serialize.h"
59 #include "ft/serialize/ft_node-serialize.h"
60 #include "ft/logger/log-internal.h"
61 #include "ft/logger/logger.h"
62 #include "ft/node.h"
63 #include "util/bytestring.h"
64 
65 #define CKERR(r) ({ int __r = r; if (__r!=0) fprintf(stderr, "%s:%d error %d %s\n", __FILE__, __LINE__, __r, strerror(r)); assert(__r==0); })
66 #define CKERR2(r,r2) do { if (r!=r2) fprintf(stderr, "%s:%d error %d %s, expected %d\n", __FILE__, __LINE__, r, strerror(r), r2); assert(r==r2); } while (0)
67 #define CKERR2s(r,r2,r3) do { if (r!=r2 && r!=r3) fprintf(stderr, "%s:%d error %d %s, expected %d or %d\n", __FILE__, __LINE__, r, strerror(r), r2,r3); assert(r==r2||r==r3); } while (0)
68 
69 #define DEBUG_LINE() do { \
70     fprintf(stderr, "%s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \
71     fflush(stderr); \
72 } while (0)
73 
74 const uint32_t len_ignore = 0xFFFFFFFF;
75 
76 static const prepared_txn_callback_t NULL_prepared_txn_callback         __attribute__((__unused__)) = NULL;
77 static const keep_cachetable_callback_t  NULL_keep_cachetable_callback  __attribute__((__unused__)) = NULL;
78 static const TOKULOGGER NULL_logger                                     __attribute__((__unused__)) = NULL;
79 
80 // dummymsn needed to simulate msn because test messages are injected at a lower level than toku_ft_root_put_msg()
81 #define MIN_DUMMYMSN ((MSN) {(uint64_t)1<<62})
82 static MSN dummymsn;
83 static int dummymsn_initialized = 0;
84 
85 static void
initialize_dummymsn(void)86 initialize_dummymsn(void) {
87     if (dummymsn_initialized == 0) {
88         dummymsn_initialized = 1;
89         dummymsn = MIN_DUMMYMSN;
90     }
91 }
92 
UU()93 static UU() MSN
94 next_dummymsn(void) {
95     assert(dummymsn_initialized);
96     ++(dummymsn.msn);
97     return dummymsn;
98 }
99 
UU()100 static UU() MSN
101 last_dummymsn(void) {
102     assert(dummymsn_initialized);
103     return dummymsn;
104 }
105 
106 
107 struct check_pair {
108     uint32_t keylen;  // A keylen equal to 0xFFFFFFFF means don't check the keylen or the key.
109     const void *key;     // A NULL key means don't check the key.
110     uint32_t vallen;  // Similarly for vallen and null val.
111     const void *val;
112     int call_count;
113 };
114 static int
lookup_checkf(uint32_t keylen,const void * key,uint32_t vallen,const void * val,void * pair_v,bool lock_only)115 lookup_checkf (uint32_t keylen, const void *key, uint32_t vallen, const void *val, void *pair_v, bool lock_only) {
116     if (!lock_only) {
117         struct check_pair *pair = (struct check_pair *) pair_v;
118         if (key!=NULL) {
119             if (pair->keylen!=len_ignore) {
120                 assert(pair->keylen == keylen);
121                 if (pair->key)
122                     assert(memcmp(pair->key, key, keylen)==0);
123             }
124             if (pair->vallen!=len_ignore) {
125                 assert(pair->vallen == vallen);
126                 if (pair->val)
127                     assert(memcmp(pair->val, val, vallen)==0);
128             }
129             pair->call_count++; // this call_count is really how many calls were made with r==0
130         }
131     }
132     return 0;
133 }
134 
135 static inline void
ft_lookup_and_check_nodup(FT_HANDLE t,const char * keystring,const char * valstring)136 ft_lookup_and_check_nodup (FT_HANDLE t, const char *keystring, const char *valstring)
137 {
138     DBT k;
139     toku_fill_dbt(&k, keystring, strlen(keystring) + 1);
140     struct check_pair pair = {(uint32_t) (1+strlen(keystring)), keystring,
141                               (uint32_t) (1+strlen(valstring)), valstring,
142 			      0};
143     int r = toku_ft_lookup(t, &k, lookup_checkf, &pair);
144     assert(r==0);
145     assert(pair.call_count==1);
146 }
147 
148 static inline void
ft_lookup_and_fail_nodup(FT_HANDLE t,char * keystring)149 ft_lookup_and_fail_nodup (FT_HANDLE t, char *keystring)
150 {
151     DBT k;
152     toku_fill_dbt(&k, keystring, strlen(keystring) + 1);
153     struct check_pair pair = {(uint32_t) (1+strlen(keystring)), keystring,
154 			      0, 0,
155 			      0};
156     int r = toku_ft_lookup(t, &k, lookup_checkf, &pair);
157     assert(r!=0);
158     assert(pair.call_count==0);
159 }
160 
UU()161 static UU() void fake_ydb_lock(void) {
162 }
163 
UU()164 static UU() void fake_ydb_unlock(void) {
165 }
166 
UU()167 static UU() void
168 def_flush (CACHEFILE f __attribute__((__unused__)),
169        int UU(fd),
170        CACHEKEY k  __attribute__((__unused__)),
171        void *v     __attribute__((__unused__)),
172        void **dd     __attribute__((__unused__)),
173        void *e     __attribute__((__unused__)),
174        PAIR_ATTR s      __attribute__((__unused__)),
175        PAIR_ATTR* new_size      __attribute__((__unused__)),
176        bool w      __attribute__((__unused__)),
177        bool keep   __attribute__((__unused__)),
178        bool c      __attribute__((__unused__)),
179        bool UU(is_clone)
180        ) {
181 }
182 
UU()183 static UU() void
184 def_pe_est_callback(
185     void* UU(ftnode_pv),
186     void* UU(dd),
187     long* bytes_freed_estimate,
188     enum partial_eviction_cost *cost,
189     void* UU(write_extraargs)
190     )
191 {
192     *bytes_freed_estimate = 0;
193     *cost = PE_CHEAP;
194 }
195 
UU()196 static UU() int
197 def_pe_callback(
198     void *ftnode_pv __attribute__((__unused__)),
199     PAIR_ATTR bytes_to_free __attribute__((__unused__)),
200     void* extraargs __attribute__((__unused__)),
201     void (*finalize)(PAIR_ATTR bytes_freed, void *extra),
202     void *finalize_extra
203     )
204 {
205     finalize(bytes_to_free, finalize_extra);
206     return 0;
207 }
208 
UU()209 static UU() void
210 def_pe_finalize_impl(PAIR_ATTR UU(bytes_freed), void *UU(extra)) { }
211 
UU()212 static UU() bool def_pf_req_callback(void* UU(ftnode_pv), void* UU(read_extraargs)) {
213   return false;
214 }
215 
UU()216   static UU() int def_pf_callback(void* UU(ftnode_pv), void* UU(dd), void* UU(read_extraargs), int UU(fd), PAIR_ATTR* UU(sizep)) {
217   assert(false);
218   return 0;
219 }
220 
UU()221 static UU() int
222 def_fetch (CACHEFILE f        __attribute__((__unused__)),
223        PAIR UU(p),
224        int UU(fd),
225        CACHEKEY k         __attribute__((__unused__)),
226        uint32_t fullhash __attribute__((__unused__)),
227        void **value       __attribute__((__unused__)),
228        void **dd     __attribute__((__unused__)),
229        PAIR_ATTR *sizep        __attribute__((__unused__)),
230        int  *dirtyp,
231        void *extraargs    __attribute__((__unused__))
232        ) {
233     *dirtyp = 0;
234     *value = NULL;
235     *sizep = make_pair_attr(8);
236     return 0;
237 }
238 
UU()239 static UU() void
240 put_callback_nop(
241     CACHEKEY UU(key),
242     void *UU(v),
243     PAIR UU(p)) {
244 }
245 
UU()246 static UU() int
247 fetch_die(
248     CACHEFILE UU(thiscf),
249     PAIR UU(p),
250     int UU(fd),
251     CACHEKEY UU(key),
252     uint32_t UU(fullhash),
253     void **UU(value),
254     void **UU(dd),
255     PAIR_ATTR *UU(sizep),
256     int *UU(dirtyp),
257     void *UU(extraargs)
258     )
259 {
260     assert(0); // should not be called
261     return 0;
262 }
263 
264 
UU()265 static UU() int
266 def_cleaner_callback(
267     void* UU(ftnode_pv),
268     BLOCKNUM UU(blocknum),
269     uint32_t UU(fullhash),
270     void* UU(extraargs)
271     )
272 {
273     assert(false);
274     return 0;
275 }
276 
UU()277 static UU() CACHETABLE_WRITE_CALLBACK def_write_callback(void* write_extraargs) {
278     CACHETABLE_WRITE_CALLBACK wc;
279     wc.flush_callback = def_flush;
280     wc.pe_est_callback = def_pe_est_callback;
281     wc.pe_callback = def_pe_callback;
282     wc.cleaner_callback = def_cleaner_callback;
283     wc.write_extraargs = write_extraargs;
284     wc.clone_callback = nullptr;
285     wc.checkpoint_complete_callback = nullptr;
286     return wc;
287 }
288 
289 class evictor_test_helpers {
290 public:
set_hysteresis_limits(evictor * ev,long low_size_watermark,long high_size_watermark)291     static void set_hysteresis_limits(evictor* ev, long low_size_watermark, long high_size_watermark) {
292         ev->m_low_size_watermark = low_size_watermark;
293         ev->m_low_size_hysteresis = low_size_watermark;
294         ev->m_high_size_hysteresis = high_size_watermark;
295         ev->m_high_size_watermark = high_size_watermark;
296     }
disable_ev_thread(evictor * ev)297     static void disable_ev_thread(evictor* ev) {
298         toku_mutex_lock(&ev->m_ev_thread_lock);
299         ev->m_period_in_seconds = 0;
300         // signal eviction thread so that it wakes up
301         // and then sleeps indefinitely
302         ev->signal_eviction_thread_locked();
303         toku_mutex_unlock(&ev->m_ev_thread_lock);
304         // sleep for one second to ensure eviction thread picks up new period
305         usleep(1*1024*1024);
306     }
get_num_eviction_runs(evictor * ev)307     static uint64_t get_num_eviction_runs(evictor* ev) {
308         return ev->m_num_eviction_thread_runs;
309     }
310 };
311 
UU()312 UU()
313 static void copy_dbt(DBT *dest, const DBT *src) {
314     assert(dest->flags & DB_DBT_REALLOC);
315     dest->data = toku_realloc(dest->data, src->size);
316     dest->size = src->size;
317     memcpy(dest->data, src->data, src->size);
318 }
319 
320 int verbose=0;
321 
322 static inline void
default_parse_args(int argc,const char * argv[])323 default_parse_args (int argc, const char *argv[]) {
324     const char *progname=argv[0];
325     argc--; argv++;
326     while (argc>0) {
327 	if (strcmp(argv[0],"-v")==0) {
328 	    ++verbose;
329 	} else if (strcmp(argv[0],"-q")==0) {
330 	    verbose=0;
331 	} else {
332 	    fprintf(stderr, "Usage:\n %s [-v] [-q]\n", progname);
333 	    exit(1);
334 	}
335 	argc--; argv++;
336     }
337 }
338 
339 int test_main(int argc, const char *argv[]);
340 
341 int
main(int argc,const char * argv[])342 main(int argc, const char *argv[]) {
343     initialize_dummymsn();
344     int rinit = toku_ft_layer_init();
345     CKERR(rinit);
346     int r = test_main(argc, argv);
347     toku_ft_layer_destroy();
348     return r;
349 }
350