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 bool do_pf;
44 bool expect_pf;
45 
46 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))47 flush (CACHEFILE f __attribute__((__unused__)),
48        int UU(fd),
49        CACHEKEY k  __attribute__((__unused__)),
50        void *v     __attribute__((__unused__)),
51        void** UU(dd),
52        void *e     __attribute__((__unused__)),
53        PAIR_ATTR s      __attribute__((__unused__)),
54        PAIR_ATTR* new_size      __attribute__((__unused__)),
55        bool w      __attribute__((__unused__)),
56        bool keep   __attribute__((__unused__)),
57        bool c      __attribute__((__unused__)),
58         bool UU(is_clone)
59        ) {
60     assert(w == false);
61 }
62 
63 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)64 fetch (CACHEFILE f        __attribute__((__unused__)),
65        PAIR UU(p),
66        int UU(fd),
67        CACHEKEY k         __attribute__((__unused__)),
68        uint32_t fullhash __attribute__((__unused__)),
69        void **value       __attribute__((__unused__)),
70        void** UU(dd),
71        PAIR_ATTR *sizep        __attribute__((__unused__)),
72        int  *dirtyp       __attribute__((__unused__)),
73        void *extraargs    __attribute__((__unused__))
74        ) {
75 
76     if(!expect_pf) {
77         sleep(2);
78     }
79     *value = 0;
80     *sizep = make_pair_attr(2);
81     *dirtyp = 0;
82 
83     return 0;
84 }
85 
pf_req_callback(void * UU (ftnode_pv),void * UU (read_extraargs))86 static bool pf_req_callback(void* UU(ftnode_pv), void* UU(read_extraargs)) {
87     if (do_pf) {
88         assert(expect_pf);
89         return true;
90     }
91     else {
92         return false;
93     }
94 }
95 
pf_callback(void * UU (ftnode_pv),void * UU (dd),void * UU (read_extraargs),int UU (fd),PAIR_ATTR * UU (sizep))96 static int pf_callback(void* UU(ftnode_pv), void* UU(dd), void* UU(read_extraargs), int UU(fd), PAIR_ATTR* UU(sizep)) {
97     assert(expect_pf);
98     sleep(2);
99     *sizep = make_pair_attr(2);
100     return 0;
101 }
102 
tdelta_usec(struct timeval * tend,struct timeval * tstart)103 static uint64_t tdelta_usec(struct timeval *tend, struct timeval *tstart) {
104     uint64_t t = tend->tv_sec * 1000000 + tend->tv_usec;
105     t -= tstart->tv_sec * 1000000 + tstart->tv_usec;
106     return t;
107 }
108 
cachetable_prefetch_maybegetandpin_test(bool do_partial_fetch)109 static void cachetable_prefetch_maybegetandpin_test (bool do_partial_fetch) {
110     const int test_limit = 2;
111     int r;
112     CACHETABLE ct;
113     toku_cachetable_create(&ct, test_limit, ZERO_LSN, nullptr);
114     const char *fname1 = TOKU_TEST_FILENAME;
115     unlink(fname1);
116     CACHEFILE f1;
117     r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO); assert(r == 0);
118     expect_pf = false;
119     do_pf = false;
120     CACHEKEY key = make_blocknum(0);
121     uint32_t fullhash = toku_cachetable_hash(f1, make_blocknum(0));
122     CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
123     wc.flush_callback = flush;
124     if (do_partial_fetch) {
125         expect_pf = true;
126         void* value;
127         r = toku_cachetable_get_and_pin(
128             f1,
129             key,
130             fullhash,
131             &value,
132             wc,
133             fetch,
134             pf_req_callback,
135             pf_callback,
136             true,
137             0
138             );
139         assert(r==0);
140         r = toku_test_cachetable_unpin(f1, key, fullhash, CACHETABLE_CLEAN, make_pair_attr(1));
141     }
142 
143     struct timeval tstart;
144     gettimeofday(&tstart, NULL);
145 
146     // prefetch block 0. this will take 2 seconds.
147     do_pf = true;
148     r = toku_cachefile_prefetch(f1, key, fullhash, wc, fetch, pf_req_callback, pf_callback, 0, NULL);
149     toku_cachetable_verify(ct);
150 
151     // verify that get_and_pin waits while the prefetch is in progress
152     void *v = 0;
153     do_pf = false;
154     r = toku_cachetable_get_and_pin_nonblocking(f1, key, fullhash, &v, wc, fetch, pf_req_callback, pf_callback, PL_WRITE_EXPENSIVE, NULL, NULL);
155     assert(r==TOKUDB_TRY_AGAIN);
156     r = toku_cachetable_get_and_pin(f1, key, fullhash, &v, wc, fetch, pf_req_callback, pf_callback, true, NULL);
157     assert(r == 0 && v == 0);
158     PAIR_ATTR attr;
159     r = toku_cachetable_get_attr(f1, key, fullhash, &attr);
160     assert(r == 0 && attr.size == 2);
161 
162     struct timeval tend;
163     gettimeofday(&tend, NULL);
164 
165     assert(tdelta_usec(&tend, &tstart) >= 1900000);
166 
167     toku_cachetable_verify(ct);
168 
169     r = toku_test_cachetable_unpin(f1, key, fullhash, CACHETABLE_CLEAN, make_pair_attr(1));
170     assert(r == 0);
171     toku_cachetable_verify(ct);
172 
173     toku_cachefile_close(&f1, false, ZERO_LSN);
174     toku_cachetable_close(&ct);
175 }
176 
177 int
test_main(int argc,const char * argv[])178 test_main(int argc, const char *argv[]) {
179     default_parse_args(argc, argv);
180     cachetable_prefetch_maybegetandpin_test(true);
181     cachetable_prefetch_maybegetandpin_test(false);
182     return 0;
183 }
184