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 sleep(2);
63 }
64
65 static int fetch_calls = 0;
66
67 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)68 fetch (CACHEFILE f __attribute__((__unused__)),
69 PAIR UU(p),
70 int UU(fd),
71 CACHEKEY k __attribute__((__unused__)),
72 uint32_t fullhash __attribute__((__unused__)),
73 void **value __attribute__((__unused__)),
74 void** UU(dd),
75 PAIR_ATTR *sizep __attribute__((__unused__)),
76 int *dirtyp __attribute__((__unused__)),
77 void *extraargs __attribute__((__unused__))
78 ) {
79
80 fetch_calls++;
81
82 *value = 0;
83 *sizep = make_pair_attr(8);
84 *dirtyp = 0;
85
86 return 0;
87 }
88
89 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))90 pe_est_callback(
91 void* UU(ftnode_pv),
92 void* UU(dd),
93 long* bytes_freed_estimate,
94 enum partial_eviction_cost *cost,
95 void* UU(write_extraargs)
96 )
97 {
98 *bytes_freed_estimate = 0;
99 *cost = PE_EXPENSIVE;
100 }
101
cachetable_eviction_full_test(void)102 static void cachetable_eviction_full_test (void) {
103 const int test_limit = 12;
104 int r;
105 CACHETABLE ct;
106 toku_cachetable_create(&ct, test_limit, ZERO_LSN, nullptr);
107 const char *fname1 = TOKU_TEST_FILENAME;
108 unlink(fname1);
109 CACHEFILE f1;
110 r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO); assert(r == 0);
111
112 CACHEKEY key = make_blocknum(0);
113 uint32_t fullhash = toku_cachetable_hash(f1, make_blocknum(0));
114
115 void* value1;
116 void* value2;
117 //
118 // let's pin a node multiple times
119 // and really bring up its clock count
120 //
121 CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
122 wc.flush_callback = flush;
123 wc.pe_est_callback = pe_est_callback;
124 for (int i = 0; i < 20; i++) {
125 r = toku_cachetable_get_and_pin(
126 f1,
127 key,
128 fullhash,
129 &value1,
130 wc,
131 fetch,
132 def_pf_req_callback,
133 def_pf_callback,
134 true,
135 0
136 );
137 assert(r==0);
138 r = toku_test_cachetable_unpin(f1, key, fullhash, CACHETABLE_DIRTY, make_pair_attr(1));
139 assert(r == 0);
140 }
141 expect_full_flush = true;
142 // now pin a different, causing an eviction
143 wc.flush_callback = def_flush;
144 wc.pe_est_callback = pe_est_callback;
145 r = toku_cachetable_get_and_pin(
146 f1,
147 make_blocknum(1),
148 1,
149 &value2,
150 wc,
151 fetch,
152 def_pf_req_callback,
153 def_pf_callback,
154 true,
155 0
156 );
157 assert(r==0);
158 r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_CLEAN, make_pair_attr(1));
159 assert(r == 0);
160 toku_cachetable_verify(ct);
161
162 // close with the eviction in progress. the close should block until
163 // all of the reads and writes are complete.
164 toku_cachefile_close(&f1, false, ZERO_LSN);
165 toku_cachetable_close(&ct);
166 }
167
168 int
test_main(int argc,const char * argv[])169 test_main(int argc, const char *argv[]) {
170 default_parse_args(argc, argv);
171 cachetable_eviction_full_test();
172 return 0;
173 }
174