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