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 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 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 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 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 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