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