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 // this mutex is used by some of the tests to serialize access to some
42 // global data, especially between the test thread and the cachetable
43 // writeback threads
44
45 toku_mutex_t test_mutex;
46
test_mutex_init(void)47 static inline void test_mutex_init(void) {
48 toku_mutex_init(toku_uninstrumented, &test_mutex, nullptr);
49 }
50
test_mutex_destroy(void)51 static inline void test_mutex_destroy(void) { toku_mutex_destroy(&test_mutex); }
52
test_mutex_lock(void)53 static inline void test_mutex_lock(void) {
54 toku_mutex_lock(&test_mutex);
55 }
56
test_mutex_unlock(void)57 static inline void test_mutex_unlock(void) {
58 toku_mutex_unlock(&test_mutex);
59 }
60
61 // verify that cachetable creation and close works
62
63 static void
test_cachetable_create(void)64 test_cachetable_create(void) {
65 CACHETABLE ct = NULL;
66 toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr);
67 toku_cachetable_close(&ct);
68 }
69
70 static const int test_object_size = 1;
71
72 struct item {
73 CACHEKEY key;
74 const char *something;
75 };
76
77 static CACHEFILE expect_f;
78
maybe_flush(CACHETABLE t)79 static void maybe_flush(CACHETABLE t) {
80 toku_cachetable_maybe_flush_some(t);
81 }
82
83
flush_n(CACHEFILE f,int UU (fd),CACHEKEY key,void * value,void ** UU (dd),void * extra,PAIR_ATTR size,PAIR_ATTR * new_size,bool write_me,bool keep_me,bool for_checkpoint,bool UU (is_clone))84 static void flush_n (CACHEFILE f __attribute__((__unused__)), int UU(fd), CACHEKEY key __attribute__((__unused__)),
85 void *value,
86 void** UU(dd),
87 void *extra __attribute__((__unused__)),
88 PAIR_ATTR size __attribute__((__unused__)),
89 PAIR_ATTR* new_size __attribute__((__unused__)),
90 bool write_me __attribute__((__unused__)), bool keep_me __attribute__((__unused__)),
91 bool for_checkpoint __attribute__ ((__unused__)),
92 bool UU(is_clone)
93 ) {
94 int *CAST_FROM_VOIDP(v, value);
95 assert(*v==0);
96 }
fetch_n(CACHEFILE f,PAIR UU (p),int UU (fd),CACHEKEY key,uint32_t fullhash,void ** value,void ** UU (dd),PAIR_ATTR * sizep,int * dirtyp,void * extraargs)97 static int fetch_n (CACHEFILE f __attribute__((__unused__)), PAIR UU(p), int UU(fd), CACHEKEY key __attribute__((__unused__)),
98 uint32_t fullhash __attribute__((__unused__)),
99 void**value,
100 void** UU(dd),
101 PAIR_ATTR *sizep __attribute__((__unused__)),
102 int * dirtyp, void*extraargs) {
103 assert((long)extraargs==42);
104 *value=0;
105 *dirtyp = 0;
106 *sizep = make_pair_attr(0);
107 return 0;
108 }
109
110
test_nested_pin(void)111 static void test_nested_pin (void) {
112 void *f2=(void*)42;
113 CACHETABLE t;
114 CACHEFILE f;
115 int i0, i1;
116 int r;
117 void *vv,*vv2;
118 const char *fname = TOKU_TEST_FILENAME;
119 if (verbose) printf("creating cachetable\n");
120 toku_cachetable_create(&t, 1, ZERO_LSN, nullptr);
121 toku_os_recursive_delete(fname);
122 r = toku_cachetable_openf(&f, t, fname, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO);
123 assert(r==0);
124 expect_f = f;
125
126 i0=0; i1=0;
127 uint32_t f1hash = toku_cachetable_hash(f, make_blocknum(1));
128 CACHETABLE_WRITE_CALLBACK wc = def_write_callback(f2);
129 wc.flush_callback = flush_n;
130 toku_cachetable_put(f, make_blocknum(1), f1hash, &i0, make_pair_attr(1), wc, put_callback_nop);
131 r = toku_test_cachetable_unpin(f, make_blocknum(1), f1hash, CACHETABLE_CLEAN, make_pair_attr(test_object_size));
132 r = toku_cachetable_get_and_pin(f, make_blocknum(1), f1hash, &vv, wc, fetch_n, def_pf_req_callback, def_pf_callback, true, f2);
133 assert(r==0);
134 assert(vv==&i0);
135 assert(i0==0);
136 r = toku_test_cachetable_unpin(f, make_blocknum(1), f1hash, CACHETABLE_CLEAN, make_pair_attr(test_object_size));
137 assert(r==0);
138 r = toku_cachetable_maybe_get_and_pin(f, make_blocknum(1), f1hash, PL_WRITE_EXPENSIVE, &vv2);
139 assert(r==0);
140 assert(vv2==vv);
141 r = toku_test_cachetable_unpin(f, make_blocknum(1), f1hash, CACHETABLE_CLEAN, make_pair_attr(test_object_size));
142 assert(r==0);
143 uint32_t f2hash = toku_cachetable_hash(f, make_blocknum(2));
144 toku_cachetable_put(f, make_blocknum(2), f2hash, &i1, make_pair_attr(test_object_size), wc, put_callback_nop);
145 r = toku_test_cachetable_unpin(f, make_blocknum(2), f2hash, CACHETABLE_CLEAN, make_pair_attr(test_object_size));
146 assert(r==0);
147 toku_cachefile_close(&f, false, ZERO_LSN);
148 toku_cachetable_close(&t);
149 }
150
151
null_flush(CACHEFILE cf,int UU (fd),CACHEKEY k,void * v,void ** UU (dd),void * extra,PAIR_ATTR size,PAIR_ATTR * new_size,bool write_me,bool keep_me,bool for_checkpoint,bool UU (is_clone))152 static void null_flush (CACHEFILE cf __attribute__((__unused__)),
153 int UU(fd),
154 CACHEKEY k __attribute__((__unused__)),
155 void *v __attribute__((__unused__)),
156 void** UU(dd),
157 void *extra __attribute__((__unused__)),
158 PAIR_ATTR size __attribute__((__unused__)),
159 PAIR_ATTR* new_size __attribute__((__unused__)),
160 bool write_me __attribute__((__unused__)),
161 bool keep_me __attribute__((__unused__)),
162 bool for_checkpoint __attribute__((__unused__)),
163 bool UU(is_clone)
164 ) {
165 }
166
add123_fetch(CACHEFILE cf,PAIR UU (p),int UU (fd),CACHEKEY key,uint32_t fullhash,void ** value,void ** UU (dd),PAIR_ATTR * sizep,int * dirtyp,void * extraargs)167 static int add123_fetch (CACHEFILE cf, PAIR UU(p), int UU(fd), CACHEKEY key, uint32_t fullhash, void **value,
168 void** UU(dd),
169 PAIR_ATTR *sizep __attribute__((__unused__)), int * dirtyp, void*extraargs) {
170 assert(fullhash==toku_cachetable_hash(cf,key));
171 assert((long)extraargs==123);
172 *value = (void*)((unsigned long)key.b+123L);
173 *dirtyp = 0;
174 *sizep = make_pair_attr(0);
175 return 0;
176 }
177
add222_fetch(CACHEFILE cf,PAIR UU (p),int UU (fd),CACHEKEY key,uint32_t fullhash,void ** value,void ** UU (dd),PAIR_ATTR * sizep,int * dirtyp,void * extraargs)178 static int add222_fetch (CACHEFILE cf, PAIR UU(p), int UU(fd), CACHEKEY key, uint32_t fullhash, void **value,
179 void** UU(dd),
180 PAIR_ATTR *sizep __attribute__((__unused__)), int * dirtyp, void*extraargs) {
181 assert(fullhash==toku_cachetable_hash(cf,key));
182 assert((long)extraargs==222);
183 *value = (void*)((unsigned long)key.b+222L);
184 *dirtyp = 0;
185 *sizep = make_pair_attr(0);
186 return 0;
187 }
188
test_multi_filehandles(void)189 static void test_multi_filehandles (void) {
190 CACHETABLE t;
191 CACHEFILE f1,f2,f3;
192 toku_os_recursive_delete(TOKU_TEST_FILENAME);
193 int r = toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU);
194 assert_zero(r);
195 char fname1[TOKU_PATH_MAX+1];
196 char fname2[TOKU_PATH_MAX+1];
197 char fname3[TOKU_PATH_MAX+1];
198 toku_path_join(fname1, 2, TOKU_TEST_FILENAME, "test1_ct.dat");
199 toku_path_join(fname2, 2, TOKU_TEST_FILENAME, "test2_ct.dat");
200 toku_path_join(fname3, 2, TOKU_TEST_FILENAME, "test3_ct.dat");
201 void *v;
202 unlink(fname1);
203 unlink(fname2);
204
205 toku_cachetable_create(&t, 4, ZERO_LSN, nullptr);
206 r = toku_cachetable_openf(&f1, t, fname1, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO); assert(r==0);
207 r = link(fname1, fname2); assert(r==0);
208 r = toku_cachetable_openf(&f2, t, fname2, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO); assert(r==0);
209 r = toku_cachetable_openf(&f3, t, fname3, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO); assert(r==0);
210
211 assert(f1==f2);
212 assert(f1!=f3);
213
214 CACHETABLE_WRITE_CALLBACK wc = def_write_callback((void*)123);
215 wc.flush_callback = null_flush;
216 toku_cachetable_put(f1, make_blocknum(1), toku_cachetable_hash(f1, make_blocknum(1)), (void*)124, make_pair_attr(test_object_size), wc, put_callback_nop);
217 r = toku_test_cachetable_unpin(f1, make_blocknum(1), toku_cachetable_hash(f1, make_blocknum(1)), CACHETABLE_DIRTY, make_pair_attr(0)); assert(r==0);
218 r = toku_cachetable_get_and_pin(f2, make_blocknum(1), toku_cachetable_hash(f2, make_blocknum(1)), &v, wc, add123_fetch, def_pf_req_callback, def_pf_callback, true, (void*)123); assert(r==0);
219 assert((unsigned long)v==124);
220 r = toku_cachetable_get_and_pin(f2, make_blocknum(2), toku_cachetable_hash(f2, make_blocknum(2)), &v, wc, add123_fetch, def_pf_req_callback, def_pf_callback, true, (void*)123); assert(r==0);
221 assert((unsigned long)v==125);
222 wc.write_extraargs = (void*)222;
223 r = toku_cachetable_get_and_pin(f3, make_blocknum(2), toku_cachetable_hash(f3, make_blocknum(2)), &v, wc, add222_fetch, def_pf_req_callback, def_pf_callback, true, (void*)222); assert(r==0);
224 assert((unsigned long)v==224);
225
226 // we support only one close for a file handle
227 r = toku_test_cachetable_unpin(f1, make_blocknum(1), toku_cachetable_hash(f1, make_blocknum(1)), CACHETABLE_CLEAN, make_pair_attr(0)); assert(r==0);
228 r = toku_test_cachetable_unpin(f2, make_blocknum(2), toku_cachetable_hash(f2, make_blocknum(2)), CACHETABLE_CLEAN, make_pair_attr(0)); assert(r==0);
229 toku_cachefile_close(&f2, false, ZERO_LSN);
230
231 r = toku_test_cachetable_unpin(f3, make_blocknum(2), toku_cachetable_hash(f3, make_blocknum(2)), CACHETABLE_CLEAN, make_pair_attr(0)); assert(r==0);
232 toku_cachefile_close(&f3, false, ZERO_LSN);
233
234 toku_cachetable_close(&t);
235 }
236
test_dirty_flush(CACHEFILE f,int UU (fd),CACHEKEY key,void * value,void ** UU (dd),void * extra,PAIR_ATTR size,PAIR_ATTR * new_size,bool do_write,bool keep,bool for_checkpoint,bool UU (is_clone))237 static void test_dirty_flush(CACHEFILE f,
238 int UU(fd),
239 CACHEKEY key,
240 void *value,
241 void** UU(dd),
242 void *extra __attribute__((__unused__)),
243 PAIR_ATTR size,
244 PAIR_ATTR* new_size __attribute__((__unused__)),
245 bool do_write,
246 bool keep,
247 bool for_checkpoint __attribute__((__unused__)),
248 bool UU(is_clone)
249 ) {
250 if (verbose) printf("test_dirty_flush %p %" PRId64 " %p %ld %u %u\n", f, key.b, value, size.size, (unsigned)do_write, (unsigned)keep);
251 }
252
test_dirty_fetch(CACHEFILE f,PAIR UU (p),int UU (fd),CACHEKEY key,uint32_t fullhash,void ** value_ptr,void ** UU (dd),PAIR_ATTR * size_ptr,int * dirtyp,void * arg)253 static int test_dirty_fetch(CACHEFILE f, PAIR UU(p), int UU(fd), CACHEKEY key, uint32_t fullhash, void **value_ptr,
254 void** UU(dd),
255 PAIR_ATTR *size_ptr, int * dirtyp, void *arg) {
256 *value_ptr = arg;
257 *dirtyp = 0;
258 *size_ptr = make_pair_attr(0);
259 assert(fullhash==toku_cachetable_hash(f,key));
260 if (verbose) printf("test_dirty_fetch %p %" PRId64 " %p %ld %p\n", f, key.b, *value_ptr, size_ptr->size, arg);
261 return 0;
262 }
263
test_dirty(void)264 static void test_dirty(void) {
265 if (verbose) printf("test_dirty\n");
266
267 CACHETABLE t;
268 CACHEFILE f;
269 CACHEKEY key; void *value;
270 int dirty; long long pinned; long entry_size;
271 int r;
272
273 toku_cachetable_create(&t, 4, ZERO_LSN, nullptr);
274
275 const char *fname = TOKU_TEST_FILENAME;
276 toku_os_recursive_delete(fname);
277 r = toku_cachetable_openf(&f, t, fname, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO);
278 assert(r == 0);
279
280 key = make_blocknum(1); value = (void*)1;
281 uint32_t hkey = toku_cachetable_hash(f, key);
282 CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
283 wc.flush_callback = test_dirty_flush;
284 toku_cachetable_put(f, key, hkey, value, make_pair_attr(test_object_size), wc, put_callback_nop);
285
286 // cachetable_print_state(t);
287 r = toku_cachetable_get_key_state(t, key, f, &value, &dirty, &pinned, &entry_size);
288 assert(r == 0);
289 assert(dirty == 1);
290 assert(pinned == 1);
291
292 r = toku_test_cachetable_unpin(f, key, hkey, CACHETABLE_CLEAN, make_pair_attr(0));
293 assert(r == 0);
294 r = toku_cachetable_get_key_state(t, key, f, &value, &dirty, &pinned, &entry_size);
295 assert(r == 0);
296 assert(dirty == 1);
297 assert(pinned == 0);
298
299 r = toku_cachetable_get_and_pin(f, key, hkey, &value, wc,
300 test_dirty_fetch, def_pf_req_callback, def_pf_callback, true, 0);
301 assert(r == 0);
302
303 // cachetable_print_state(t);
304 r = toku_cachetable_get_key_state(t, key, f, &value, &dirty, &pinned, &entry_size);
305 assert(r == 0);
306 assert(dirty == 1);
307 assert(pinned == 1);
308
309 r = toku_test_cachetable_unpin(f, key, hkey, CACHETABLE_CLEAN, make_pair_attr(test_object_size));
310 assert(r == 0);
311
312 // cachetable_print_state(t);
313 r = toku_cachetable_get_key_state(t, key, f, &value, &dirty, &pinned, &entry_size);
314 assert(r == 0);
315 assert(dirty == 1);
316 assert(pinned == 0);
317
318 key = make_blocknum(2);
319 hkey = toku_cachetable_hash(f, key);
320 r = toku_cachetable_get_and_pin(f, key, hkey,
321 &value, wc,
322 test_dirty_fetch, def_pf_req_callback, def_pf_callback, true, 0);
323 assert(r == 0);
324
325 // cachetable_print_state(t);
326 r = toku_cachetable_get_key_state(t, key, f, &value, &dirty, &pinned, &entry_size);
327 assert(r == 0);
328 assert(dirty == 0);
329 assert(pinned == 1);
330
331 r = toku_test_cachetable_unpin(f, key, hkey, CACHETABLE_CLEAN, make_pair_attr(test_object_size));
332 assert(r == 0);
333
334 // cachetable_print_state(t);
335 r = toku_cachetable_get_key_state(t, key, f, &value, &dirty, &pinned, &entry_size);
336 assert(r == 0);
337 assert(dirty == 0);
338 assert(pinned == 0);
339
340 r = toku_cachetable_get_and_pin(f, key, hkey,
341 &value, wc,
342 test_dirty_fetch, def_pf_req_callback, def_pf_callback, true, 0);
343 assert(r == 0);
344
345 // cachetable_print_state(t);
346 r = toku_cachetable_get_key_state(t, key, f, &value, &dirty, &pinned, &entry_size);
347 assert(r == 0);
348 assert(dirty == 0);
349 assert(pinned == 1);
350
351 r = toku_test_cachetable_unpin(f, key, hkey, CACHETABLE_DIRTY, make_pair_attr(test_object_size));
352 assert(r == 0);
353
354 // cachetable_print_state(t);
355 r = toku_cachetable_get_key_state(t, key, f, &value, &dirty, &pinned, &entry_size);
356 assert(r == 0);
357 assert(dirty == 1);
358 assert(pinned == 0);
359
360 toku_cachefile_close(&f, false, ZERO_LSN);
361
362 toku_cachetable_close(&t);
363 }
364
365 static int test_size_debug;
366 static CACHEKEY test_size_flush_key;
367
test_size_flush_callback(CACHEFILE f,int UU (fd),CACHEKEY key,void * value,void ** UU (dd),void * extra,PAIR_ATTR size,PAIR_ATTR * new_size,bool do_write,bool keep,bool for_checkpoint,bool UU (is_clone))368 static void test_size_flush_callback(CACHEFILE f,
369 int UU(fd),
370 CACHEKEY key,
371 void *value,
372 void** UU(dd),
373 void *extra __attribute__((__unused__)),
374 PAIR_ATTR size,
375 PAIR_ATTR* new_size __attribute__((__unused__)),
376 bool do_write,
377 bool keep,
378 bool for_checkpoint __attribute__((__unused__)),
379 bool UU(is_clone)
380 ) {
381 if (test_size_debug && verbose) printf("test_size_flush %p %" PRId64 " %p %ld %u %u\n", f, key.b, value, size.size, (unsigned)do_write, (unsigned)keep);
382 if (keep) {
383 if (do_write) {
384 test_mutex_lock();
385 test_size_flush_key = key;
386 test_mutex_unlock();
387 }
388 } else {
389 assert(!do_write);
390 }
391 }
392
test_size_resize(void)393 static void test_size_resize(void) {
394 if (verbose) printf("test_size_resize\n");
395
396 CACHETABLE t;
397 CACHEFILE f;
398 int r;
399
400 int n = 3;
401 long size = 1;
402
403 toku_cachetable_create(&t, n*size, ZERO_LSN, nullptr);
404
405 const char *fname = TOKU_TEST_FILENAME;
406 unlink(fname);
407 r = toku_cachetable_openf(&f, t, fname, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO);
408 assert(r == 0);
409
410 CACHEKEY key = make_blocknum(42);
411 void *value = (void *) -42;
412
413 uint32_t hkey = toku_cachetable_hash(f, key);
414
415 CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
416 wc.flush_callback = test_size_flush_callback;
417 toku_cachetable_put(f, key, hkey, value, make_pair_attr(size), wc, put_callback_nop);
418
419 void *entry_value; int dirty; long long pinned; long entry_size;
420 r = toku_cachetable_get_key_state(t, key, f, &entry_value, &dirty, &pinned, &entry_size);
421 assert(r == 0);
422 assert(dirty == 1);
423 assert(pinned == 1);
424 assert(entry_value == value);
425 assert(entry_size == size);
426
427 long long new_size = 2*size;
428 r = toku_test_cachetable_unpin(f, key, hkey, CACHETABLE_CLEAN, make_pair_attr(new_size));
429 assert(r == 0);
430
431 void *current_value;
432 r = toku_cachetable_get_and_pin(f, key, hkey, ¤t_value, wc, 0, def_pf_req_callback, def_pf_callback, true, 0);
433 assert(r == 0);
434 assert(current_value == value);
435 PAIR_ATTR attr;
436 r = toku_cachetable_get_attr(f, key, hkey, &attr);
437 assert(r == 0);
438 assert(attr.size == new_size);
439
440 r = toku_test_cachetable_unpin(f, key, hkey, CACHETABLE_CLEAN, make_pair_attr(new_size));
441 assert(r == 0);
442
443 toku_cachefile_close(&f, false, ZERO_LSN);
444 toku_cachetable_close(&t);
445 }
446
min2(int a,int b)447 static int min2(int a, int b) { return a < b ? a : b; }
448
449 __attribute__((unused))
test_size_flush(void)450 static void test_size_flush(void) {
451 if (verbose) printf("test_size_flush\n");
452
453 CACHETABLE t;
454 CACHEFILE f;
455 int r;
456
457 const int n = 8;
458 long long size = 1*1024*1024;
459 toku_cachetable_create(&t, n*size, ZERO_LSN, nullptr);
460
461 const char *fname = TOKU_TEST_FILENAME;
462 unlink(fname);
463 r = toku_cachetable_openf(&f, t, fname, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO);
464 assert(r == 0);
465
466 /* put 2*n keys into the table, ensure flushes occur in key order */
467 test_mutex_lock();
468 test_size_flush_key = make_blocknum(-1);
469 test_mutex_unlock();
470
471 int i;
472 CACHEKEY expect_flush_key = make_blocknum(0);
473 for (i=0; i<2*n; i++) {
474 CACHEKEY key = make_blocknum(i);
475 void *value = (void *)(long)-i;
476 // printf("test_size put %lld %p %lld\n", key, value, size);
477 uint32_t hkey = toku_cachetable_hash(f, key);
478 CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
479 wc.flush_callback = test_size_flush_callback;
480 toku_cachetable_put(f, key, hkey, value, make_pair_attr(size), wc, put_callback_nop);
481
482 int n_entries, hash_size; long size_current, size_limit;
483 toku_cachetable_get_state(t, &n_entries, &hash_size, &size_current, &size_limit);
484 while (n_entries != min2(i+1, n)) {
485 toku_pthread_yield(); maybe_flush(t);
486 toku_cachetable_get_state(t, &n_entries, 0, 0, 0);
487 }
488 assert(n_entries == min2(i+1, n));
489
490 void *entry_value; int dirty; long long pinned; long entry_size;
491 r = toku_cachetable_get_key_state(t, key, f, &entry_value, &dirty, &pinned, &entry_size);
492 assert(r == 0);
493 assert(dirty == 1);
494 assert(pinned == 1);
495 assert(entry_value == value);
496 assert(entry_size == size);
497
498 test_mutex_lock();
499 if (test_size_flush_key.b != -1) {
500 assert(test_size_flush_key.b == expect_flush_key.b);
501 assert(expect_flush_key.b == i-n);
502 expect_flush_key.b += 1;
503 }
504 test_mutex_unlock();
505
506 r = toku_test_cachetable_unpin(f, key, hkey, CACHETABLE_CLEAN, make_pair_attr(size));
507 assert(r == 0);
508 }
509
510 toku_cachefile_close(&f, false, ZERO_LSN);
511 toku_cachetable_close(&t);
512 }
513
514 int
test_main(int argc,const char * argv[])515 test_main (int argc, const char *argv[]) {
516 // parse args
517 int i;
518 for (i=1; i<argc; i++) {
519 const char *arg = argv[i];
520 if (strcmp(arg, "-v") == 0) {
521 verbose++;
522 continue;
523 }
524 if (strcmp(arg, "-q") == 0) {
525 if (verbose > 0) verbose--;
526 continue;
527 }
528 }
529
530 test_mutex_init();
531
532 // run tests
533 test_multi_filehandles();
534 test_cachetable_create();
535 for (i=0; i<1; i++) {
536 test_nested_pin();
537 test_multi_filehandles ();
538 test_dirty();
539 test_size_resize();
540 //test_size_flush();
541 }
542
543 test_mutex_destroy();
544
545 if (verbose) printf("ok\n");
546 return 0;
547 }
548