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 // verify that closing the cachetable with prefetches in progress works
40 
41 #include "test.h"
42 
43 bool check_flush;
44 bool expect_full_flush;
45 bool expect_pe;
46 
47 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))48 flush (CACHEFILE f __attribute__((__unused__)),
49        int UU(fd),
50        CACHEKEY k  __attribute__((__unused__)),
51        void *v     __attribute__((__unused__)),
52        void** UU(dd),
53        void *e     __attribute__((__unused__)),
54        PAIR_ATTR s      __attribute__((__unused__)),
55        PAIR_ATTR* new_size      __attribute__((__unused__)),
56        bool w      __attribute__((__unused__)),
57        bool keep   __attribute__((__unused__)),
58        bool c      __attribute__((__unused__)),
59         bool UU(is_clone)
60        ) {
61     assert(expect_full_flush);
62 }
63 
64 static int fetch_calls = 0;
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       __attribute__((__unused__)),
76        void *extraargs    __attribute__((__unused__))
77        ) {
78 
79     fetch_calls++;
80 
81     *value = 0;
82     *sizep = make_pair_attr(8);
83     *dirtyp = 0;
84 
85     return 0;
86 }
87 
88 static void
pe_est_callback(void * UU (ftnode_pv),void * UU (dd),long * bytes_freed_estimate,enum partial_eviction_cost * cost,void * UU (write_extraargs))89 pe_est_callback(
90     void* UU(ftnode_pv),
91     void* UU(dd),
92     long* bytes_freed_estimate,
93     enum partial_eviction_cost *cost,
94     void* UU(write_extraargs)
95     )
96 {
97     *bytes_freed_estimate = 7;
98     *cost = PE_EXPENSIVE;
99 }
100 
101 static int
pe_callback(void * ftnode_pv,PAIR_ATTR bytes_to_free,void * extraargs,void (* finalize)(PAIR_ATTR bytes_freed,void * extra),void * finalize_extra)102 pe_callback (
103     void *ftnode_pv __attribute__((__unused__)),
104     PAIR_ATTR bytes_to_free __attribute__((__unused__)),
105     void* extraargs __attribute__((__unused__)),
106     void (*finalize)(PAIR_ATTR bytes_freed, void *extra),
107     void *finalize_extra
108     )
109 {
110     sleep(2);
111     finalize(bytes_to_free, finalize_extra);
112     return 0;
113 }
114 
cachetable_eviction_full_test(void)115 static void cachetable_eviction_full_test (void) {
116     const int test_limit = 12;
117     int r;
118     CACHETABLE ct;
119     toku_cachetable_create(&ct, test_limit, ZERO_LSN, nullptr);
120     const char *fname1 = TOKU_TEST_FILENAME;
121     unlink(fname1);
122     CACHEFILE f1;
123     r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO); assert(r == 0);
124 
125     CACHEKEY key = make_blocknum(0);
126     uint32_t fullhash = toku_cachetable_hash(f1, make_blocknum(0));
127 
128     void* value1;
129     void* value2;
130     //
131     // let's pin a node multiple times
132     // and really bring up its clock count
133     //
134     for (int i = 0; i < 20; i++) {
135         CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
136         wc.flush_callback = flush;
137         wc.pe_est_callback = pe_est_callback;
138         wc.pe_callback = pe_callback;
139         r = toku_cachetable_get_and_pin(
140             f1,
141             key,
142             fullhash,
143             &value1,
144             wc,
145             fetch,
146             def_pf_req_callback,
147             def_pf_callback,
148             true,
149             0
150             );
151         assert(r==0);
152         r = toku_test_cachetable_unpin(f1, key, fullhash, CACHETABLE_DIRTY, make_pair_attr(8));
153         assert(r == 0);
154     }
155     expect_full_flush = true;
156     // now pin a different, causing an eviction
157     CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
158     wc.pe_est_callback = pe_est_callback;
159     wc.pe_callback = pe_callback;
160     r = toku_cachetable_get_and_pin(
161         f1,
162         make_blocknum(1),
163         1,
164         &value2,
165         wc,
166         fetch,
167         def_pf_req_callback,
168         def_pf_callback,
169         true,
170         0
171         );
172     assert(r==0);
173     r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_CLEAN, make_pair_attr(1));
174     assert(r == 0);
175     toku_cachetable_verify(ct);
176 
177     // close with the eviction in progress. the close should block until
178     // all of the reads and writes are complete.
179     toku_cachefile_close(&f1, false, ZERO_LSN);
180     toku_cachetable_close(&ct);
181 }
182 
183 int
test_main(int argc,const char * argv[])184 test_main(int argc, const char *argv[]) {
185     default_parse_args(argc, argv);
186     cachetable_eviction_full_test();
187     return 0;
188 }
189