12
12
You should have received a copy of the GNU General Public License
13
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
#include "heap_priv.h"
16
#include <drizzled/server_includes.h>
17
17
#include <drizzled/error.h>
18
18
#include <drizzled/table.h>
19
19
#include <drizzled/session.h>
20
#include <drizzled/current_session.h>
20
21
#include <drizzled/field/timestamp.h>
21
22
#include <drizzled/field/varstring.h>
22
#include "drizzled/plugin/daemon.h"
24
#include <boost/thread/mutex.hpp>
27
25
#include "ha_heap.h"
32
using namespace drizzled;
33
30
using namespace std;
35
32
static const string engine_name("MEMORY");
37
boost::mutex THR_LOCK_heap;
34
pthread_mutex_t THR_LOCK_heap= PTHREAD_MUTEX_INITIALIZER;
39
36
static const char *ha_heap_exts[] = {
43
class HeapEngine : public plugin::StorageEngine
40
class HeapEngine : public StorageEngine
46
explicit HeapEngine(string name_arg) :
47
plugin::StorageEngine(name_arg,
48
HTON_STATS_RECORDS_IS_EXACT |
53
HTON_SKIP_STORE_LOCK |
60
hp_panic(HA_PANIC_CLOSE);
63
virtual Cursor *create(Table &table)
65
return new ha_heap(*this, table);
43
HeapEngine(string name_arg) : StorageEngine(name_arg, HTON_CAN_RECREATE|HTON_TEMPORARY_ONLY)
48
virtual handler *create(TableShare *table,
51
return new (mem_root) ha_heap(this, table);
68
54
const char **bas_ext() const {
69
55
return ha_heap_exts;
72
int doCreateTable(Session &session,
74
const TableIdentifier &identifier,
75
message::Table &create_proto);
58
int createTableImplementation(Session *session, const char *table_name,
59
Table *table_arg, HA_CREATE_INFO *create_info,
60
drizzled::message::Table*);
77
/* For whatever reason, internal tables can be created by Cursor::open()
62
/* For whatever reason, internal tables can be created by handler::open()
79
64
Instead of diving down a rat hole, let's just cry ourselves to sleep
80
65
at night with this odd hackish workaround.
82
67
int heap_create_table(Session *session, const char *table_name,
68
Table *table_arg, HA_CREATE_INFO *create_info,
84
69
bool internal_table,
85
message::Table &create_proto,
86
70
HP_SHARE **internal_share);
88
int doRenameTable(Session&, const TableIdentifier &from, const TableIdentifier &to);
90
int doDropTable(Session&, const TableIdentifier &identifier);
92
int doGetTableDefinition(Session& session,
93
const TableIdentifier &identifier,
94
message::Table &table_message);
96
uint32_t max_supported_keys() const { return MAX_KEY; }
97
uint32_t max_supported_key_part_length() const { return MAX_KEY_LENGTH; }
99
uint32_t index_flags(enum ha_key_alg ) const
101
return ( HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR);
104
bool doDoesTableExist(Session& session, const TableIdentifier &identifier);
105
void doGetTableIdentifiers(CachedDirectory &directory,
106
const SchemaIdentifier &schema_identifier,
107
TableIdentifier::vector &set_of_identifiers);
72
int renameTableImplementation(Session*, const char * from, const char * to);
74
int deleteTableImplementation(Session *, const string table_path);
110
void HeapEngine::doGetTableIdentifiers(CachedDirectory&,
111
const SchemaIdentifier&,
112
TableIdentifier::vector&)
116
bool HeapEngine::doDoesTableExist(Session& session, const TableIdentifier &identifier)
118
return session.getMessageCache().doesTableMessageExist(identifier);
121
int HeapEngine::doGetTableDefinition(Session &session,
122
const TableIdentifier &identifier,
123
message::Table &table_proto)
125
if (session.getMessageCache().getTableMessage(identifier, table_proto))
131
We have to ignore ENOENT entries as the MEMORY table is created on open and
78
We have to ignore ENOENT entries as the HEAP table is created on open and
132
79
not when doing a CREATE on the table.
134
int HeapEngine::doDropTable(Session &session, const TableIdentifier &identifier)
81
int HeapEngine::deleteTableImplementation(Session*, const string table_path)
136
session.getMessageCache().removeTableMessage(identifier);
138
int error= heap_delete_table(identifier.getPath().c_str());
83
return heap_delete_table(table_path.c_str());
146
86
static HeapEngine *heap_storage_engine= NULL;
148
static int heap_init(module::Context &context)
88
static int heap_init(drizzled::plugin::Registry ®istry)
150
90
heap_storage_engine= new HeapEngine(engine_name);
151
context.add(heap_storage_engine);
91
registry.add(heap_storage_engine);
92
pthread_mutex_init(&THR_LOCK_heap, MY_MUTEX_INIT_FAST);
96
static int heap_deinit(drizzled::plugin::Registry ®istry)
98
registry.remove(heap_storage_engine);
99
delete heap_storage_engine;
101
int ret= hp_panic(HA_PANIC_CLOSE);
103
pthread_mutex_destroy(&THR_LOCK_heap);
156
110
/*****************************************************************************
158
112
*****************************************************************************/
160
ha_heap::ha_heap(plugin::StorageEngine &engine_arg,
162
:Cursor(engine_arg, table_arg), file(0), records_changed(0), key_stat_version(0),
114
ha_heap::ha_heap(StorageEngine *engine_arg, TableShare *table_arg)
115
:handler(engine_arg, table_arg), file(0), records_changed(0), key_stat_version(0),
163
116
internal_table(0)
167
120
Hash index statistics is updated (copied from HP_KEYDEF::hash_buckets to
168
rec_per_key) after 1/MEMORY_STATS_UPDATE_THRESHOLD fraction of table records
121
rec_per_key) after 1/HEAP_STATS_UPDATE_THRESHOLD fraction of table records
169
122
have been inserted/updated/deleted. delete_all_rows() and table flush cause
170
123
immediate update.
174
127
from 0 to non-zero value and vice versa. Otherwise records_in_range may
175
128
erroneously return 0 and 'range' may miss records.
177
#define MEMORY_STATS_UPDATE_THRESHOLD 10
130
#define HEAP_STATS_UPDATE_THRESHOLD 10
179
int ha_heap::doOpen(const drizzled::TableIdentifier &identifier, int mode, uint32_t test_if_locked)
132
int ha_heap::open(const char *name, int mode, uint32_t test_if_locked)
181
if ((test_if_locked & HA_OPEN_INTERNAL_TABLE) || (!(file= heap_open(identifier.getPath().c_str(), mode)) && errno == ENOENT))
134
if ((test_if_locked & HA_OPEN_INTERNAL_TABLE) || (!(file= heap_open(name, mode)) && my_errno == ENOENT))
136
HA_CREATE_INFO create_info;
183
137
internal_table= test(test_if_locked & HA_OPEN_INTERNAL_TABLE);
138
memset(&create_info, 0, sizeof(create_info));
185
140
HP_SHARE *internal_share= NULL;
186
message::Table create_proto;
188
if (not heap_storage_engine->heap_create_table(getTable()->in_use,
189
identifier.getPath().c_str(),
141
if (!heap_storage_engine->heap_create_table(ha_session(), name, table,
143
internal_table,&internal_share))
195
145
file= internal_table ?
196
146
heap_open_from_share(internal_share, mode) :
235
186
Do same as default implementation but use file->s->name instead of
236
table->getShare()->path. This is needed by Windows where the clone() call sees
237
'/'-delimited path in table->getShare()->path, while ha_peap::open() was called
187
table->s->path. This is needed by Windows where the clone() call sees
188
'/'-delimited path in table->s->path, while ha_peap::open() was called
238
189
with '\'-delimited path.
241
Cursor *ha_heap::clone(memory::Root *)
192
handler *ha_heap::clone(MEM_ROOT *mem_root)
243
Cursor *new_handler= getTable()->getMutableShare()->db_type()->getCursor(*getTable());
244
TableIdentifier identifier(getTable()->getShare()->getSchemaName(),
245
getTable()->getShare()->getTableName(),
246
getTable()->getShare()->getPath());
248
if (new_handler && !new_handler->ha_open(identifier, getTable()->db_stat,
194
handler *new_handler= get_new_handler(table->s, mem_root, table->s->db_type());
195
if (new_handler && !new_handler->ha_open(table, file->s->name, table->db_stat,
249
196
HA_OPEN_IGNORE_IF_LOCKED))
250
197
return new_handler;
255
const char *ha_heap::index_type(uint32_t )
198
return NULL; /* purecov: inspected */
202
const char *ha_heap::index_type(uint32_t inx)
204
return ((table_share->key_info[inx].algorithm == HA_KEY_ALG_BTREE) ?
209
uint32_t ha_heap::index_flags(uint32_t inx, uint32_t, bool) const
211
return ((table_share->key_info[inx].algorithm == HA_KEY_ALG_BTREE) ?
212
HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER | HA_READ_RANGE :
213
HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR);
304
265
records_changed= 0;
305
266
/* At the end of update_key_stats() we can proudly claim they are OK. */
306
key_stat_version= file->getShare()->key_stat_version;
267
key_stat_version= file->s->key_stat_version;
310
int ha_heap::doInsertRecord(unsigned char * buf)
271
int ha_heap::write_row(unsigned char * buf)
313
if (getTable()->next_number_field && buf == getTable()->getInsertRecord())
274
ha_statistic_increment(&SSV::ha_write_count);
275
if (table->next_number_field && buf == table->record[0])
315
277
if ((res= update_auto_increment()))
318
280
res= heap_write(file,buf);
319
if (!res && (++records_changed*MEMORY_STATS_UPDATE_THRESHOLD >
320
file->getShare()->records))
281
if (!res && (++records_changed*HEAP_STATS_UPDATE_THRESHOLD >
323
285
We can perform this safely since only one writer at the time is
324
286
allowed on the table.
326
file->getShare()->key_stat_version++;
288
file->s->key_stat_version++;
331
int ha_heap::doUpdateRecord(const unsigned char * old_data, unsigned char * new_data)
293
int ha_heap::update_row(const unsigned char * old_data, unsigned char * new_data)
296
ha_statistic_increment(&SSV::ha_update_count);
297
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
298
table->timestamp_field->set_time();
335
299
res= heap_update(file,old_data,new_data);
336
if (!res && ++records_changed*MEMORY_STATS_UPDATE_THRESHOLD >
337
file->getShare()->records)
300
if (!res && ++records_changed*HEAP_STATS_UPDATE_THRESHOLD >
340
304
We can perform this safely since only one writer at the time is
341
305
allowed on the table.
343
file->getShare()->key_stat_version++;
307
file->s->key_stat_version++;
348
int ha_heap::doDeleteRecord(const unsigned char * buf)
312
int ha_heap::delete_row(const unsigned char * buf)
315
ha_statistic_increment(&SSV::ha_delete_count);
352
316
res= heap_delete(file,buf);
353
if (!res && getTable()->getShare()->getType() == message::Table::STANDARD &&
354
++records_changed*MEMORY_STATS_UPDATE_THRESHOLD > file->getShare()->records)
317
if (!res && table->s->tmp_table == NO_TMP_TABLE &&
318
++records_changed*HEAP_STATS_UPDATE_THRESHOLD > file->s->records)
357
321
We can perform this safely since only one writer at the time is
358
322
allowed on the table.
360
file->getShare()->key_stat_version++;
324
file->s->key_stat_version++;
388
352
key_part_map keypart_map,
389
353
enum ha_rkey_function find_flag)
391
ha_statistic_increment(&system_status_var::ha_read_key_count);
355
ha_statistic_increment(&SSV::ha_read_key_count);
392
356
int error = heap_rkey(file, buf, index, key, keypart_map, find_flag);
393
getTable()->status = error ? STATUS_NOT_FOUND : 0;
357
table->status = error ? STATUS_NOT_FOUND : 0;
397
361
int ha_heap::index_next(unsigned char * buf)
399
363
assert(inited==INDEX);
400
ha_statistic_increment(&system_status_var::ha_read_next_count);
364
ha_statistic_increment(&SSV::ha_read_next_count);
401
365
int error=heap_rnext(file,buf);
402
getTable()->status=error ? STATUS_NOT_FOUND: 0;
366
table->status=error ? STATUS_NOT_FOUND: 0;
406
370
int ha_heap::index_prev(unsigned char * buf)
408
372
assert(inited==INDEX);
409
ha_statistic_increment(&system_status_var::ha_read_prev_count);
373
ha_statistic_increment(&SSV::ha_read_prev_count);
410
374
int error=heap_rprev(file,buf);
411
getTable()->status=error ? STATUS_NOT_FOUND: 0;
375
table->status=error ? STATUS_NOT_FOUND: 0;
415
379
int ha_heap::index_first(unsigned char * buf)
417
381
assert(inited==INDEX);
418
ha_statistic_increment(&system_status_var::ha_read_first_count);
382
ha_statistic_increment(&SSV::ha_read_first_count);
419
383
int error=heap_rfirst(file, buf, active_index);
420
getTable()->status=error ? STATUS_NOT_FOUND: 0;
384
table->status=error ? STATUS_NOT_FOUND: 0;
424
388
int ha_heap::index_last(unsigned char * buf)
426
390
assert(inited==INDEX);
427
ha_statistic_increment(&system_status_var::ha_read_last_count);
391
ha_statistic_increment(&SSV::ha_read_last_count);
428
392
int error=heap_rlast(file, buf, active_index);
429
getTable()->status=error ? STATUS_NOT_FOUND: 0;
393
table->status=error ? STATUS_NOT_FOUND: 0;
433
int ha_heap::doStartTableScan(bool scan)
397
int ha_heap::rnd_init(bool scan)
435
399
return scan ? heap_scan_init(file) : 0;
438
402
int ha_heap::rnd_next(unsigned char *buf)
440
ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
404
ha_statistic_increment(&SSV::ha_read_rnd_next_count);
441
405
int error=heap_scan(file, buf);
442
getTable()->status=error ? STATUS_NOT_FOUND: 0;
406
table->status=error ? STATUS_NOT_FOUND: 0;
617
596
return heap_indexes_are_disabled(file);
599
THR_LOCK_DATA **ha_heap::store_lock(Session *,
601
enum thr_lock_type lock_type)
603
if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
604
file->lock.type=lock_type;
620
609
void ha_heap::drop_table(const char *)
622
file->getShare()->delete_on_close= 1;
611
file->s->delete_on_close= 1;
627
int HeapEngine::doRenameTable(Session &session, const TableIdentifier &from, const TableIdentifier &to)
616
int HeapEngine::renameTableImplementation(Session*,
617
const char *from, const char *to)
629
session.getMessageCache().renameTableMessage(from, to);
630
return heap_rename(from.getPath().c_str(), to.getPath().c_str());
619
return heap_rename(from,to);
634
623
ha_rows ha_heap::records_in_range(uint32_t inx, key_range *min_key,
635
624
key_range *max_key)
637
KeyInfo *key= &getTable()->key_info[inx];
626
KEY *key=table->key_info+inx;
627
if (key->algorithm == HA_KEY_ALG_BTREE)
628
return hp_rb_records_in_range(file, inx, min_key, max_key);
639
630
if (!min_key || !max_key ||
640
631
min_key->length != max_key->length ||
647
638
return stats.records;
649
640
/* Assert that info() did run. We need current statistics here. */
650
assert(key_stat_version == file->getShare()->key_stat_version);
641
assert(key_stat_version == file->s->key_stat_version);
651
642
return key->rec_per_key[key->key_parts-1];
654
int HeapEngine::doCreateTable(Session &session,
656
const TableIdentifier &identifier,
657
message::Table& create_proto)
645
int HeapEngine::createTableImplementation(Session *session,
646
const char *table_name,
648
HA_CREATE_INFO *create_info,
649
drizzled::message::Table*)
660
651
HP_SHARE *internal_share;
661
const char *table_name= identifier.getPath().c_str();
663
error= heap_create_table(&session, table_name, &table_arg,
670
session.getMessageCache().storeTableMessage(identifier, create_proto);
652
return heap_create_table(session, table_name, table_arg, create_info,
653
false, &internal_share);
677
657
int HeapEngine::heap_create_table(Session *session, const char *table_name,
680
message::Table &create_proto,
681
HP_SHARE **internal_share)
658
Table *table_arg, HA_CREATE_INFO *create_info,
659
bool internal_table, HP_SHARE **internal_share)
683
uint32_t key, parts, mem_per_row_keys= 0;
684
uint32_t keys= table_arg->getShare()->sizeKeys();
661
uint32_t key, parts, mem_per_row_keys= 0, keys= table_arg->s->keys;
685
662
uint32_t auto_key= 0, auto_key_type= 0;
686
663
uint32_t max_key_fieldnr = 0, key_part_size = 0, next_field_pos = 0;
687
uint32_t column_count= table_arg->getShare()->sizeFields();
688
std::vector<HP_KEYDEF> keydef;
664
uint32_t column_idx, column_count= table_arg->s->fields;
665
HP_COLUMNDEF *columndef;
668
char buff[FN_REFLEN];
670
TableShare *share= table_arg->s;
690
671
bool found_real_auto_increment= 0;
695
676
* can return a number more than that, we trap it here instead of casting
696
677
* to a truncated integer.
698
uint64_t num_rows= table_arg->getShare()->getMaxRows();
679
uint64_t num_rows= share->getMaxRows();
699
680
if (num_rows > UINT32_MAX)
683
if (!(columndef= (HP_COLUMNDEF*) malloc(column_count * sizeof(HP_COLUMNDEF))))
686
for (column_idx= 0; column_idx < column_count; column_idx++)
688
Field* field= *(table_arg->field + column_idx);
689
HP_COLUMNDEF* column= columndef + column_idx;
690
column->type= (uint16_t)field->type();
691
column->length= field->pack_length();
692
column->offset= field->offset(field->table->record[0]);
696
column->null_bit= field->null_bit;
697
column->null_pos= (uint) (field->null_ptr - (unsigned char*) table_arg->record[0]);
705
if (field->type() == DRIZZLE_TYPE_VARCHAR)
707
column->length_bytes= (uint8_t)(((Field_varstring*)field)->length_bytes);
711
column->length_bytes= 0;
702
715
for (key= parts= 0; key < keys; key++)
703
716
parts+= table_arg->key_info[key].key_parts;
706
std::vector<HA_KEYSEG> seg_buffer;
707
seg_buffer.resize(parts);
708
HA_KEYSEG *seg= &seg_buffer[0];
718
if (!(keydef= (HP_KEYDEF*) malloc(keys * sizeof(HP_KEYDEF) +
719
parts * sizeof(HA_KEYSEG))))
721
free((void *) columndef);
725
seg= reinterpret_cast<HA_KEYSEG*> (keydef + keys);
710
726
for (key= 0; key < keys; key++)
712
KeyInfo *pos= &table_arg->key_info[key];
713
KeyPartInfo *key_part= pos->key_part;
714
KeyPartInfo *key_part_end= key_part + pos->key_parts;
728
KEY *pos= table_arg->key_info+key;
729
KEY_PART_INFO *key_part= pos->key_part;
730
KEY_PART_INFO *key_part_end= key_part + pos->key_parts;
716
732
keydef[key].keysegs= (uint) pos->key_parts;
717
733
keydef[key].flag= (pos->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL));
718
734
keydef[key].seg= seg;
720
mem_per_row_keys+= sizeof(char*) * 2; // = sizeof(HASH_INFO)
736
switch (pos->algorithm) {
737
case HA_KEY_ALG_UNDEF:
738
case HA_KEY_ALG_HASH:
739
keydef[key].algorithm= HA_KEY_ALG_HASH;
740
mem_per_row_keys+= sizeof(char*) * 2; // = sizeof(HASH_INFO)
742
case HA_KEY_ALG_BTREE:
743
keydef[key].algorithm= HA_KEY_ALG_BTREE;
744
mem_per_row_keys+=sizeof(TREE_ELEMENT)+pos->key_length+sizeof(char*);
747
assert(0); // cannot happen
722
750
for (; key_part != key_part_end; key_part++, seg++)
724
752
Field *field= key_part->field;
754
if (pos->algorithm == HA_KEY_ALG_BTREE)
755
seg->type= field->key_type();
727
758
if ((seg->type = field->key_type()) != (int) HA_KEYTYPE_TEXT &&
728
759
seg->type != HA_KEYTYPE_VARTEXT1 &&
770
801
auto_key= key+ 1;
771
802
auto_key_type= field->key_type();
773
if ((uint)field->position() + 1 > max_key_fieldnr)
804
if ((uint)field->field_index + 1 > max_key_fieldnr)
775
806
/* Do not use seg->fieldnr as it's not reliable in case of temp tables */
776
max_key_fieldnr= field->position() + 1;
807
max_key_fieldnr= field->field_index + 1;
781
if (key_part_size < table_arg->getShare()->null_bytes + ((table_arg->getShare()->last_null_bit_pos+7) >> 3))
812
if (key_part_size < share->null_bytes + ((share->last_null_bit_pos+7) >> 3))
783
814
/* Make sure to include null fields regardless of the presense of keys */
784
key_part_size = table_arg->getShare()->null_bytes + ((table_arg->getShare()->last_null_bit_pos+7) >> 3);
815
key_part_size = share->null_bytes + ((share->last_null_bit_pos+7) >> 3);
789
820
if (table_arg->found_next_number_field)
791
keydef[table_arg->getShare()->next_number_index].flag|= HA_AUTO_KEY;
792
found_real_auto_increment= table_arg->getShare()->next_number_key_offset == 0;
822
keydef[share->next_number_index].flag|= HA_AUTO_KEY;
823
found_real_auto_increment= share->next_number_key_offset == 0;
794
825
HP_CREATE_INFO hp_create_info;
795
826
hp_create_info.auto_key= auto_key;
796
827
hp_create_info.auto_key_type= auto_key_type;
797
hp_create_info.auto_increment= (create_proto.options().has_auto_increment_value() ?
798
create_proto.options().auto_increment_value() - 1 : 0);
828
hp_create_info.auto_increment= (create_info->auto_increment_value ?
829
create_info->auto_increment_value - 1 : 0);
799
830
hp_create_info.max_table_size=session->variables.max_heap_table_size;
800
831
hp_create_info.with_auto_increment= found_real_auto_increment;
801
832
hp_create_info.internal_table= internal_table;
802
hp_create_info.max_chunk_size= table_arg->getShare()->block_size;
804
error= heap_create(table_name,
808
table_arg->getShare()->getRecordLength(), mem_per_row_keys,
809
static_cast<uint32_t>(num_rows), /* We check for overflow above, so cast is fine here. */
811
&hp_create_info, internal_share);
833
hp_create_info.max_chunk_size= share->block_size;
834
hp_create_info.is_dynamic= (share->row_type == ROW_TYPE_DYNAMIC);
836
error= heap_create(fn_format(buff,table_name,"","",
837
MY_REPLACE_EXT|MY_UNPACK_FILENAME),
839
column_count, columndef,
840
max_key_fieldnr, key_part_size,
841
share->reclength, mem_per_row_keys,
842
static_cast<uint32_t>(num_rows), /* We check for overflow above, so cast is fine here. */
844
&hp_create_info, internal_share);
846
free((unsigned char*) keydef);
847
free((void *) columndef);