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