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