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