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/*======
5This file is part of TokuDB
6
7
8Copyright (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
26namespace tokudb {
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.
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.
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.
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
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
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.
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