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 TokuDB 6 7 8 Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved. 9 10 TokuDBis 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 TokuDB 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 TokuDB. If not, see <http://www.gnu.org/licenses/>. 21 22 ======= */ 23 24 #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved." 25 26 namespace tokudb { compute_total_key_parts(TABLE_SHARE * table_share)27 uint compute_total_key_parts(TABLE_SHARE *table_share) { 28 uint total_key_parts = 0; 29 for (uint i = 0; i < table_share->keys; i++) { 30 total_key_parts += table_share->key_info[i].user_defined_key_parts; 31 } 32 return total_key_parts; 33 } 34 35 // Put the cardinality counters into the status dictionary. set_card_in_status(DB * status_db,DB_TXN * txn,uint rec_per_keys,const uint64_t rec_per_key[])36 int set_card_in_status( 37 DB* status_db, 38 DB_TXN* txn, 39 uint rec_per_keys, 40 const uint64_t rec_per_key[]) { 41 42 // encode cardinality into the buffer 43 tokudb::buffer b; 44 size_t s; 45 s = b.append_ui<uint32_t>(rec_per_keys); 46 assert_always(s > 0); 47 for (uint i = 0; i < rec_per_keys; i++) { 48 s = b.append_ui<uint64_t>(rec_per_key[i]); 49 assert_always(s > 0); 50 } 51 // write cardinality to status 52 int error = 53 tokudb::metadata::write( 54 status_db, 55 hatoku_cardinality, 56 b.data(), 57 b.size(), 58 txn); 59 return error; 60 } 61 62 // Get the cardinality counters from the status dictionary. get_card_from_status(DB * status_db,DB_TXN * txn,uint rec_per_keys,uint64_t rec_per_key[])63 int get_card_from_status( 64 DB* status_db, 65 DB_TXN* txn, 66 uint rec_per_keys, 67 uint64_t rec_per_key[]) { 68 69 // read cardinality from status 70 void* buf = 0; size_t buf_size = 0; 71 int error = 72 tokudb::metadata::read_realloc( 73 status_db, 74 txn, 75 hatoku_cardinality, 76 &buf, 77 &buf_size); 78 if (error == 0) { 79 // decode cardinality from the buffer 80 tokudb::buffer b(buf, 0, buf_size); 81 size_t s; 82 uint32_t num_parts; 83 s = b.consume_ui<uint32_t>(&num_parts); 84 if (s == 0 || num_parts != rec_per_keys) 85 error = EINVAL; 86 if (error == 0) { 87 for (uint i = 0; i < rec_per_keys; i++) { 88 s = b.consume_ui<uint64_t>(&rec_per_key[i]); 89 if (s == 0) { 90 error = EINVAL; 91 break; 92 } 93 } 94 } 95 } 96 // cleanup 97 free(buf); 98 return error; 99 } 100 101 // Delete the cardinality counters from the status dictionary. delete_card_from_status(DB * status_db,DB_TXN * txn)102 int delete_card_from_status(DB* status_db, DB_TXN* txn) { 103 int error = 104 tokudb::metadata::remove(status_db, hatoku_cardinality, txn); 105 return error; 106 } 107 find_index_of_key(const char * key_name,TABLE_SHARE * table_share,uint * index_offset_ptr)108 bool find_index_of_key( 109 const char* key_name, 110 TABLE_SHARE* table_share, 111 uint* index_offset_ptr) { 112 113 for (uint i = 0; i < table_share->keys; i++) { 114 if (strcmp(key_name, table_share->key_info[i].name.str) == 0) { 115 *index_offset_ptr = i; 116 return true; 117 } 118 } 119 return false; 120 } 121 copy_card(uint64_t * dest,uint64_t * src,size_t n)122 static void copy_card(uint64_t *dest, uint64_t *src, size_t n) { 123 for (size_t i = 0; i < n; i++) 124 dest[i] = src[i]; 125 } 126 127 // Altered table cardinality = select cardinality data from current table 128 // cardinality for keys that exist 129 // in the altered table and the current table. alter_card(DB * status_db,DB_TXN * txn,TABLE_SHARE * table_share,TABLE_SHARE * altered_table_share)130 int alter_card( 131 DB* status_db, 132 DB_TXN *txn, 133 TABLE_SHARE* table_share, 134 TABLE_SHARE* altered_table_share) { 135 136 int error; 137 // read existing cardinality data from status 138 uint table_total_key_parts = 139 tokudb::compute_total_key_parts(table_share); 140 141 uint64_t rec_per_key[table_total_key_parts]; 142 error = 143 get_card_from_status( 144 status_db, 145 txn, 146 table_total_key_parts, 147 rec_per_key); 148 // set altered records per key to unknown 149 uint altered_table_total_key_parts = 150 tokudb::compute_total_key_parts(altered_table_share); 151 uint64_t altered_rec_per_key[altered_table_total_key_parts]; 152 for (uint i = 0; i < altered_table_total_key_parts; i++) 153 altered_rec_per_key[i] = 0; 154 // compute the beginning of the key offsets in the original table 155 uint orig_key_offset[table_share->keys]; 156 uint orig_key_parts = 0; 157 for (uint i = 0; i < table_share->keys; i++) { 158 orig_key_offset[i] = orig_key_parts; 159 orig_key_parts += table_share->key_info[i].user_defined_key_parts; 160 } 161 // if orig card data exists, then use it to compute new card data 162 if (error == 0) { 163 uint next_key_parts = 0; 164 for (uint i = 0; error == 0 && i < altered_table_share->keys; i++) { 165 uint ith_key_parts = 166 altered_table_share->key_info[i].user_defined_key_parts; 167 uint orig_key_index; 168 if (find_index_of_key( 169 altered_table_share->key_info[i].name.str, 170 table_share, 171 &orig_key_index)) { 172 copy_card( 173 &altered_rec_per_key[next_key_parts], 174 &rec_per_key[orig_key_offset[orig_key_index]], 175 ith_key_parts); 176 } 177 next_key_parts += ith_key_parts; 178 } 179 } 180 if (error == 0) { 181 error = 182 set_card_in_status( 183 status_db, 184 txn, 185 altered_table_total_key_parts, 186 altered_rec_per_key); 187 } else { 188 error = delete_card_from_status(status_db, txn); 189 } 190 return error; 191 } 192 } 193