17
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22
21
#include "ha_blitz.h"
23
#include <drizzled/plugin/storage_engine.h>
25
23
using namespace std;
26
24
using namespace drizzled;
27
namespace po= boost::program_options;
29
26
static pthread_mutex_t blitz_utility_mutex;
57
51
tcmapdel(blitz_table_cache);
60
virtual drizzled::Cursor *create(drizzled::Table &table) {
61
return new ha_blitz(*this, table);
54
virtual drizzled::Cursor *create(drizzled::TableShare &table,
55
drizzled::memory::Root *mem_root) {
56
return new (mem_root) ha_blitz(*this, table);
64
59
const char **bas_ext() const {
68
63
int doCreateTable(drizzled::Session &session,
69
64
drizzled::Table &table_arg,
70
const drizzled::identifier::Table &identifier,
65
const drizzled::TableIdentifier &identifier,
71
66
drizzled::message::Table &table_proto);
73
68
int doRenameTable(drizzled::Session &session,
74
const drizzled::identifier::Table &from_identifier,
75
const drizzled::identifier::Table &to_identifier);
69
const drizzled::TableIdentifier &from_identifier,
70
const drizzled::TableIdentifier &to_identifier);
77
72
int doDropTable(drizzled::Session &session,
78
const drizzled::identifier::Table &identifier);
73
const drizzled::TableIdentifier &identifier);
80
75
int doGetTableDefinition(drizzled::Session &session,
81
const drizzled::identifier::Table &identifier,
76
const drizzled::TableIdentifier &identifier,
82
77
drizzled::message::Table &table_proto);
79
void doGetTableNames(drizzled::CachedDirectory &directory,
80
const drizzled::SchemaIdentifier &schema_identifier,
81
std::set<std::string>& set_of_names);
84
83
void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
85
const drizzled::identifier::Schema &schema_identifier,
86
drizzled::identifier::Table::vector &set_of_identifiers);
84
const drizzled::SchemaIdentifier &schema_identifier,
85
drizzled::TableIdentifiers &set_of_identifiers);
88
87
bool doDoesTableExist(drizzled::Session &session,
89
const drizzled::identifier::Table &identifier);
91
bool validateCreateTableOption(const std::string &key,
92
const std::string &state);
88
const drizzled::TableIdentifier &identifier);
94
90
bool doCreateTableCache(void);
119
115
static char *skip_btree_key(const char *key, const size_t skip_len,
120
116
int *return_klen);
122
static bool str_is_numeric(const std::string &str);
124
118
int BlitzEngine::doCreateTable(drizzled::Session &,
125
119
drizzled::Table &table,
126
const drizzled::identifier::Table &identifier,
120
const drizzled::TableIdentifier &identifier,
127
121
drizzled::message::Table &proto) {
132
126
/* Temporary fix for blocking composite keys. We need to add this
133
127
check because version 1 doesn't handle composite indexes. */
134
for (uint32_t i = 0; i < table.getShare()->keys; i++) {
128
for (uint32_t i = 0; i < table.s->keys; i++) {
135
129
if (table.key_info[i].key_parts > 1)
136
130
return HA_ERR_UNSUPPORTED;
147
141
/* Create b+tree index(es) for this table. */
148
for (uint32_t i = 0; i < table.getShare()->keys; i++) {
142
for (uint32_t i = 0; i < table.s->keys; i++) {
149
143
if ((ecode = btree.create(identifier.getPath().c_str(), i)) != 0)
166
160
int BlitzEngine::doRenameTable(drizzled::Session &,
167
const drizzled::identifier::Table &from,
168
const drizzled::identifier::Table &to) {
161
const drizzled::TableIdentifier &from,
162
const drizzled::TableIdentifier &to) {
171
165
BlitzData blitz_table;
176
/* Write the table definition to system table. */
177
if ((ecode = dict.open_system_table(from.getPath(), HDBOWRITER)) != 0)
180
drizzled::message::Table proto;
182
int proto_string_len;
184
proto_string = dict.get_system_entry(BLITZ_TABLE_PROTO_KEY.c_str(),
185
BLITZ_TABLE_PROTO_KEY.length(),
188
if (proto_string == NULL) {
192
if (!proto.ParseFromArray(proto_string, proto_string_len)) {
194
return HA_ERR_CRASHED_ON_USAGE;
199
proto.set_name(to.getTableName());
200
proto.set_schema(to.getSchemaName());
201
proto.set_catalog(to.getCatalogName());
203
if (!dict.write_table_definition(proto)) {
204
dict.close_system_table();
205
return HA_ERR_CRASHED_ON_USAGE;
208
dict.close_system_table();
210
168
/* Find out the number of indexes in this table. This information
211
169
is required because BlitzDB creates a file for each indexes.*/
212
170
if (blitz_table.open_data_table(from.getPath().c_str(), HDBOREADER) != 0)
286
244
int BlitzEngine::doGetTableDefinition(drizzled::Session &,
287
const drizzled::identifier::Table &identifier,
245
const drizzled::TableIdentifier &identifier,
288
246
drizzled::message::Table &proto) {
289
247
struct stat stat_info;
290
248
std::string path(identifier.getPath());
286
void BlitzEngine::doGetTableNames(drizzled::CachedDirectory &directory,
287
const drizzled::SchemaIdentifier &,
288
std::set<string> &set_of_names) {
289
drizzled::CachedDirectory::Entries entries = directory.getEntries();
291
for (drizzled::CachedDirectory::Entries::iterator entry_iter = entries.begin();
292
entry_iter != entries.end(); ++entry_iter) {
294
drizzled::CachedDirectory::Entry *entry = *entry_iter;
295
std::string *filename = &entry->filename;
297
assert(filename->size());
299
const char *ext = strchr(filename->c_str(), '.');
302
char uname[NAME_LEN + 1];
303
uint32_t file_name_len;
305
file_name_len = TableIdentifier::filename_to_tablename(filename->c_str(),
309
uname[file_name_len - sizeof(BLITZ_DATA_EXT) + 1]= '\0';
310
set_of_names.insert(uname);
328
315
void BlitzEngine::doGetTableIdentifiers(drizzled::CachedDirectory &directory,
329
const drizzled::identifier::Schema &schema_id,
330
drizzled::identifier::Table::vector &ids) {
316
const drizzled::SchemaIdentifier &schema_id,
317
drizzled::TableIdentifiers &ids) {
331
318
drizzled::CachedDirectory::Entries entries = directory.getEntries();
333
320
for (drizzled::CachedDirectory::Entries::iterator entry_iter = entries.begin();
346
333
char uname[NAME_LEN + 1];
347
334
uint32_t file_name_len;
349
file_name_len = identifier::Table::filename_to_tablename(filename->c_str(),
336
file_name_len = TableIdentifier::filename_to_tablename(filename->c_str(),
353
340
uname[file_name_len - sizeof(BLITZ_DATA_EXT) + 1]= '\0';
354
ids.push_back(identifier::Table(schema_id, uname));
341
ids.push_back(TableIdentifier(schema_id, uname));
359
346
bool BlitzEngine::doDoesTableExist(drizzled::Session &,
360
const drizzled::identifier::Table &identifier) {
347
const drizzled::TableIdentifier &identifier) {
361
348
std::string proto_path(identifier.getPath());
362
349
proto_path.append(BLITZ_DATA_EXT);
364
351
return (access(proto_path.c_str(), F_OK)) ? false : true;
367
bool BlitzEngine::validateCreateTableOption(const std::string &key,
368
const std::string &state) {
369
if (key == "ESTIMATED_ROWS" || key == "estimated_rows") {
370
if (str_is_numeric(state))
376
354
bool BlitzEngine::doCreateTableCache(void) {
377
355
return ((blitz_table_cache = tcmapnew()) == NULL) ? false : true;
406
384
ha_blitz::ha_blitz(drizzled::plugin::StorageEngine &engine_arg,
407
Table &table_arg) : Cursor(engine_arg, table_arg),
385
TableShare &table_arg) : Cursor(engine_arg, table_arg),
408
386
btree_cursor(NULL),
409
387
table_scan(false),
410
388
table_based(false),
460
438
will use to uniquely identify a row. The actual allocation is
461
439
done by the kernel so all we do here is specify the size of it.*/
462
440
if (share->primary_key_exists) {
463
ref_length = getTable()->key_info[getTable()->getShare()->getPrimaryKey()].key_length;
441
ref_length = table->key_info[table->s->getPrimaryKey()].key_length;
465
443
ref_length = sizeof(held_key_len) + sizeof(uint64_t);
500
478
int ha_blitz::doStartTableScan(bool scan) {
501
479
/* Obtain the query type for this scan */
502
sql_command_type = getTable()->getSession()->getSqlCommand();
480
sql_command_type = session_sql_command(table->getSession());
503
481
table_scan = scan;
504
482
table_based = true;
506
484
/* Obtain the most suitable lock for the given statement type. */
507
blitz_optimal_lock();
485
critical_section_enter();
509
487
/* Get the first record from TCHDB. Let the scanner take
510
488
care of checking return value errors. */
625
603
int ha_blitz::doStartIndexScan(uint32_t key_num, bool) {
626
604
active_index = key_num;
627
sql_command_type = getTable()->getSession()->getSqlCommand();
605
sql_command_type = session_sql_command(table->getSession());
629
607
/* This is unlikely to happen but just for assurance, re-obtain
630
608
the lock if this thread already has a certain lock. This makes
631
609
sure that this thread will get the most appropriate lock for
632
610
the current statement. */
633
611
if (thread_locked)
634
blitz_optimal_unlock();
612
critical_section_exit();
636
blitz_optimal_lock();
614
critical_section_enter();
679
657
if ((row = share->dict.get_row(dict_key, dict_klen, &rlen)) == NULL) {
681
getTable()->status = STATUS_NOT_FOUND;
659
table->status = STATUS_NOT_FOUND;
682
660
return HA_ERR_KEY_NOT_FOUND;
833
811
ha_statistic_increment(&system_status_var::ha_write_count);
835
813
/* Prepare Auto Increment field if one exists. */
836
if (getTable()->next_number_field && drizzle_row == getTable()->getInsertRecord()) {
814
if (table->next_number_field && drizzle_row == table->record[0]) {
837
815
pthread_mutex_lock(&blitz_utility_mutex);
838
816
if ((rv = update_auto_increment()) != 0) {
839
817
pthread_mutex_unlock(&blitz_utility_mutex);
843
uint64_t next_val = getTable()->next_number_field->val_int();
821
uint64_t next_val = table->next_number_field->val_int();
845
823
if (next_val > share->auto_increment_value) {
846
824
share->auto_increment_value = next_val;
971
949
/* Now write the new key. */
972
950
prefix_len = make_index_key(key_buffer, i, new_row);
974
if (i == getTable()->getShare()->getPrimaryKey()) {
952
if (i == table->s->getPrimaryKey()) {
975
953
key = merge_key(key_buffer, prefix_len, key_buffer, prefix_len, &klen);
976
954
rv = share->btrees[i].write(key, klen);
998
976
if (table_based) {
999
977
rv = share->dict.write_row(held_key, held_key_len, row_buf, row_len);
1001
int klen = make_index_key(key_buffer, getTable()->getShare()->getPrimaryKey(), old_row);
979
int klen = make_index_key(key_buffer, table->s->getPrimaryKey(), old_row);
1003
981
/* Delete with the old key. */
1004
982
share->dict.delete_row(key_buffer, klen);
1006
984
/* Write with the new key. */
1007
klen = make_index_key(key_buffer, getTable()->getShare()->getPrimaryKey(), new_row);
985
klen = make_index_key(key_buffer, table->s->getPrimaryKey(), new_row);
1008
986
rv = share->dict.write_row(key_buffer, klen, row_buf, row_len);
1098
1076
uint32_t ha_blitz::max_row_length(void) {
1099
uint32_t length = (getTable()->getRecordLength() + getTable()->sizeFields() * 2);
1100
uint32_t *pos = getTable()->getBlobField();
1101
uint32_t *end = pos + getTable()->sizeBlobFields();
1077
uint32_t length = (table->getRecordLength() + table->sizeFields() * 2);
1078
uint32_t *pos = table->getBlobField();
1079
uint32_t *end = pos + table->sizeBlobFields();
1103
1081
while (pos != end) {
1104
length += 2 + ((Field_blob *)getTable()->getField(*pos))->get_length();
1082
length += 2 + ((Field_blob *)table->getField(*pos))->get_length();
1118
1096
/* Getting here means that there is a PK in this table. Get the
1119
1097
binary representation of the PK, pack it to BlitzDB's key buffer
1120
1098
and return the size of it. */
1121
return make_index_key(pack_to, getTable()->getShare()->getPrimaryKey(), row);
1099
return make_index_key(pack_to, table->s->getPrimaryKey(), row);
1124
1102
size_t ha_blitz::make_index_key(char *pack_to, int key_num,
1125
1103
const unsigned char *row) {
1126
KeyInfo *key = &getTable()->key_info[key_num];
1104
KeyInfo *key = &table->key_info[key_num];
1127
1105
KeyPartInfo *key_part = key->key_part;
1128
1106
KeyPartInfo *key_part_end = key_part + key->key_parts;
1146
/* Here we normalize VARTEXT1 to VARTEXT2 for simplicity. */
1147
if (key_part->type == HA_KEYTYPE_VARTEXT1) {
1148
/* Extract the length of the string from the row. */
1149
uint16_t data_len = *(uint8_t *)(row + key_part->offset);
1151
/* Copy the length of the string. Use 2 bytes. */
1152
int2store(pos, data_len);
1153
pos += sizeof(data_len);
1155
/* Copy the string data */
1156
memcpy(pos, row + key_part->offset + sizeof(uint8_t), data_len);
1159
end = key_part->field->pack(pos, row + key_part->offset);
1124
end = key_part->field->pack(pos, row + key_part->offset);
1165
1129
return ((char *)pos - pack_to);
1200
1164
size_t ha_blitz::btree_key_length(const char *key, const int key_num) {
1201
KeyInfo *key_info = &getTable()->key_info[key_num];
1165
KeyInfo *key_info = &table->key_info[key_num];
1202
1166
KeyPartInfo *key_part = key_info->key_part;
1203
1167
KeyPartInfo *key_part_end = key_part + key_info->key_parts;
1204
1168
char *pos = (char *)key;
1208
1172
for (; key_part != key_part_end; key_part++) {
1209
1173
if (key_part->null_bit) {
1216
if (key_part->type == HA_KEYTYPE_VARTEXT1 ||
1217
key_part->type == HA_KEYTYPE_VARTEXT2) {
1179
if (key_part->type == HA_KEYTYPE_VARTEXT1) {
1180
len = *(uint8_t *)pos;
1181
rv += len + sizeof(uint8_t);
1182
} else if (key_part->type == HA_KEYTYPE_VARTEXT2) {
1218
1183
len = uint2korr(pos);
1219
1184
rv += len + sizeof(uint16_t);
1237
1202
/* Converts a native Drizzle index key to BlitzDB's format. */
1238
1203
char *ha_blitz::native_to_blitz_key(const unsigned char *native_key,
1239
1204
const int key_num, int *return_key_len) {
1240
KeyInfo *key = &getTable()->key_info[key_num];
1205
KeyInfo *key = &table->key_info[key_num];
1241
1206
KeyPartInfo *key_part = key->key_part;
1242
1207
KeyPartInfo *key_part_end = key_part + key->key_parts;
1261
/* Normalize a VARTEXT1 key to VARTEXT2. */
1226
/* This is a temporary workaround for a bug in Drizzle's VARCHAR
1227
where a 1 byte representable length varchar's actual data is
1228
positioned 2 bytes ahead of the beginning of the buffer. The
1229
correct behavior is to be positioned 1 byte ahead. Furthermore,
1230
this is only applicable with varchar keys on READ. */
1262
1231
if (key_part->type == HA_KEYTYPE_VARTEXT1) {
1263
uint16_t str_len = *(uint16_t *)key_pos;
1265
/* Copy the length of the string over to key buffer. */
1266
int2store(keybuf_pos, str_len);
1267
keybuf_pos += sizeof(str_len);
1269
/* Copy the actual value over to the key buffer. */
1270
memcpy(keybuf_pos, key_pos + sizeof(str_len), str_len);
1271
keybuf_pos += str_len;
1273
/* NULL byte + Length of str (2 byte) + Actual String. */
1274
offset = 1 + sizeof(str_len) + str_len;
1232
/* Dereference the 1 byte length of the value. */
1233
uint8_t varlen = *(uint8_t *)key_pos;
1234
*keybuf_pos++ = varlen;
1236
/* Read the value by skipping 2 bytes. This is the workaround. */
1237
memcpy(keybuf_pos, key_pos + sizeof(uint16_t), varlen);
1238
offset = (sizeof(uint8_t) + varlen);
1239
keybuf_pos += varlen;
1276
1241
end = key_part->field->pack(keybuf_pos, key_pos);
1277
1242
offset = end - keybuf_pos;
1293
1258
/* Nothing special to do if the table is fixed length */
1294
1259
if (share->fixed_length_table) {
1295
memcpy(row_buffer, row_to_pack, getTable()->getShare()->getRecordLength());
1296
return (size_t)getTable()->getShare()->getRecordLength();
1260
memcpy(row_buffer, row_to_pack, table->s->getRecordLength());
1261
return (size_t)table->s->getRecordLength();
1299
1264
/* Copy NULL bits */
1300
memcpy(row_buffer, row_to_pack, getTable()->getShare()->null_bytes);
1301
pos = row_buffer + getTable()->getShare()->null_bytes;
1265
memcpy(row_buffer, row_to_pack, table->s->null_bytes);
1266
pos = row_buffer + table->s->null_bytes;
1303
1268
/* Pack each field into the buffer */
1304
for (Field **field = getTable()->getFields(); *field; field++) {
1269
for (Field **field = table->getFields(); *field; field++) {
1305
1270
if (!((*field)->is_null()))
1306
1271
pos = (*field)->pack(pos, row_to_pack + (*field)->offset(row_to_pack));
1322
1287
/* Start by copying NULL bits which is the beginning block
1323
1288
of a Drizzle row. */
1324
1289
pos = (const unsigned char *)from;
1325
memcpy(to, pos, getTable()->getShare()->null_bytes);
1326
pos += getTable()->getShare()->null_bytes;
1290
memcpy(to, pos, table->s->null_bytes);
1291
pos += table->s->null_bytes;
1328
1293
/* Unpack all fields in the provided row. */
1329
for (Field **field = getTable()->getFields(); *field; field++) {
1294
for (Field **field = table->getFields(); *field; field++) {
1330
1295
if (!((*field)->is_null())) {
1331
pos = (*field)->unpack(to + (*field)->offset(getTable()->getInsertRecord()), pos);
1296
pos = (*field)->unpack(to + (*field)->offset(table->record[0]), pos);
1361
1326
BlitzShare *ha_blitz::get_share(const char *name) {
1362
1327
BlitzShare *share_ptr;
1363
BlitzEngine *bz_engine = (BlitzEngine *)getEngine();
1328
BlitzEngine *bz_engine = (BlitzEngine *)engine;
1364
1329
std::string table_path(name);
1366
1331
pthread_mutex_lock(&blitz_utility_mutex);
1387
1352
/* Prepare Index Structure(s) */
1388
KeyInfo *curr = &getTable()->getMutableShare()->getKeyInfo(0);
1389
share_ptr->btrees = new BlitzTree[getTable()->getShare()->keys];
1353
KeyInfo *curr = &table->s->getKeyInfo(0);
1354
share_ptr->btrees = new BlitzTree[table->s->keys];
1391
for (uint32_t i = 0; i < getTable()->getShare()->keys; i++, curr++) {
1356
for (uint32_t i = 0; i < table->s->keys; i++, curr++) {
1392
1357
share_ptr->btrees[i].open(table_path.c_str(), i, BDBOWRITER);
1393
1358
share_ptr->btrees[i].parts = new BlitzKeyPart[curr->key_parts];
1395
if (getTable()->key_info[i].flags & HA_NOSAME)
1360
if (table->key_info[i].flags & HA_NOSAME)
1396
1361
share_ptr->btrees[i].unique = true;
1398
1363
share_ptr->btrees[i].length = curr->key_length;
1405
1370
if (f->null_ptr) {
1406
1371
share_ptr->btrees[i].parts[j].null_bitmask = f->null_bit;
1407
1372
share_ptr->btrees[i].parts[j].null_pos
1408
= (uint32_t)(f->null_ptr - (unsigned char *)getTable()->getInsertRecord());
1373
= (uint32_t)(f->null_ptr - (unsigned char *)table->record[0]);
1411
1376
share_ptr->btrees[i].parts[j].flag = curr->key_part[j].key_part_flag;
1423
1388
/* Set Meta Data */
1424
1389
share_ptr->auto_increment_value = share_ptr->dict.read_meta_autoinc();
1425
1390
share_ptr->table_name = table_path;
1426
share_ptr->nkeys = getTable()->getShare()->keys;
1391
share_ptr->nkeys = table->s->keys;
1427
1392
share_ptr->use_count = 1;
1429
share_ptr->fixed_length_table = !(getTable()->getShare()->db_create_options
1394
share_ptr->fixed_length_table = !(table->s->db_create_options
1430
1395
& HA_OPTION_PACK_RECORD);
1432
if (getTable()->getShare()->getPrimaryKey() >= MAX_KEY)
1397
if (table->s->getPrimaryKey() >= MAX_KEY)
1433
1398
share_ptr->primary_key_exists = false;
1435
1400
share_ptr->primary_key_exists = true;
1494
1457
return pos + skip_len + sizeof(uint16_t);
1497
static bool str_is_numeric(const std::string &str) {
1498
for (uint32_t i = 0; i < str.length(); i++) {
1499
if (!std::isdigit(str[i]))
1505
static void blitz_init_options(drizzled::module::option_context &context)
1507
context("estimated-rows",
1508
po::value<uint64_t>(&blitz_estimated_rows)->default_value(0),
1509
N_("Estimated number of rows that a BlitzDB table will store."));
1512
DRIZZLE_PLUGIN(blitz_init, NULL, blitz_init_options);
1460
DRIZZLE_PLUGIN(blitz_init, NULL, NULL);