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 #ifndef _TOKUDB_STATUS_H
27 #define _TOKUDB_STATUS_H
28
29 // These are keys that will be used for retrieving metadata in status.tokudb
30 // To get the version, one looks up the value associated with key hatoku_version
31 // in status.tokudb
32 typedef ulonglong HA_METADATA_KEY;
33 #define hatoku_old_version 0
34 #define hatoku_capabilities 1
35 #define hatoku_max_ai 2 //maximum auto increment value found so far
36 #define hatoku_ai_create_value 3
37 #define hatoku_key_name 4
38 #define hatoku_frm_data 5
39 #define hatoku_new_version 6
40 #define hatoku_cardinality 7
41
42 // use a very small pagesize for the status dictionary
43 #define status_dict_pagesize 1024
44
45 namespace tokudb {
46 namespace metadata {
47
48 // get the value for a given key in the status dictionary.
49 // copy the value to the supplied buffer.
50 // returns 0 if successful.
read(DB * status_db,DB_TXN * txn,HA_METADATA_KEY k,void * p,size_t s,size_t * sp)51 int read(
52 DB* status_db,
53 DB_TXN* txn,
54 HA_METADATA_KEY k,
55 void* p,
56 size_t s,
57 size_t* sp) {
58
59 DBT key = {};
60 key.data = &k;
61 key.size = sizeof(k);
62 DBT val = {};
63 val.data = p;
64 val.ulen = (uint32_t)s;
65 val.flags = DB_DBT_USERMEM;
66 int error = status_db->get(status_db, txn, &key, &val, 0);
67 if (error == 0) {
68 *sp = val.size;
69 }
70 return error;
71 }
72
73 // get the value for a given key in the status dictionary.
74 // put the value in a realloced buffer.
75 // returns 0 if successful.
read_realloc(DB * status_db,DB_TXN * txn,HA_METADATA_KEY k,void ** pp,size_t * sp)76 int read_realloc(
77 DB* status_db,
78 DB_TXN* txn,
79 HA_METADATA_KEY k,
80 void** pp,
81 size_t* sp) {
82
83 DBT key = {};
84 key.data = &k;
85 key.size = sizeof(k);
86 DBT val = {};
87 val.data = *pp;
88 val.size = (uint32_t)*sp;
89 val.flags = DB_DBT_REALLOC;
90 int error = status_db->get(status_db, txn, &key, &val, 0);
91 if (error == 0) {
92 *pp = val.data;
93 *sp = val.size;
94 }
95 return error;
96 }
97
98 // write a key value pair into the status dictionary,
99 // overwriting the previous value if any.
100 // auto create a txn if necessary.
101 // returns 0 if successful.
write_low(DB * status_db,void * key_data,uint key_size,void * val_data,uint val_size,DB_TXN * txn)102 int write_low(
103 DB* status_db,
104 void* key_data,
105 uint key_size,
106 void* val_data,
107 uint val_size,
108 DB_TXN *txn) {
109
110 DBT key = {};
111 key.data = key_data;
112 key.size = key_size;
113 DBT value = {};
114 value.data = val_data;
115 value.size = val_size;
116 int error = status_db->put(status_db, txn, &key, &value, 0);
117 return error;
118 }
119
120 // write a key value pair into the status dictionary,
121 // overwriting the previous value if any.
122 // the key must be a HA_METADATA_KEY.
123 // returns 0 if successful.
write(DB * status_db,HA_METADATA_KEY curr_key_data,void * val,size_t val_size,DB_TXN * txn)124 int write(
125 DB* status_db,
126 HA_METADATA_KEY curr_key_data,
127 void* val,
128 size_t val_size,
129 DB_TXN* txn) {
130
131 return
132 tokudb::metadata::write_low(
133 status_db,
134 &curr_key_data,
135 sizeof(curr_key_data),
136 val,
137 val_size,
138 txn);
139 }
140
141 // remove a key from the status dictionary.
142 // auto create a txn if necessary.
143 // returns 0 if successful.
remove_low(DB * status_db,void * key_data,uint key_size,DB_TXN * txn)144 int remove_low(
145 DB* status_db,
146 void* key_data,
147 uint key_size,
148 DB_TXN* txn) {
149
150 DBT key = {};
151 key.data = key_data;
152 key.size = key_size;
153 int error = status_db->del(status_db, txn, &key, DB_DELETE_ANY);
154 return error;
155 }
156
157 // remove a key from the status dictionary.
158 // the key must be a HA_METADATA_KEY
159 // returns 0 if successful.
remove(DB * status_db,HA_METADATA_KEY curr_key_data,DB_TXN * txn)160 int remove(
161 DB* status_db,
162 HA_METADATA_KEY curr_key_data,
163 DB_TXN* txn) {
164 return
165 tokudb::metadata::remove_low(
166 status_db,
167 &curr_key_data,
168 sizeof(curr_key_data),
169 txn);
170 }
171
close(DB ** status_db_ptr)172 int close(DB** status_db_ptr) {
173 int error = 0;
174 DB* status_db = *status_db_ptr;
175 if (status_db) {
176 error = status_db->close(status_db, 0);
177 if (error == 0)
178 *status_db_ptr = NULL;
179 }
180 return error;
181 }
182
create(DB_ENV * env,DB ** status_db_ptr,const char * name,DB_TXN * txn)183 int create(
184 DB_ENV* env,
185 DB** status_db_ptr,
186 const char* name,
187 DB_TXN* txn) {
188
189 int error;
190 DB *status_db = NULL;
191
192 error = db_create(&status_db, env, 0);
193 if (error == 0) {
194 error = status_db->set_pagesize(status_db, status_dict_pagesize);
195 }
196 if (error == 0) {
197 error =
198 status_db->open(
199 status_db,
200 txn,
201 name,
202 NULL,
203 DB_BTREE, DB_CREATE | DB_EXCL,
204 S_IWUSR);
205 }
206 if (error == 0) {
207 *status_db_ptr = status_db;
208 } else {
209 int r = tokudb::metadata::close(&status_db);
210 assert_always(r == 0);
211 }
212 return error;
213 }
214
215 extern "C" {
216 extern uint force_recovery;
217 }
218
219
open(DB_ENV * env,DB ** status_db_ptr,const char * name,DB_TXN * txn)220 int open(
221 DB_ENV* env,
222 DB** status_db_ptr,
223 const char* name,
224 DB_TXN* txn) {
225
226 int error = 0;
227 DB* status_db = NULL;
228 error = db_create(&status_db, env, 0);
229 if (error == 0) {
230 error =
231 status_db->open(
232 status_db,
233 txn,
234 name,
235 NULL,
236 DB_BTREE,
237 DB_THREAD,
238 force_recovery ? 0 : S_IWUSR);
239 }
240 if (error == 0) {
241 uint32_t pagesize = 0;
242 error = status_db->get_pagesize(status_db, &pagesize);
243 if (error == 0 && pagesize > status_dict_pagesize) {
244 error =
245 status_db->change_pagesize(status_db, status_dict_pagesize);
246 }
247 }
248 if (error == 0) {
249 *status_db_ptr = status_db;
250 } else {
251 int r = tokudb::metadata::close(&status_db);
252 assert_always(r == 0);
253 }
254 return error;
255 }
256
strip_frm_data(DB_ENV * env)257 int strip_frm_data(DB_ENV* env) {
258 int r;
259 DB_TXN* txn = NULL;
260
261 fprintf(stderr, "TokuDB strip_frm_data : Beginning stripping process.\n");
262
263 r = db_env->txn_begin(env, NULL, &txn, 0);
264 assert_always(r == 0);
265
266 DBC* c = NULL;
267 r = env->get_cursor_for_directory(env, txn, &c);
268 assert_always(r == 0);
269
270 DBT key = { };
271 key.flags = DB_DBT_REALLOC;
272
273 DBT val = { };
274 val.flags = DB_DBT_REALLOC;
275 while (1) {
276 r = c->c_get(c, &key, &val, DB_NEXT);
277 if (r == DB_NOTFOUND)
278 break;
279 const char* dname = (const char*) key.data;
280 const char* iname = (const char*) val.data;
281 assert_always(r == 0);
282
283 if (strstr(iname, "_status_")) {
284 fprintf(
285 stderr,
286 "TokuDB strip_frm_data : stripping from dname=%s iname=%s\n",
287 dname,
288 iname);
289
290 DB* status_db;
291 r = tokudb::metadata::open(db_env, &status_db, dname, txn);
292 if (r != 0) {
293 fprintf(
294 stderr,
295 "TokuDB strip_frm_data : unable to open status file %s, "
296 "error = %d\n",
297 dname,
298 r);
299 continue;
300 }
301
302 // GOL : this is a godawful hack. The inventors of this did not
303 // think it would be a good idea to use some kind of magic
304 // identifier k/v pair so that you can in fact tell a proper status
305 // file from any other file that might have the string _status_ in
306 // it. Out in ha_tokudb::create, when the status file is initially
307 // created, it is immediately populated with:
308 // uint hatoku_new_version=HA_TOKU_VERSION=4 and
309 // uint hatoku_capabilities=HA_TOKU_CAP=0
310 // Since I can't count on the fact that these values are/were
311 // _always_ 4 and 0, I can count on the fact that they _must_ be
312 // there and the _must_ be sizeof(uint). That will at least give us
313 // a much better idea that these are in fact status files.
314 void* p = NULL;
315 size_t sz;
316 r =
317 tokudb::metadata::read_realloc(
318 status_db,
319 txn,
320 hatoku_new_version,
321 &p,
322 &sz);
323 if (r != 0) {
324 fprintf(
325 stderr,
326 "TokuDB strip_frm_data : does not look like a real TokuDB "
327 "status file, new_verion is missing, leaving alone %s \n",
328 dname);
329
330 r = tokudb::metadata::close(&status_db);
331 assert_always(r == 0);
332 continue;
333 } else if (sz != sizeof(uint)) {
334 fprintf(
335 stderr,
336 "TokuDB strip_frm_data : does not look like a real TokuDB "
337 "status file, new_verion is the wrong size, "
338 "leaving alone %s \n",
339 dname);
340
341 tokudb::memory::free(p);
342 r = tokudb::metadata::close(&status_db);
343 assert_always(r == 0);
344 continue;
345 }
346 tokudb::memory::free(p);
347 p = NULL;
348
349 r =
350 tokudb::metadata::read_realloc(
351 status_db,
352 txn,
353 hatoku_capabilities,
354 &p,
355 &sz);
356 if (r != 0) {
357 fprintf(
358 stderr,
359 "TokuDB strip_frm_data : does not look like a real TokuDB "
360 "status file, capabilities is missing, leaving alone %s \n",
361 dname);
362
363 r = tokudb::metadata::close(&status_db);
364 assert_always(r == 0);
365 continue;
366 } else if (sz != sizeof(uint)) {
367 fprintf(
368 stderr,
369 "TokuDB strip_frm_data : does not look like a real TokuDB "
370 "status file, capabilities is the wrong size, "
371 "leaving alone %s \n",
372 dname);
373
374 tokudb::memory::free(p);
375 r = tokudb::metadata::close(&status_db);
376 assert_always(r == 0);
377 continue;
378 }
379 tokudb::memory::free(p);
380
381 // OK, st this point, it is probably a status file, not 100% but
382 // it looks like it :(
383 r = tokudb::metadata::remove(status_db, hatoku_frm_data, txn);
384 if (r != 0) {
385 fprintf(
386 stderr,
387 "TokuDB strip_frm_data : unable to find/strip frm data "
388 "from status file %s, error = %d\n",
389 dname,
390 r);
391 }
392
393 r = tokudb::metadata::close(&status_db);
394 assert_always(r == 0);
395 }
396 }
397 tokudb::memory::free(key.data);
398 tokudb::memory::free(val.data);
399
400 fprintf(
401 stderr,
402 "TokuDB strip_frm_data : Stripping process complete, beginning "
403 "commit, this may take some time.\n");
404
405 r = c->c_close(c);
406 assert_always(r == 0);
407
408 r = txn->commit(txn, 0);
409 assert_always(r == 0);
410
411 fprintf(
412 stderr,
413 "TokuDB strip_frm_data : Commit complete, resuming server init "
414 "process.");
415
416 return 0;
417 }
418
419 } // namespace metadata
420 } // namespace tokudb
421 #endif
422