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
41 bool flush_may_occur;
42 long expected_bytes_to_free;
43
44 static void
flush(CACHEFILE f,int UU (fd),CACHEKEY k,void * v,void ** UU (dd),void * e,PAIR_ATTR s,PAIR_ATTR * new_size,bool w,bool keep,bool c,bool UU (is_clone))45 flush (CACHEFILE f __attribute__((__unused__)),
46 int UU(fd),
47 CACHEKEY k __attribute__((__unused__)),
48 void *v,
49 void** UU(dd),
50 void *e __attribute__((__unused__)),
51 PAIR_ATTR s __attribute__((__unused__)),
52 PAIR_ATTR* new_size __attribute__((__unused__)),
53 bool w __attribute__((__unused__)),
54 bool keep,
55 bool c __attribute__((__unused__)),
56 bool UU(is_clone)
57 ) {
58 assert(flush_may_occur);
59 if (!keep) {
60 int* CAST_FROM_VOIDP(foo, v);
61 assert(*foo == 3);
62 toku_free(v);
63 }
64 }
65
66 static int
fetch(CACHEFILE f,PAIR UU (p),int UU (fd),CACHEKEY k,uint32_t fullhash,void ** value,void ** UU (dd),PAIR_ATTR * sizep,int * dirtyp,void * extraargs)67 fetch (CACHEFILE f __attribute__((__unused__)),
68 PAIR UU(p),
69 int UU(fd),
70 CACHEKEY k __attribute__((__unused__)),
71 uint32_t fullhash __attribute__((__unused__)),
72 void **value __attribute__((__unused__)),
73 void** UU(dd),
74 PAIR_ATTR *sizep __attribute__((__unused__)),
75 int *dirtyp,
76 void *extraargs __attribute__((__unused__))
77 ) {
78 *dirtyp = 0;
79 int* XMALLOC(foo);
80 *value = foo;
81 *sizep = make_pair_attr(4);
82 *foo = 4;
83 return 0;
84 }
85
86 static void
other_flush(CACHEFILE f,int UU (fd),CACHEKEY k,void * v,void ** UU (dd),void * e,PAIR_ATTR s,PAIR_ATTR * new_size,bool w,bool keep,bool c,bool UU (is_clone))87 other_flush (CACHEFILE f __attribute__((__unused__)),
88 int UU(fd),
89 CACHEKEY k __attribute__((__unused__)),
90 void *v __attribute__((__unused__)),
91 void** UU(dd),
92 void *e __attribute__((__unused__)),
93 PAIR_ATTR s __attribute__((__unused__)),
94 PAIR_ATTR* new_size __attribute__((__unused__)),
95 bool w __attribute__((__unused__)),
96 bool keep __attribute__((__unused__)),
97 bool c __attribute__((__unused__)),
98 bool UU(is_clone)
99 ) {
100 }
101
102 static int
pe_callback(void * ftnode_pv,PAIR_ATTR UU (bytes_to_free),void * extraargs,void (* finalize)(PAIR_ATTR bytes_freed,void * extra),void * finalize_extra)103 pe_callback (
104 void *ftnode_pv,
105 PAIR_ATTR UU(bytes_to_free),
106 void* extraargs __attribute__((__unused__)),
107 void (*finalize)(PAIR_ATTR bytes_freed, void *extra),
108 void *finalize_extra
109 )
110 {
111 expected_bytes_to_free--;
112 int* CAST_FROM_VOIDP(foo, ftnode_pv);
113 int blah = *foo;
114 *foo = blah-1;
115 finalize(make_pair_attr(bytes_to_free.size-1), finalize_extra);
116 return 0;
117 }
118
119 static int
other_pe_callback(void * ftnode_pv,PAIR_ATTR bytes_to_free,void * extraargs,void (* finalize)(PAIR_ATTR bytes_freed,void * extra),void * finalize_extra)120 other_pe_callback (
121 void *ftnode_pv __attribute__((__unused__)),
122 PAIR_ATTR bytes_to_free __attribute__((__unused__)),
123 void* extraargs __attribute__((__unused__)),
124 void (*finalize)(PAIR_ATTR bytes_freed, void *extra),
125 void *finalize_extra
126 )
127 {
128 finalize(bytes_to_free, finalize_extra);
129 return 0;
130 }
131
132 static void
cachetable_test(void)133 cachetable_test (void) {
134 const int test_limit = 16;
135 int r;
136 CACHETABLE ct;
137 toku_cachetable_create(&ct, test_limit, ZERO_LSN, nullptr);
138 const char *fname1 = TOKU_TEST_FILENAME;
139 unlink(fname1);
140 CACHEFILE f1;
141 r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO); assert(r == 0);
142
143 void* v1;
144 void* v2;
145 flush_may_occur = false;
146 for (int i = 0; i < 100000; i++) {
147 CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
148 wc.flush_callback = flush;
149 wc.pe_callback = pe_callback;
150 r = toku_cachetable_get_and_pin(f1, make_blocknum(1), 1, &v1, wc, fetch, def_pf_req_callback, def_pf_callback, true, NULL);
151 r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_CLEAN, make_pair_attr(4));
152 }
153 for (int i = 0; i < 8; i++) {
154 CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
155 wc.flush_callback = flush;
156 wc.pe_callback = pe_callback;
157 r = toku_cachetable_get_and_pin(f1, make_blocknum(2), 2, &v2, wc, fetch, def_pf_req_callback, def_pf_callback, true, NULL);
158 r = toku_test_cachetable_unpin(f1, make_blocknum(2), 2, CACHETABLE_CLEAN, make_pair_attr(4));
159 }
160 for (int i = 0; i < 4; i++) {
161 CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
162 wc.flush_callback = flush;
163 wc.pe_callback = pe_callback;
164 r = toku_cachetable_get_and_pin(f1, make_blocknum(3), 3, &v2, wc, fetch, def_pf_req_callback, def_pf_callback, true, NULL);
165 r = toku_test_cachetable_unpin(f1, make_blocknum(3), 3, CACHETABLE_CLEAN, make_pair_attr(4));
166 }
167 for (int i = 0; i < 2; i++) {
168 CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
169 wc.flush_callback = flush;
170 wc.pe_callback = pe_callback;
171 r = toku_cachetable_get_and_pin(f1, make_blocknum(4), 4, &v2, wc, fetch, def_pf_req_callback, def_pf_callback, true, NULL);
172 r = toku_test_cachetable_unpin(f1, make_blocknum(4), 4, CACHETABLE_CLEAN, make_pair_attr(4));
173 }
174 flush_may_occur = false;
175 expected_bytes_to_free = 4;
176 CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
177 wc.flush_callback = other_flush;
178 wc.pe_callback = other_pe_callback;
179 toku_cachetable_put(f1, make_blocknum(5), 5, NULL, make_pair_attr(4), wc, put_callback_nop);
180 ct->ev.signal_eviction_thread();
181 usleep(1*1024*1024);
182 flush_may_occur = true;
183 r = toku_test_cachetable_unpin(f1, make_blocknum(5), 5, CACHETABLE_CLEAN, make_pair_attr(4));
184 ct->ev.signal_eviction_thread();
185 usleep(1*1024*1024);
186 assert(expected_bytes_to_free == 0);
187
188
189 toku_cachefile_close(&f1, false, ZERO_LSN);
190 toku_cachetable_close(&ct);
191 }
192
193 int
test_main(int argc,const char * argv[])194 test_main(int argc, const char *argv[]) {
195 default_parse_args(argc, argv);
196 cachetable_test();
197 return 0;
198 }
199