1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2009 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
22
#define BLITZ_TC_EXTRA_MMAP_SIZE (1024 * 1024 * 256)
23
#define BLITZ_TC_BUCKET_NUM 1000000
25
BlitzData::BlitzData() : current_hidden_id(0) {
26
pthread_mutex_init(&id_lock, NULL);
29
BlitzData::~BlitzData() {
30
pthread_mutex_destroy(&id_lock);
33
bool BlitzData::startup(const char *table_name) {
34
data_table = open_table(table_name, BLITZ_DATAFILE_EXT, HDBOWRITER);
36
if (data_table == NULL)
39
system_table = open_table(table_name, BLITZ_SYSTEM_EXT, HDBOWRITER);
41
if (system_table == NULL) {
42
close_table(data_table);
46
tc_meta_buffer = tchdbopaque(data_table);
47
current_hidden_id = (uint64_t)uint8korr(tc_meta_buffer);
51
bool BlitzData::shutdown() {
52
/* Copy the latest autogenerated ID back to TC's metadata buffer.
53
This data will be sync'd by TC. */
54
int8store(tc_meta_buffer, current_hidden_id);
56
if (!close_table(data_table))
59
if (!close_table(system_table))
65
/* Similar to UNIX touch(1) but generates a TCHDB file. */
66
int BlitzData::create_table(const char *table_path, const char *ext) {
68
int mode = (HDBOWRITER | HDBOCREAT);
70
if ((table = open_table(table_path, ext, mode)) == NULL)
71
return HA_ERR_CRASHED_ON_USAGE;
73
if (!close_table(table))
74
return HA_ERR_CRASHED_ON_USAGE;
79
TCHDB *BlitzData::open_table(const char *path, const char *ext, int mode) {
81
char name_buffer[FN_REFLEN];
83
if ((table = tchdbnew()) == NULL) {
87
if (!tchdbsetmutex(table)) {
92
/* Allow the data table to use more resource than default. */
93
if (strcmp(ext, BLITZ_DATAFILE_EXT) == 0) {
94
if (!tchdbtune(table, BLITZ_TC_BUCKET_NUM, -1, -1, 0)) {
99
if (!tchdbsetxmsiz(table, BLITZ_TC_EXTRA_MMAP_SIZE)) {
105
snprintf(name_buffer, FN_REFLEN, "%s%s", path, ext);
107
if (!tchdbopen(table, name_buffer, mode)) {
115
bool BlitzData::rename_table(const char *from, const char *to) {
116
char from_buf[FN_REFLEN];
117
char to_buf[FN_REFLEN];
119
snprintf(from_buf, FN_REFLEN, "%s%s", from, BLITZ_DATAFILE_EXT);
120
snprintf(to_buf, FN_REFLEN, "%s%s", to, BLITZ_DATAFILE_EXT);
122
if (rename(from_buf, to_buf) != 0)
125
snprintf(from_buf, FN_REFLEN, "%s%s", from, BLITZ_SYSTEM_EXT);
126
snprintf(to_buf, FN_REFLEN, "%s%s", to, BLITZ_SYSTEM_EXT);
128
if (rename(from_buf, to_buf) != 0)
134
bool BlitzData::close_table(TCHDB *table) {
137
if (!tchdbclose(table)) {
146
bool BlitzData::write_table_definition(TCHDB *table,
147
drizzled::message::Table &proto) {
149
string serialized_proto;
151
proto.SerializeToString(&serialized_proto);
153
if (!tchdbput(table, BLITZ_TABLE_PROTO_KEY.c_str(),
154
BLITZ_TABLE_PROTO_KEY.length(), serialized_proto.c_str(),
155
serialized_proto.length())) {
159
if (proto.options().has_comment()) {
160
if (!tchdbput(table, BLITZ_TABLE_PROTO_COMMENT_KEY.c_str(),
161
BLITZ_TABLE_PROTO_COMMENT_KEY.length(),
162
proto.options().comment().c_str(),
163
proto.options().comment().length())) {
170
uint64_t BlitzData::nrecords() {
171
return tchdbrnum(data_table);
174
char *BlitzData::get_row(const char *key, const size_t klen, int *vlen) {
175
return (char *)tchdbget(data_table, key, klen, vlen);
178
/* Fastest way to fetch both key and value from TCHDB since it only
179
involves one allocation. That is, both key and value are living
180
on the same block of memory. The return value is a pointer to the
181
next key. Technically it is a pointer to the region of memory that
182
holds both key and value. */
183
char *BlitzData::next_key_and_row(const char *key, const size_t klen,
184
int *next_key_len, const char **value,
186
return tchdbgetnext3(data_table, key, klen, next_key_len,
187
value, value_length);
190
/* Set key_ptr to the beginning of the key on memory and return
191
the length of the key */
192
uint16_t BlitzData::fetch_position(unsigned char *position_buf,
193
unsigned char *key_ptr) {
195
memcpy(&key_length, position_buf, sizeof(uint16_t));
196
key_ptr = position_buf + sizeof(uint16_t);
200
/* Store the position of the most recently fetched record so
201
that drizzled can directly fetch the row later on for some
203
void BlitzData::store_position(unsigned char *ref, char *key,
205
uint16_t key_length = (uint16_t)klen;
206
memcpy(ref, &key_length, sizeof(uint16_t));
207
memcpy(ref + sizeof(uint16_t), key, klen);
210
uint64_t BlitzData::next_hidden_row_id(void) {
211
pthread_mutex_lock(&id_lock);
212
uint64_t rv = ++current_hidden_id;
213
pthread_mutex_unlock(&id_lock);
217
size_t BlitzData::generate_table_key(char *key_buffer) {
218
int8store(key_buffer, next_hidden_row_id());
219
return sizeof(uint64_t);
222
bool BlitzData::overwrite_row(const char *key, const size_t klen,
223
const unsigned char *row, const size_t rlen) {
224
return tchdbput(data_table, key, klen, row, rlen);
227
bool BlitzData::delete_row(const char *key, const size_t klen) {
228
return tchdbout(data_table, key, klen);
231
bool BlitzData::delete_all_rows() {
232
return tchdbvanish(data_table);