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 #include "test.h"
40 
41 bool pf_called;
42 bool fetch_called;
43 CACHEFILE f1;
44 
45 static int
sleep_fetch(CACHEFILE f,PAIR UU (p),int UU (fd),CACHEKEY k,uint32_t fullhash,void ** value,void ** dd,PAIR_ATTR * sizep,int * dirtyp,void * extraargs)46 sleep_fetch (CACHEFILE f        __attribute__((__unused__)),
47        PAIR UU(p),
48        int UU(fd),
49        CACHEKEY k         __attribute__((__unused__)),
50        uint32_t fullhash __attribute__((__unused__)),
51        void **value       __attribute__((__unused__)),
52        void **dd     __attribute__((__unused__)),
53        PAIR_ATTR *sizep        __attribute__((__unused__)),
54        int  *dirtyp,
55        void *extraargs    __attribute__((__unused__))
56        ) {
57     sleep(2);
58     *dirtyp = 0;
59     *value = NULL;
60     *sizep = make_pair_attr(8);
61     fetch_called = true;
62     return 0;
63 }
64 
sleep_pf_req_callback(void * UU (ftnode_pv),void * UU (read_extraargs))65 static bool sleep_pf_req_callback(void* UU(ftnode_pv), void* UU(read_extraargs)) {
66   return true;
67 }
68 
sleep_pf_callback(void * UU (ftnode_pv),void * UU (disk_data),void * UU (read_extraargs),int UU (fd),PAIR_ATTR * sizep)69 static int sleep_pf_callback(void* UU(ftnode_pv), void* UU(disk_data), void* UU(read_extraargs), int UU(fd), PAIR_ATTR* sizep) {
70    sleep(2);
71   *sizep = make_pair_attr(8);
72   pf_called = true;
73   return 0;
74 }
75 
run_expensive_pf(void * arg)76 static void *run_expensive_pf(void *arg) {
77     void* v1;
78     CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
79     int r = toku_cachetable_get_and_pin_nonblocking(f1, make_blocknum(1), 1, &v1, wc, sleep_fetch, sleep_pf_req_callback, sleep_pf_callback, PL_READ, NULL, NULL);
80     assert(r == TOKUDB_TRY_AGAIN);
81     assert(pf_called);
82     return arg;
83 }
84 
run_expensive_fetch(void * arg)85 static void *run_expensive_fetch(void *arg) {
86     void* v1;
87     CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
88     int r = toku_cachetable_get_and_pin_nonblocking(f1, make_blocknum(1), 1, &v1, wc, sleep_fetch, sleep_pf_req_callback, sleep_pf_callback, PL_READ, NULL, NULL);
89     assert(fetch_called);
90     assert(r == TOKUDB_TRY_AGAIN);
91     return arg;
92 }
93 
94 
95 static void
run_test(void)96 run_test (void) {
97     const int test_limit = 20;
98     int r;
99     void *ret;
100     CACHETABLE ct;
101     toku_cachetable_create(&ct, test_limit, ZERO_LSN, nullptr);
102     const char *fname1 = TOKU_TEST_FILENAME;
103     unlink(fname1);
104     r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO); assert(r == 0);
105 
106     void* v1;
107     CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
108 
109     toku_pthread_t fetch_tid;
110     fetch_called = false;
111     r = toku_pthread_create(
112         toku_uninstrumented, &fetch_tid, nullptr, run_expensive_fetch, nullptr);
113     sleep(1);
114     r = toku_cachetable_get_and_pin(f1,
115                                     make_blocknum(1),
116                                     1,
117                                     &v1,
118                                     wc,
119                                     sleep_fetch,
120                                     def_pf_req_callback,
121                                     def_pf_callback,
122                                     false,
123                                     NULL);
124     assert_zero(r);
125     assert(fetch_called);
126     r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_CLEAN, make_pair_attr(8));
127     assert(r==0);
128     r = toku_pthread_join(fetch_tid, &ret);
129     assert_zero(r);
130 
131     // call with may_modify_node = false twice, make sure we can get it
132     r = toku_cachetable_get_and_pin_nonblocking(f1, make_blocknum(1), 1, &v1, wc, sleep_fetch, def_pf_req_callback, def_pf_callback, PL_READ, NULL, NULL);
133     assert_zero(r);
134     r = toku_cachetable_get_and_pin_nonblocking(f1, make_blocknum(1), 1, &v1, wc, sleep_fetch, def_pf_req_callback, def_pf_callback, PL_READ, NULL, NULL);
135     assert_zero(r);
136     r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_CLEAN, make_pair_attr(8));
137     assert(r==0);
138     r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_CLEAN, make_pair_attr(8));
139     assert(r==0);
140 
141     toku_pthread_t pf_tid;
142     pf_called = false;
143     r = toku_pthread_create(
144         toku_uninstrumented, &pf_tid, nullptr, run_expensive_pf, nullptr);
145     sleep(1);
146     r = toku_cachetable_get_and_pin(f1,
147                                     make_blocknum(1),
148                                     1,
149                                     &v1,
150                                     wc,
151                                     sleep_fetch,
152                                     def_pf_req_callback,
153                                     def_pf_callback,
154                                     false,
155                                     NULL);
156     assert_zero(r);
157     assert(pf_called);
158     r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_CLEAN, make_pair_attr(8));
159     assert(r==0);
160 
161     r = toku_pthread_join(pf_tid, &ret);
162     assert_zero(r);
163 
164     toku_cachetable_verify(ct);
165     toku_cachefile_close(&f1, false, ZERO_LSN);
166     toku_cachetable_close(&ct);
167 }
168 
169 int
test_main(int argc,const char * argv[])170 test_main(int argc, const char *argv[]) {
171   default_parse_args(argc, argv);
172   run_test();
173   return 0;
174 }
175