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