1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2009 - 2010 Toru Maesaka
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; version 2 of the License.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
using namespace drizzled;
26
int BlitzData::startup(const char *path) {
29
if ((rv = open_data_table(path, HDBOWRITER)) != 0)
32
current_hidden_row_id = read_meta_row_id();
36
int BlitzData::shutdown() {
39
/* Copy the latest autogenerated ID back to TC's metadata buffer.
40
This data will be sync'd by TC. */
41
write_meta_row_id(current_hidden_row_id);
43
if ((rv = close_data_table()) != 0)
49
/* Similar to UNIX touch(1) but generates a tuned TCHDB file. */
50
int BlitzData::create_data_table(drizzled::message::Table &proto,
51
drizzled::Table &table_info,
52
const drizzled::identifier::Table &identifier) {
54
std::string path = identifier.getPath() + BLITZ_DATA_EXT;
56
uint64_t autoinc = (proto.options().has_auto_increment_value())
57
? proto.options().auto_increment_value() - 1 : 0;
59
uint64_t hash_buckets = (blitz_estimated_rows == 0) ? BLITZ_TC_BUCKETS
60
: blitz_estimated_rows;
61
int n_options = proto.engine().options_size();
63
for (int i = 0; i < n_options; i++) {
64
if (proto.engine().options(i).name() == "estimated_rows" ||
65
proto.engine().options(i).name() == "ESTIMATED_ROWS") {
66
std::istringstream stream(proto.engine().options(i).state());
67
stream >> hash_buckets;
69
if (hash_buckets <= 0)
70
hash_buckets = BLITZ_TC_BUCKETS;
74
if (data_table != NULL)
75
return HA_ERR_GENERIC;
77
if ((data_table = tchdbnew()) == NULL)
78
return HA_ERR_OUT_OF_MEM;
80
if (!tchdbtune(data_table, hash_buckets, -1, -1, 0)) {
82
return HA_ERR_CRASHED_ON_USAGE;
85
if (!tchdbopen(data_table, path.c_str(), (HDBOWRITER | HDBOCREAT))) {
87
return HA_ERR_CRASHED_ON_USAGE;
90
/* Write the Meta Data for this Table. */
91
tc_meta_buffer = tchdbopaque(data_table);
92
write_meta_autoinc(autoinc);
93
write_meta_keycount(table_info.getShare()->keys);
96
if (close_data_table() != 0)
97
return HA_ERR_CRASHED_ON_USAGE;
102
int BlitzData::open_data_table(const char *path, const int mode) {
105
if ((data_table = tchdbnew()) == NULL)
106
return HA_ERR_OUT_OF_MEM;
108
if (!tchdbsetmutex(data_table)) {
109
tchdbdel(data_table);
110
return HA_ERR_CRASHED_ON_USAGE;
113
if (!tchdbsetxmsiz(data_table, BLITZ_TC_EXTRA_MMAP_SIZE)) {
114
tchdbdel(data_table);
115
return HA_ERR_CRASHED_ON_USAGE;
118
snprintf(buf, FN_REFLEN, "%s%s", path, BLITZ_DATA_EXT);
120
if (!tchdbopen(data_table, buf, mode)) {
121
tchdbdel(data_table);
122
return HA_ERR_CRASHED_ON_USAGE;
125
tc_meta_buffer = tchdbopaque(data_table);
129
bool BlitzData::rename_table(const char *from, const char *to) {
130
char from_buf[FN_REFLEN];
131
char to_buf[FN_REFLEN];
133
snprintf(from_buf, FN_REFLEN, "%s%s", from, BLITZ_DATA_EXT);
134
snprintf(to_buf, FN_REFLEN, "%s%s", to, BLITZ_DATA_EXT);
136
if (rename(from_buf, to_buf) != 0)
139
snprintf(from_buf, FN_REFLEN, "%s%s", from, BLITZ_SYSTEM_EXT);
140
snprintf(to_buf, FN_REFLEN, "%s%s", to, BLITZ_SYSTEM_EXT);
142
if (rename(from_buf, to_buf) != 0)
148
int BlitzData::close_data_table(void) {
151
if (!tchdbclose(data_table)) {
152
tchdbdel(data_table);
153
return HA_ERR_CRASHED_ON_USAGE;
156
tchdbdel(data_table);
158
tc_meta_buffer = NULL;
162
uint64_t BlitzData::nrecords(void) {
163
return tchdbrnum(data_table);
166
uint64_t BlitzData::table_size(void) {
167
return tchdbfsiz(data_table);
170
uint64_t BlitzData::read_meta_row_id(void) {
171
assert(tc_meta_buffer);
172
return (uint64_t)uint8korr(tc_meta_buffer);
175
uint64_t BlitzData::read_meta_autoinc(void) {
176
assert(tc_meta_buffer);
177
char *pos = tc_meta_buffer + sizeof (current_hidden_row_id);
178
return (uint64_t)uint8korr(pos);
181
uint32_t BlitzData::read_meta_keycount(void) {
182
assert(tc_meta_buffer);
183
char *pos = tc_meta_buffer;
184
pos += sizeof(current_hidden_row_id) + sizeof(uint64_t);
185
return (uint32_t)uint4korr(pos);
188
void BlitzData::write_meta_row_id(uint64_t row_id) {
189
assert(tc_meta_buffer);
190
int8store(tc_meta_buffer, row_id);
193
void BlitzData::write_meta_autoinc(uint64_t num) {
194
assert(tc_meta_buffer);
195
char *pos = tc_meta_buffer + sizeof(current_hidden_row_id);
199
void BlitzData::write_meta_keycount(uint32_t nkeys) {
200
assert(tc_meta_buffer);
201
char *pos = tc_meta_buffer;
202
pos += sizeof(current_hidden_row_id) + sizeof(uint64_t);
203
int4store(pos, nkeys);
206
char *BlitzData::get_row(const char *key, const size_t klen, int *vlen) {
207
return (char *)tchdbget(data_table, key, klen, vlen);
210
/* Fastest way to fetch both key and value from TCHDB since it only
211
involves one allocation. That is, both key and value are living
212
on the same block of memory. The return value is a pointer to the
213
next key. Technically it is a pointer to the region of memory that
214
holds both key and value. */
215
char *BlitzData::next_key_and_row(const char *key, const size_t klen,
216
int *next_key_len, const char **value,
218
return tchdbgetnext3(data_table, key, klen, next_key_len, value, value_len);
221
char *BlitzData::first_row(int *row_len) {
222
return (char *)tchdbgetnext(data_table, NULL, 0, row_len);
225
uint64_t BlitzData::next_hidden_row_id(void) {
226
/* current_hidden_row_id is an atomic type */
227
uint64_t rv = current_hidden_row_id.increment();
231
int BlitzData::write_row(const char *key, const size_t klen,
232
const unsigned char *row, const size_t rlen) {
233
return (tchdbput(data_table, key, klen, row, rlen)) ? 0 : 1;
236
int BlitzData::write_unique_row(const char *key, const size_t klen,
237
const unsigned char *row, const size_t rlen) {
240
if (!tchdbputkeep(data_table, key, klen, row, rlen)) {
241
if (tchdbecode(data_table) == TCEKEEP) {
242
errno = HA_ERR_FOUND_DUPP_KEY;
243
rv = HA_ERR_FOUND_DUPP_KEY;
249
int BlitzData::delete_row(const char *key, const size_t klen) {
250
return (tchdbout(data_table, key, klen)) ? 0 : -1;
253
bool BlitzData::delete_all_rows() {
254
char buf[BLITZ_MAX_META_LEN];
256
/* Evacuate the meta data buffer since this will be wiped out. */
257
memcpy(buf, tc_meta_buffer, BLITZ_MAX_META_LEN);
259
/* Now it's safe to wipe everything. */
260
if (!tchdbvanish(data_table))
263
/* Copy the evacuated meta buffer back to the fresh TCHDB file. */
264
tc_meta_buffer = tchdbopaque(data_table);
265
memcpy(tc_meta_buffer, buf, BLITZ_MAX_META_LEN);
270
/* Code from here on is for BlitzDB's internal system information management.
271
It is deliberately separated from the data dictionary code because we
272
might move to a simple flat file structure in the future. For now we
273
use a micro Tokyo Cabinet database for this. */
274
int BlitzData::create_system_table(const std::string &path) {
276
int mode = (HDBOWRITER | HDBOCREAT);
278
if ((rv = open_system_table(path.c_str(), mode)) != 0)
281
return close_system_table();
284
int BlitzData::open_system_table(const std::string &path, const int mode) {
286
const int BUCKETS = 7;
288
if ((system_table = tchdbnew()) == NULL)
289
return HA_ERR_OUT_OF_MEM;
291
if (!tchdbsetmutex(system_table)) {
292
tchdbdel(system_table);
293
return HA_ERR_CRASHED_ON_USAGE;
296
if (!tchdbtune(system_table, BUCKETS, -1, -1, 0)) {
297
tchdbdel(system_table);
298
return HA_ERR_CRASHED_ON_USAGE;
301
snprintf(buf, FN_REFLEN, "%s%s", path.c_str(), BLITZ_SYSTEM_EXT);
303
if (!tchdbopen(system_table, buf, mode)) {
304
tchdbdel(system_table);
305
return HA_ERR_CRASHED_ON_USAGE;
311
int BlitzData::close_system_table(void) {
312
assert(system_table);
314
if (!tchdbclose(system_table)) {
315
tchdbdel(system_table);
316
return HA_ERR_CRASHED_ON_USAGE;
318
tchdbdel(system_table);
322
bool BlitzData::write_table_definition(drizzled::message::Table &proto) {
323
assert(system_table);
325
std::string serialized_proto;
326
proto.SerializeToString(&serialized_proto);
328
if (!tchdbput(system_table, BLITZ_TABLE_PROTO_KEY.c_str(),
329
BLITZ_TABLE_PROTO_KEY.length(), serialized_proto.c_str(),
330
serialized_proto.length())) {
334
if (proto.options().has_comment()) {
335
if (!tchdbput(system_table, BLITZ_TABLE_PROTO_COMMENT_KEY.c_str(),
336
BLITZ_TABLE_PROTO_COMMENT_KEY.length(),
337
proto.options().comment().c_str(),
338
proto.options().comment().length())) {
345
char *BlitzData::get_system_entry(const char *key, const size_t klen,
347
assert(system_table);
348
return (char *)tchdbget(system_table, key, klen, vlen);