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     if (pf_called || fetch_called) return false;
67     return true;
68   return true;
69 }
70 
sleep_pf_callback(void * UU (ftnode_pv),void * UU (disk_data),void * UU (read_extraargs),int UU (fd),PAIR_ATTR * sizep)71 static int sleep_pf_callback(void* UU(ftnode_pv), void* UU(disk_data), void* UU(read_extraargs), int UU(fd), PAIR_ATTR* sizep) {
72    sleep(2);
73   *sizep = make_pair_attr(8);
74   pf_called = true;
75   return 0;
76 }
77 
run_expensive_pf(void * arg)78 static void *run_expensive_pf(void *arg) {
79     void* v1;
80     CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
81     pf_called = false;
82     fetch_called = false;
83     int r = toku_cachetable_get_and_pin(f1, make_blocknum(1), 1, &v1, wc, sleep_fetch, sleep_pf_req_callback, sleep_pf_callback, false, NULL);
84     assert_zero(r);
85     assert(pf_called);
86     return arg;
87 }
88 
run_expensive_fetch(void * arg)89 static void *run_expensive_fetch(void *arg) {
90     void* v1;
91     CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
92     pf_called = false;
93     fetch_called = false;
94     int r = toku_cachetable_get_and_pin(f1, make_blocknum(1), 1, &v1, wc, sleep_fetch, sleep_pf_req_callback, sleep_pf_callback, false, NULL);
95     assert_zero(r);
96     assert(fetch_called);
97     return arg;
98 }
99 
100 
101 static void
run_test(void)102 run_test (void) {
103     const int test_limit = 12;
104     int r;
105     void *ret;
106     CACHETABLE ct;
107     toku_cachetable_create(&ct, test_limit, ZERO_LSN, nullptr);
108     const char *fname1 = TOKU_TEST_FILENAME;
109     unlink(fname1);
110     r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO); assert(r == 0);
111 
112     void* v1;
113     CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
114 
115     toku_pthread_t fetch_tid;
116     fetch_called = false;
117     r = toku_pthread_create(
118         toku_uninstrumented, &fetch_tid, nullptr, run_expensive_fetch, nullptr);
119     sleep(1);
120     r = toku_cachetable_get_and_pin(f1,
121                                     make_blocknum(1),
122                                     1,
123                                     &v1,
124                                     wc,
125                                     sleep_fetch,
126                                     def_pf_req_callback,
127                                     def_pf_callback,
128                                     false,
129                                     NULL);
130     assert_zero(r);
131     assert(fetch_called);
132     r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_CLEAN, make_pair_attr(8));
133     assert(r==0);
134     r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_CLEAN, make_pair_attr(8));
135     assert(r==0);
136     r = toku_pthread_join(fetch_tid, &ret);
137     assert_zero(r);
138 
139     // call with may_modify_node = false twice, make sure we can get it
140     r = toku_cachetable_get_and_pin(f1, make_blocknum(1), 1, &v1, wc, sleep_fetch, def_pf_req_callback, def_pf_callback, false, NULL);
141     assert_zero(r);
142     r = toku_cachetable_get_and_pin(f1, make_blocknum(1), 1, &v1, wc, sleep_fetch, def_pf_req_callback, def_pf_callback, false, NULL);
143     assert_zero(r);
144     r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_CLEAN, make_pair_attr(8));
145     assert(r==0);
146     r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_CLEAN, make_pair_attr(8));
147     assert(r==0);
148 
149     toku_pthread_t pf_tid;
150     pf_called = false;
151     r = toku_pthread_create(
152         toku_uninstrumented, &pf_tid, nullptr, run_expensive_pf, nullptr);
153     sleep(1);
154     r = toku_cachetable_get_and_pin(f1,
155                                     make_blocknum(1),
156                                     1,
157                                     &v1,
158                                     wc,
159                                     sleep_fetch,
160                                     def_pf_req_callback,
161                                     def_pf_callback,
162                                     false,
163                                     NULL);
164     assert_zero(r);
165     assert(pf_called);
166     r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_CLEAN, make_pair_attr(8));
167     assert(r==0);
168     r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_CLEAN, make_pair_attr(8));
169     assert(r==0);
170 
171     r = toku_pthread_join(pf_tid, &ret);
172     assert_zero(r);
173 
174     toku_cachetable_verify(ct);
175     toku_cachefile_close(&f1, false, ZERO_LSN);
176     toku_cachetable_close(&ct);
177 }
178 
179 int
test_main(int argc,const char * argv[])180 test_main(int argc, const char *argv[]) {
181   default_parse_args(argc, argv);
182   run_test();
183   return 0;
184 }
185