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