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
42 bool clone_called;
43 bool check_flush;
44 bool flush_expected;
45 bool flush_called;
46
47 static void
clone_callback(void * UU (value_data),void ** cloned_value_data,long * clone_size,PAIR_ATTR * new_attr,bool UU (for_checkpoint),void * UU (write_extraargs))48 clone_callback(void* UU(value_data), void** cloned_value_data, long* clone_size, PAIR_ATTR* new_attr, bool UU(for_checkpoint), void* UU(write_extraargs))
49 {
50 *cloned_value_data = (void *)1;
51 new_attr->is_valid = false;
52 clone_called = true;
53 *clone_size = 8;
54 }
55
56 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))57 flush (
58 CACHEFILE f __attribute__((__unused__)),
59 int UU(fd),
60 CACHEKEY k __attribute__((__unused__)),
61 void *v __attribute__((__unused__)),
62 void** UU(dd),
63 void *e __attribute__((__unused__)),
64 PAIR_ATTR s __attribute__((__unused__)),
65 PAIR_ATTR* new_size __attribute__((__unused__)),
66 bool w __attribute__((__unused__)),
67 bool keep __attribute__((__unused__)),
68 bool c __attribute__((__unused__)),
69 bool UU(is_clone)
70 )
71 {
72 if (w) usleep(5*1024*1024);
73 if (w && check_flush) {
74 assert(flush_expected);
75 if (clone_called) assert(is_clone);
76 }
77 flush_called = true;
78 if (is_clone) assert(!keep);
79 }
80
tdelta_usec(struct timeval * tend,struct timeval * tstart)81 static uint64_t tdelta_usec(struct timeval *tend, struct timeval *tstart) {
82 uint64_t t = tend->tv_sec * 1000000 + tend->tv_usec;
83 t -= tstart->tv_sec * 1000000 + tstart->tv_usec;
84 return t;
85 }
86
87
88 //
89 // test the following things for simple cloning:
90 // - if the pending pair is clean, nothing gets written
91 // - if the pending pair is dirty and cloneable, then pair is written
92 // in background and get_and_pin returns immedietely
93 // - if the pending pair is dirty and not cloneable, then get_and_pin
94 // blocks until the pair is written out
95 //
96 static void
test_clean(enum cachetable_dirty dirty,bool cloneable)97 test_clean (enum cachetable_dirty dirty, bool cloneable) {
98 const int test_limit = 12;
99 int r;
100 CACHETABLE ct;
101 toku_cachetable_create(&ct, test_limit, ZERO_LSN, nullptr);
102 const char *fname1 = TOKU_TEST_FILENAME;
103 unlink(fname1);
104 CACHEFILE f1;
105 r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO); assert(r == 0);
106 create_dummy_functions(f1);
107
108 void* v1;
109 CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
110 wc.clone_callback = cloneable ? clone_callback : NULL;
111 wc.flush_callback = flush;
112 r = toku_cachetable_get_and_pin(f1, make_blocknum(1), 1, &v1, wc, def_fetch, def_pf_req_callback, def_pf_callback, true, NULL);
113 r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, dirty, make_pair_attr(8));
114
115 check_flush = true;
116 clone_called = false;
117 flush_expected = (dirty == CACHETABLE_DIRTY) ? true : false;
118 flush_called = false;
119 // begin checkpoint, since pair is clean, we should not
120 // have the clone called
121 CHECKPOINTER cp = toku_cachetable_get_checkpointer(ct);
122 toku_cachetable_begin_checkpoint(cp, NULL);
123 assert_zero(r);
124 struct timeval tstart;
125 struct timeval tend;
126 gettimeofday(&tstart, NULL);
127
128 // test that having a pin that passes false for may_modify_value does not stall behind checkpoint
129 r = toku_cachetable_get_and_pin(f1, make_blocknum(1), 1, &v1, wc, def_fetch, def_pf_req_callback, def_pf_callback, false, NULL);
130 r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_CLEAN, make_pair_attr(8));
131 gettimeofday(&tend, NULL);
132 assert(tdelta_usec(&tend, &tstart) <= 2000000);
133 assert(!clone_called);
134
135 r = toku_cachetable_get_and_pin(f1, make_blocknum(1), 1, &v1, wc, def_fetch, def_pf_req_callback, def_pf_callback, true, NULL);
136 gettimeofday(&tend, NULL);
137
138 // we take 5 seconds for a write
139 // we check if time to pin is less than 2 seconds, if it is
140 // then we know act of cloning worked properly
141 if (cloneable || !dirty ) {
142 assert(tdelta_usec(&tend, &tstart) <= 2000000);
143 }
144 else {
145 assert(tdelta_usec(&tend, &tstart) >= 2000000);
146 }
147
148
149 if (dirty == CACHETABLE_DIRTY && cloneable) {
150 assert(clone_called);
151 }
152 else {
153 assert(!clone_called);
154 }
155
156 // at this point, there should be no more dirty writes
157 r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_CLEAN, make_pair_attr(8));
158 gettimeofday(&tend, NULL);
159 if (cloneable || !dirty ) {
160 assert(tdelta_usec(&tend, &tstart) <= 2000000);
161 }
162 else {
163 assert(tdelta_usec(&tend, &tstart) >= 2000000);
164 }
165
166 toku_cachetable_end_checkpoint(
167 cp,
168 NULL,
169 NULL,
170 NULL
171 );
172
173 check_flush = false;
174
175 toku_cachetable_verify(ct);
176 toku_cachefile_close(&f1, false, ZERO_LSN);
177 toku_cachetable_close(&ct);
178 }
179
180 int
test_main(int argc,const char * argv[])181 test_main(int argc, const char *argv[]) {
182 default_parse_args(argc, argv);
183 test_clean(CACHETABLE_CLEAN, true);
184 test_clean(CACHETABLE_DIRTY, true);
185 test_clean(CACHETABLE_CLEAN, false);
186 test_clean(CACHETABLE_DIRTY, false);
187 return 0;
188 }
189