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