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_sleep;
44 
45 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))46 flush (CACHEFILE f __attribute__((__unused__)),
47        int UU(fd),
48        CACHEKEY k  __attribute__((__unused__)),
49        void *v     __attribute__((__unused__)),
50        void** UU(dd),
51        void *e     __attribute__((__unused__)),
52        PAIR_ATTR s      __attribute__((__unused__)),
53        PAIR_ATTR* new_size      __attribute__((__unused__)),
54        bool w      __attribute__((__unused__)),
55        bool keep   __attribute__((__unused__)),
56        bool c      __attribute__((__unused__)),
57         bool UU(is_clone)
58        ) {
59     if (do_sleep) {
60         sleep(3);
61     }
62 }
63 
tdelta_usec(struct timeval * tend,struct timeval * tstart)64 static uint64_t tdelta_usec(struct timeval *tend, struct timeval *tstart) {
65     uint64_t t = tend->tv_sec * 1000000 + tend->tv_usec;
66     t -= tstart->tv_sec * 1000000 + tstart->tv_usec;
67     return t;
68 }
69 
cachetable_predef_fetch_maybegetandpin_test(void)70 static void cachetable_predef_fetch_maybegetandpin_test (void) {
71     const int test_limit = 12;
72     int r;
73     CACHETABLE ct;
74     toku_cachetable_create(&ct, test_limit, ZERO_LSN, nullptr);
75     evictor_test_helpers::disable_ev_thread(&ct->ev);
76     const char *fname1 = TOKU_TEST_FILENAME;
77     unlink(fname1);
78     CACHEFILE f1;
79     r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO); assert(r == 0);
80     CACHEKEY key = make_blocknum(0);
81     uint32_t fullhash = toku_cachetable_hash(f1, make_blocknum(0));
82 
83     // let's get and pin this node a bunch of times to drive up the clock count
84     for (int i = 0; i < 20; i++) {
85         void* value;
86         CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
87         wc.flush_callback = flush;
88         r = toku_cachetable_get_and_pin(
89             f1,
90             key,
91             fullhash,
92             &value,
93             wc,
94             def_fetch,
95             def_pf_req_callback,
96             def_pf_callback,
97             true,
98             0
99             );
100         assert(r==0);
101         r = toku_test_cachetable_unpin(f1, key, fullhash, CACHETABLE_DIRTY, make_pair_attr(8));
102     }
103 
104     struct timeval tstart;
105     gettimeofday(&tstart, NULL);
106 
107     // def_fetch another block, causing an eviction of the first block we made above
108     do_sleep = true;
109     void* value2;
110     CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
111     r = toku_cachetable_get_and_pin(
112         f1,
113         make_blocknum(1),
114         1,
115         &value2,
116         wc,
117         def_fetch,
118         def_pf_req_callback,
119         def_pf_callback,
120         true,
121         0
122         );
123     assert(r==0);
124     ct->ev.signal_eviction_thread();
125     usleep(1*1024*1024);
126     r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_CLEAN, make_pair_attr(8));
127     toku_cachetable_verify(ct);
128 
129     void *v = 0;
130     // now verify that the block we are trying to evict is gone
131     wc = def_write_callback(NULL);
132     wc.flush_callback = flush;
133     r = toku_cachetable_get_and_pin_nonblocking(f1, key, fullhash, &v, wc, def_fetch, def_pf_req_callback, def_pf_callback, PL_WRITE_EXPENSIVE, NULL, NULL);
134     assert(r == TOKUDB_TRY_AGAIN);
135     r = toku_cachetable_get_and_pin(f1, key, fullhash, &v, wc, def_fetch, def_pf_req_callback, def_pf_callback, true, NULL);
136     assert(r == 0 && v == 0);
137     PAIR_ATTR attr;
138     r = toku_cachetable_get_attr(f1, key, fullhash, &attr);
139     assert(r == 0 && attr.size == 8);
140     do_sleep = false;
141 
142     struct timeval tend;
143     gettimeofday(&tend, NULL);
144 
145     assert(tdelta_usec(&tend, &tstart) >= 2000000);
146     if (verbose)printf("time %" PRIu64 " \n", tdelta_usec(&tend, &tstart));
147     toku_cachetable_verify(ct);
148 
149     r = toku_test_cachetable_unpin(f1, key, fullhash, CACHETABLE_CLEAN, make_pair_attr(1));
150     assert(r == 0);
151     toku_cachetable_verify(ct);
152 
153     toku_cachefile_close(&f1, false, ZERO_LSN);
154     toku_cachetable_close(&ct);
155 }
156 
157 int
test_main(int argc,const char * argv[])158 test_main(int argc, const char *argv[]) {
159     default_parse_args(argc, argv);
160     cachetable_predef_fetch_maybegetandpin_test();
161     return 0;
162 }
163