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 // test that an update broadcast called when there are previously deleted 40 // keys doesn't get a callback to update_fun on those keys 41 42 #include "test.h" 43 44 const int envflags = DB_INIT_MPOOL|DB_CREATE|DB_THREAD |DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_TXN|DB_PRIVATE; 45 46 DB_ENV *env; 47 48 const int to_delete[] = { 1, 1, 0, 0, 1, 0, 0, 0, 1, 0 }; 49 const int to_update[] = { 0, 1, 1, 1, 0, 0, 1, 0, 1, 0 }; 50 51 static inline unsigned int _v(const unsigned int i) { return 10 - i; } 52 static inline unsigned int _e(const unsigned int i) { return i + 4; } 53 static inline unsigned int _u(const unsigned int v, const unsigned int e) { return v * v * e; } 54 55 static int update_fun(DB *UU(db), 56 const DBT *key, 57 const DBT *old_val, const DBT *extra, 58 void (*set_val)(const DBT *new_val, 59 void *set_extra), 60 void *set_extra) { 61 unsigned int *k, *ov, v; 62 assert(key->size == sizeof(*k)); 63 CAST_FROM_VOIDP(k, key->data); 64 assert(extra->size == 0); 65 if (to_delete[*k]) { 66 assert(0); 67 } else { 68 assert(old_val->size == sizeof(*ov)); 69 CAST_FROM_VOIDP(ov, old_val->data); 70 v = _u(*ov, _e(*k)); 71 } 72 73 if (to_update[*k]) { 74 DBT newval; 75 set_val(dbt_init(&newval, &v, sizeof(v)), set_extra); 76 } 77 78 return 0; 79 } 80 81 static void setup (void) { 82 toku_os_recursive_delete(TOKU_TEST_FILENAME); 83 { int chk_r = toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(chk_r); } 84 { int chk_r = db_env_create(&env, 0); CKERR(chk_r); } 85 env->set_errfile(env, stderr); 86 env->set_update(env, update_fun); 87 { int chk_r = env->open(env, TOKU_TEST_FILENAME, envflags, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(chk_r); } 88 } 89 90 static void cleanup (void) { 91 { int chk_r = env->close(env, 0); CKERR(chk_r); } 92 } 93 94 static int do_inserts(DB_TXN *txn, DB *db) { 95 int r = 0; 96 DBT key, val; 97 unsigned int i, v; 98 DBT *keyp = dbt_init(&key, &i, sizeof(i)); 99 DBT *valp = dbt_init(&val, &v, sizeof(v)); 100 for (i = 0; i < (sizeof(to_update) / sizeof(to_update[0])); ++i) { 101 v = _v(i); 102 r = db->put(db, txn, keyp, valp, 0); CKERR(r); 103 } 104 return r; 105 } 106 107 static int do_deletes(DB_TXN *txn, DB *db) { 108 int r = 0; 109 DBT key; 110 unsigned int i; 111 DBT *keyp = dbt_init(&key, &i, sizeof(i)); 112 for (i = 0; i < (sizeof(to_delete) / sizeof(to_delete[0])); ++i) { 113 if (to_delete[i]) { 114 r = db->del(db, txn, keyp, DB_DELETE_ANY); CKERR(r); 115 } 116 } 117 return r; 118 } 119 120 static int do_updates(DB_TXN *txn, DB *db, uint32_t flags) { 121 DBT extra; 122 DBT *extrap = dbt_init(&extra, NULL, 0); 123 int r = db->update_broadcast(db, txn, extrap, flags); CKERR(r); 124 return r; 125 } 126 127 static void chk_updated(const unsigned int k, const unsigned int v) { 128 if (to_update[k]) { 129 assert(v == _u(_v(k), _e(k))); 130 } else { 131 assert(v == _v(k)); 132 } 133 } 134 135 static void chk_original(const unsigned int k, const unsigned int v) { 136 assert(v == _v(k)); 137 } 138 139 static int do_verify_results(DB_TXN *txn, DB *db, void (*check_val)(const unsigned int k, const unsigned int v)) { 140 int r = 0; 141 DBT key, val; 142 unsigned int i, *vp; 143 DBT *keyp = dbt_init(&key, &i, sizeof(i)); 144 DBT *valp = dbt_init(&val, NULL, 0); 145 for (i = 0; i < (sizeof(to_update) / sizeof(to_update[0])); ++i) { 146 r = db->get(db, txn, keyp, valp, 0); 147 if (to_delete[i]) { 148 CKERR2(r, DB_NOTFOUND); 149 r = 0; 150 } else { 151 CKERR(r); 152 assert(val.size == sizeof(*vp)); 153 CAST_FROM_VOIDP(vp, val.data); 154 check_val(i, *vp); 155 } 156 } 157 return r; 158 } 159 160 static void run_test(bool is_resetting) { 161 DB *db; 162 uint32_t update_flags = is_resetting ? DB_IS_RESETTING_OP : 0; 163 164 IN_TXN_COMMIT(env, NULL, txn_1, 0, { 165 { int chk_r = db_create(&db, env, 0); CKERR(chk_r); } 166 { int chk_r = db->open(db, txn_1, "foo.db", NULL, DB_BTREE, DB_CREATE, 0666); CKERR(chk_r); } 167 168 { int chk_r = do_inserts(txn_1, db); CKERR(chk_r); } 169 170 { int chk_r = do_deletes(txn_1, db); CKERR(chk_r); } 171 172 IN_TXN_COMMIT(env, txn_1, txn_11, 0, { 173 { int chk_r = do_verify_results(txn_11, db, chk_original); CKERR(chk_r); } 174 }); 175 }); 176 177 IN_TXN_COMMIT(env, NULL, txn_2, 0, { 178 { int chk_r = do_updates(txn_2, db, update_flags); CKERR(chk_r); } 179 }); 180 181 IN_TXN_COMMIT(env, NULL, txn_3, 0, { 182 { int chk_r = do_verify_results(txn_3, db, chk_updated); CKERR(chk_r); } 183 }); 184 185 { int chk_r = db->close(db, 0); CKERR(chk_r); } 186 } 187 188 int test_main(int argc, char * const argv[]) { 189 parse_args(argc, argv); 190 setup(); 191 run_test(true); 192 run_test(false); 193 cleanup(); 194 195 return 0; 196 } 197