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 get_and_pin waits while a prefetch block is pending */
40
41 #include "test.h"
42
43
44 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))45 pe_est_callback(
46 void* UU(ftnode_pv),
47 void* UU(dd),
48 long* bytes_freed_estimate,
49 enum partial_eviction_cost *cost,
50 void* UU(write_extraargs)
51 )
52 {
53 *bytes_freed_estimate = 7;
54 *cost = PE_EXPENSIVE;
55 }
56
57 static int
pe_callback(void * ftnode_pv,PAIR_ATTR bytes_to_free,void * extraargs,void (* finalize)(PAIR_ATTR new_attr,void * extra),void * finalize_extra)58 pe_callback (
59 void *ftnode_pv __attribute__((__unused__)),
60 PAIR_ATTR bytes_to_free __attribute__((__unused__)),
61 void* extraargs __attribute__((__unused__)),
62 void (*finalize)(PAIR_ATTR new_attr, void *extra),
63 void *finalize_extra
64 )
65 {
66 sleep(3);
67 finalize(make_pair_attr(bytes_to_free.size - 7), finalize_extra);
68 return 0;
69 }
70
tdelta_usec(struct timeval * tend,struct timeval * tstart)71 static uint64_t tdelta_usec(struct timeval *tend, struct timeval *tstart) {
72 uint64_t t = tend->tv_sec * 1000000 + tend->tv_usec;
73 t -= tstart->tv_sec * 1000000 + tstart->tv_usec;
74 return t;
75 }
76
cachetable_prefetch_maybegetandpin_test(void)77 static void cachetable_prefetch_maybegetandpin_test (void) {
78 const int test_limit = 12;
79 int r;
80 CACHETABLE ct;
81 toku_cachetable_create(&ct, test_limit, ZERO_LSN, nullptr);
82 evictor_test_helpers::disable_ev_thread(&ct->ev);
83 const char *fname1 = TOKU_TEST_FILENAME;
84 unlink(fname1);
85 CACHEFILE f1;
86 r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO); assert(r == 0);
87 CACHEKEY key = make_blocknum(0);
88 uint32_t fullhash = toku_cachetable_hash(f1, make_blocknum(0));
89
90 // let's get and pin this node a bunch of times to drive up the clock count
91 CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
92 wc.pe_est_callback = pe_est_callback;
93 wc.pe_callback = pe_callback;
94 for (int i = 0; i < 20; i++) {
95 void* value;
96 r = toku_cachetable_get_and_pin(
97 f1,
98 key,
99 fullhash,
100 &value,
101 wc,
102 def_fetch,
103 def_pf_req_callback,
104 def_pf_callback,
105 true,
106 0
107 );
108 assert(r==0);
109 r = toku_test_cachetable_unpin(f1, key, fullhash, CACHETABLE_DIRTY, make_pair_attr(8));
110 }
111
112 struct timeval tstart;
113 gettimeofday(&tstart, NULL);
114
115 // fetch another block, causing an eviction of the first block we made above
116 void* value2;
117 r = toku_cachetable_get_and_pin(
118 f1,
119 make_blocknum(1),
120 1,
121 &value2,
122 wc,
123 def_fetch,
124 def_pf_req_callback,
125 def_pf_callback,
126 true,
127 0
128 );
129 assert(r==0);
130 ct->ev.signal_eviction_thread();
131 usleep(1*1024*1024);
132 r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_CLEAN, make_pair_attr(8));
133
134
135 toku_cachetable_verify(ct);
136
137 void *v = 0;
138 // now verify that the block we are trying to evict may be pinned
139 r = toku_cachetable_get_and_pin_nonblocking(
140 f1,
141 key,
142 fullhash,
143 &v,
144 wc,
145 def_fetch,
146 def_pf_req_callback,
147 def_pf_callback,
148 PL_WRITE_EXPENSIVE,
149 NULL,
150 NULL
151 );
152 assert(r==TOKUDB_TRY_AGAIN);
153 r = toku_cachetable_get_and_pin(
154 f1,
155 key,
156 fullhash,
157 &v,
158 wc,
159 def_fetch,
160 def_pf_req_callback,
161 def_pf_callback,
162 true,
163 NULL
164 );
165 assert(r == 0 && v == 0);
166 PAIR_ATTR attr;
167 r = toku_cachetable_get_attr(f1, key, fullhash, &attr);
168 assert(r == 0 && attr.size == 1);
169
170 struct timeval tend;
171 gettimeofday(&tend, NULL);
172
173 assert(tdelta_usec(&tend, &tstart) >= 2000000);
174 if (verbose) printf("time %" PRIu64 " \n", tdelta_usec(&tend, &tstart));
175 toku_cachetable_verify(ct);
176
177 r = toku_test_cachetable_unpin(f1, key, fullhash, CACHETABLE_CLEAN, make_pair_attr(1));
178 assert(r == 0);
179 toku_cachetable_verify(ct);
180
181 toku_cachefile_close(&f1, false, ZERO_LSN);
182 toku_cachetable_close(&ct);
183 }
184
185 int
test_main(int argc,const char * argv[])186 test_main(int argc, const char *argv[]) {
187 default_parse_args(argc, argv);
188 cachetable_prefetch_maybegetandpin_test();
189 return 0;
190 }
191