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, &current_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