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 the cache table checkpoint with prefetched blocks active works.
40 // the blocks in the reading state should be ignored.
41
42 #include "test.h"
43 #include <stdio.h>
44 #include <unistd.h>
45 #include "cachetable-test.h"
46
47 #include "cachetable/checkpoint.h"
48
49 const int item_size = 1;
50
51 int n_flush, n_write_me, n_keep_me, n_fetch;
52
flush(CACHEFILE UU (cf),int UU (fd),CACHEKEY UU (key),void * UU (value),void ** UU (dd),void * UU (extraargs),PAIR_ATTR size,PAIR_ATTR * UU (new_size),bool write_me,bool keep_me,bool UU (for_checkpoint),bool UU (is_clone))53 static void flush(
54 CACHEFILE UU(cf),
55 int UU(fd),
56 CACHEKEY UU(key),
57 void *UU(value),
58 void** UU(dd),
59 void *UU(extraargs),
60 PAIR_ATTR size,
61 PAIR_ATTR* UU(new_size),
62 bool write_me,
63 bool keep_me,
64 bool UU(for_checkpoint),
65 bool UU(is_clone)
66 )
67 {
68 // assert(key == make_blocknum((long)value));
69 assert(size.size == item_size);
70 n_flush++;
71 if (write_me) n_write_me++;
72 if (keep_me) n_keep_me++;
73 }
74
fetch(CACHEFILE UU (cf),PAIR UU (p),int UU (fd),CACHEKEY UU (key),uint32_t UU (fullhash),void ** UU (value),void ** UU (dd),PAIR_ATTR * UU (sizep),int * dirtyp,void * UU (extraargs))75 static int fetch(
76 CACHEFILE UU(cf),
77 PAIR UU(p),
78 int UU(fd),
79 CACHEKEY UU(key),
80 uint32_t UU(fullhash),
81 void **UU(value),
82 void** UU(dd),
83 PAIR_ATTR *UU(sizep),
84 int *dirtyp,
85 void *UU(extraargs)
86 )
87 {
88 n_fetch++;
89 sleep(10);
90 *value = 0;
91 *sizep = make_pair_attr(item_size);
92 *dirtyp = 0;
93 return 0;
94 }
95
96 // put n items into the cachetable, maybe mark them dirty, do a checkpoint, and
97 // verify that all of the items have been written and are clean.
cachetable_prefetch_checkpoint_test(int n,enum cachetable_dirty dirty)98 static void cachetable_prefetch_checkpoint_test(int n, enum cachetable_dirty dirty) {
99 if (verbose) printf("%s:%d n=%d dirty=%d\n", __FUNCTION__, __LINE__, n, (int) dirty);
100 const int test_limit = n;
101 int r;
102 CACHETABLE ct;
103 CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
104 wc.flush_callback = flush;
105 toku_cachetable_create(&ct, test_limit, ZERO_LSN, nullptr);
106 const char *fname1 = TOKU_TEST_FILENAME;
107 unlink(fname1);
108 CACHEFILE f1;
109 r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO); assert(r == 0);
110 create_dummy_functions(f1);
111
112 // disable the eviction thread. this thread was written to assume
113 // evictions hapepn on the client thread, which is no longer true.
114 evictor_test_helpers::disable_ev_thread(&ct->ev);
115
116 // prefetch block n+1. this will take 10 seconds.
117 {
118 CACHEKEY key = make_blocknum(n+1);
119 uint32_t fullhash = toku_cachetable_hash(f1, key);
120 r = toku_cachefile_prefetch(f1, key, fullhash, wc, fetch, def_pf_req_callback, def_pf_callback, 0, NULL);
121 toku_cachetable_verify(ct);
122 }
123
124 // insert items into the cachetable. all should be dirty
125 int i;
126 for (i=0; i<n; i++) {
127 CACHEKEY key = make_blocknum(i);
128 uint32_t hi = toku_cachetable_hash(f1, key);
129 toku_cachetable_put(f1, key, hi, (void *)(long)i, make_pair_attr(1), wc, put_callback_nop);
130
131 r = toku_test_cachetable_unpin(f1, key, hi, dirty, make_pair_attr(item_size));
132 assert(r == 0);
133
134 void *v;
135 int its_dirty;
136 long long its_pin;
137 long its_size;
138 r = toku_cachetable_get_key_state(ct, key, f1, &v, &its_dirty, &its_pin, &its_size);
139 if (r != 0)
140 continue;
141 assert(its_dirty == CACHETABLE_DIRTY);
142 assert(its_pin == 0);
143 assert(its_size == item_size);
144 }
145
146 // the checkpoint should cause n writes, but since n <= the cachetable size,
147 // all items should be kept in the cachetable
148 n_flush = n_write_me = n_keep_me = n_fetch = 0;
149 CHECKPOINTER cp = toku_cachetable_get_checkpointer(ct);
150 r = toku_checkpoint(cp, NULL, NULL, NULL, NULL, NULL, CLIENT_CHECKPOINT);
151 assert(r == 0);
152 assert(n_flush == n && n_write_me == n && n_keep_me == n);
153
154 // after the checkpoint, all of the items should be clean
155 for (i=0; i<n; i++) {
156 CACHEKEY key = make_blocknum(i);
157 uint32_t hi = toku_cachetable_hash(f1, key);
158 void *v;
159 r = toku_cachetable_maybe_get_and_pin(f1, key, hi, PL_WRITE_EXPENSIVE, &v);
160 if (r != 0)
161 continue;
162 r = toku_test_cachetable_unpin(f1, key, hi, CACHETABLE_CLEAN, make_pair_attr(item_size));
163 assert(r == 0);
164
165 int its_dirty;
166 long long its_pin;
167 long its_size;
168 r = toku_cachetable_get_key_state(ct, key, f1, &v, &its_dirty, &its_pin, &its_size);
169 if (r != 0)
170 continue;
171 assert(its_dirty == CACHETABLE_CLEAN);
172 assert(its_pin == 0);
173 assert(its_size == item_size);
174 }
175
176 // a subsequent checkpoint should cause no flushes, or writes since all of the items are clean
177 n_flush = n_write_me = n_keep_me = n_fetch = 0;
178
179 r = toku_checkpoint(cp, NULL, NULL, NULL, NULL, NULL, CLIENT_CHECKPOINT);
180 assert(r == 0);
181 assert(n_flush == 0 && n_write_me == 0 && n_keep_me == 0);
182
183 toku_cachefile_close(&f1, false, ZERO_LSN);
184 toku_cachetable_close(&ct);
185 }
186
187 int
test_main(int argc,const char * argv[])188 test_main(int argc, const char *argv[]) {
189 int i;
190 for (i=1; i<argc; i++) {
191 if (strcmp(argv[i], "-v") == 0) {
192 verbose++;
193 continue;
194 }
195 }
196 for (i=0; i<8; i++) {
197 cachetable_prefetch_checkpoint_test(i, CACHETABLE_CLEAN);
198 cachetable_prefetch_checkpoint_test(i, CACHETABLE_DIRTY);
199 }
200 return 0;
201 }
202