1
/* Copyright (C) 2000-2006 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
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 */
16
#include "heap_priv.h"
17
#include <drizzled/error.h>
18
#include <drizzled/table.h>
19
#include <drizzled/session.h>
20
#include <drizzled/field/timestamp.h>
21
#include <drizzled/field/varstring.h>
22
#include "drizzled/plugin/daemon.h"
24
#include <boost/thread/mutex.hpp>
32
using namespace drizzled;
35
static const string engine_name("MEMORY");
37
boost::mutex THR_LOCK_heap;
39
static const char *ha_heap_exts[] = {
43
class HeapEngine : public plugin::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);
68
const char **bas_ext() const {
72
int doCreateTable(Session &session,
74
const TableIdentifier &identifier,
75
message::Table &create_proto);
77
/* For whatever reason, internal tables can be created by Cursor::open()
79
Instead of diving down a rat hole, let's just cry ourselves to sleep
80
at night with this odd hackish workaround.
82
int heap_create_table(Session *session, const char *table_name,
85
message::Table &create_proto,
86
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);
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
132
not when doing a CREATE on the table.
134
int HeapEngine::doDropTable(Session &session, const TableIdentifier &identifier)
136
session.getMessageCache().removeTableMessage(identifier);
138
int error= heap_delete_table(identifier.getPath().c_str());
146
static HeapEngine *heap_storage_engine= NULL;
148
static int heap_init(module::Context &context)
150
heap_storage_engine= new HeapEngine(engine_name);
151
context.add(heap_storage_engine);
156
/*****************************************************************************
158
*****************************************************************************/
160
ha_heap::ha_heap(plugin::StorageEngine &engine_arg,
162
:Cursor(engine_arg, table_arg), file(0), records_changed(0), key_stat_version(0),
167
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
169
have been inserted/updated/deleted. delete_all_rows() and table flush cause
173
hash index statistics must be updated when number of table records changes
174
from 0 to non-zero value and vice versa. Otherwise records_in_range may
175
erroneously return 0 and 'range' may miss records.
177
#define MEMORY_STATS_UPDATE_THRESHOLD 10
179
int ha_heap::doOpen(const drizzled::TableIdentifier &identifier, 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))
183
internal_table= test(test_if_locked & HA_OPEN_INTERNAL_TABLE);
185
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(),
195
file= internal_table ?
196
heap_open_from_share(internal_share, mode) :
197
heap_open_from_share_and_register(internal_share, mode);
200
/* Couldn't open table; Remove the newly created table */
201
THR_LOCK_heap.lock();
202
hp_free(internal_share);
203
THR_LOCK_heap.unlock();
207
ref_length= sizeof(HEAP_PTR);
210
/* Initialize variables for the opened table */
211
set_keys_for_scanning();
213
We cannot run update_key_stats() here because we do not have a
214
lock on the table. The 'records' count might just be changed
215
temporarily at this moment and we might get wrong statistics (Bug
216
#10178). Instead we request for update. This will be done in
217
ha_heap::info(), which is always called before key statistics are
220
key_stat_version= file->getShare()->key_stat_version - 1;
222
return (file ? 0 : 1);
225
int ha_heap::close(void)
227
return internal_table ? hp_close(file) : heap_close(file);
232
Create a copy of this table
235
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
238
with '\'-delimited path.
241
Cursor *ha_heap::clone(memory::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,
249
HA_OPEN_IGNORE_IF_LOCKED))
255
const char *ha_heap::index_type(uint32_t )
262
Compute which keys to use for scanning
265
set_keys_for_scanning()
269
Set the bitmap btree_keys, which is used when the upper layers ask
270
which keys to use for scanning. For each btree index the
271
corresponding bit is set.
277
void ha_heap::set_keys_for_scanning(void)
282
void ha_heap::update_key_stats()
284
for (uint32_t i= 0; i < getTable()->getShare()->sizeKeys(); i++)
286
KeyInfo *key= &getTable()->key_info[i];
288
if (!key->rec_per_key)
292
if (key->flags & HA_NOSAME)
293
key->rec_per_key[key->key_parts-1]= 1;
296
ha_rows hash_buckets= file->getShare()->keydef[i].hash_buckets;
297
uint32_t no_records= hash_buckets ? (uint) (file->getShare()->records/hash_buckets) : 2;
300
key->rec_per_key[key->key_parts-1]= no_records;
305
/* At the end of update_key_stats() we can proudly claim they are OK. */
306
key_stat_version= file->getShare()->key_stat_version;
310
int ha_heap::doInsertRecord(unsigned char * buf)
313
if (getTable()->next_number_field && buf == getTable()->getInsertRecord())
315
if ((res= update_auto_increment()))
318
res= heap_write(file,buf);
319
if (!res && (++records_changed*MEMORY_STATS_UPDATE_THRESHOLD >
320
file->getShare()->records))
323
We can perform this safely since only one writer at the time is
324
allowed on the table.
326
file->getShare()->key_stat_version++;
331
int ha_heap::doUpdateRecord(const unsigned char * old_data, unsigned char * new_data)
335
res= heap_update(file,old_data,new_data);
336
if (!res && ++records_changed*MEMORY_STATS_UPDATE_THRESHOLD >
337
file->getShare()->records)
340
We can perform this safely since only one writer at the time is
341
allowed on the table.
343
file->getShare()->key_stat_version++;
348
int ha_heap::doDeleteRecord(const unsigned char * buf)
352
res= heap_delete(file,buf);
353
if (!res && getTable()->getShare()->getType() == message::Table::STANDARD &&
354
++records_changed*MEMORY_STATS_UPDATE_THRESHOLD > file->getShare()->records)
357
We can perform this safely since only one writer at the time is
358
allowed on the table.
360
file->getShare()->key_stat_version++;
365
int ha_heap::index_read_map(unsigned char *buf, const unsigned char *key,
366
key_part_map keypart_map,
367
enum ha_rkey_function find_flag)
369
assert(inited==INDEX);
370
ha_statistic_increment(&system_status_var::ha_read_key_count);
371
int error = heap_rkey(file,buf,active_index, key, keypart_map, find_flag);
372
getTable()->status = error ? STATUS_NOT_FOUND : 0;
376
int ha_heap::index_read_last_map(unsigned char *buf, const unsigned char *key,
377
key_part_map keypart_map)
379
assert(inited==INDEX);
380
ha_statistic_increment(&system_status_var::ha_read_key_count);
381
int error= heap_rkey(file, buf, active_index, key, keypart_map,
382
HA_READ_PREFIX_LAST);
383
getTable()->status= error ? STATUS_NOT_FOUND : 0;
387
int ha_heap::index_read_idx_map(unsigned char *buf, uint32_t index, const unsigned char *key,
388
key_part_map keypart_map,
389
enum ha_rkey_function find_flag)
391
ha_statistic_increment(&system_status_var::ha_read_key_count);
392
int error = heap_rkey(file, buf, index, key, keypart_map, find_flag);
393
getTable()->status = error ? STATUS_NOT_FOUND : 0;
397
int ha_heap::index_next(unsigned char * buf)
399
assert(inited==INDEX);
400
ha_statistic_increment(&system_status_var::ha_read_next_count);
401
int error=heap_rnext(file,buf);
402
getTable()->status=error ? STATUS_NOT_FOUND: 0;
406
int ha_heap::index_prev(unsigned char * buf)
408
assert(inited==INDEX);
409
ha_statistic_increment(&system_status_var::ha_read_prev_count);
410
int error=heap_rprev(file,buf);
411
getTable()->status=error ? STATUS_NOT_FOUND: 0;
415
int ha_heap::index_first(unsigned char * buf)
417
assert(inited==INDEX);
418
ha_statistic_increment(&system_status_var::ha_read_first_count);
419
int error=heap_rfirst(file, buf, active_index);
420
getTable()->status=error ? STATUS_NOT_FOUND: 0;
424
int ha_heap::index_last(unsigned char * buf)
426
assert(inited==INDEX);
427
ha_statistic_increment(&system_status_var::ha_read_last_count);
428
int error=heap_rlast(file, buf, active_index);
429
getTable()->status=error ? STATUS_NOT_FOUND: 0;
433
int ha_heap::doStartTableScan(bool scan)
435
return scan ? heap_scan_init(file) : 0;
438
int ha_heap::rnd_next(unsigned char *buf)
440
ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
441
int error=heap_scan(file, buf);
442
getTable()->status=error ? STATUS_NOT_FOUND: 0;
446
int ha_heap::rnd_pos(unsigned char * buf, unsigned char *pos)
449
HEAP_PTR heap_position;
450
ha_statistic_increment(&system_status_var::ha_read_rnd_count);
451
memcpy(&heap_position, pos, sizeof(HEAP_PTR));
452
error=heap_rrnd(file, buf, heap_position);
453
getTable()->status=error ? STATUS_NOT_FOUND: 0;
457
void ha_heap::position(const unsigned char *)
459
*(HEAP_PTR*) ref= heap_position(file); // Ref is aligned
462
int ha_heap::info(uint32_t flag)
465
(void) heap_info(file,&hp_info,flag);
467
errkey= hp_info.errkey;
468
stats.records= hp_info.records;
469
stats.deleted= hp_info.deleted;
470
stats.mean_rec_length= hp_info.reclength;
471
stats.data_file_length= hp_info.data_length;
472
stats.index_file_length= hp_info.index_length;
473
stats.max_data_file_length= hp_info.max_records * hp_info.reclength;
474
stats.delete_length= hp_info.deleted * hp_info.reclength;
475
if (flag & HA_STATUS_AUTO)
476
stats.auto_increment_value= hp_info.auto_increment;
478
If info() is called for the first time after open(), we will still
479
have to update the key statistics. Hoping that a table lock is now
482
if (key_stat_version != file->getShare()->key_stat_version)
487
int ha_heap::extra(enum ha_extra_function operation)
489
return heap_extra(file,operation);
495
return heap_reset(file);
499
int ha_heap::delete_all_rows()
502
if (getTable()->getShare()->getType() == message::Table::STANDARD)
505
We can perform this safely since only one writer at the time is
506
allowed on the table.
508
file->getShare()->key_stat_version++;
518
mode mode of operation:
519
HA_KEY_SWITCH_NONUNIQ disable all non-unique keys
520
HA_KEY_SWITCH_ALL disable all keys
521
HA_KEY_SWITCH_NONUNIQ_SAVE dis. non-uni. and make persistent
522
HA_KEY_SWITCH_ALL_SAVE dis. all keys and make persistent
525
Disable indexes and clear keys to use for scanning.
528
HA_KEY_SWITCH_NONUNIQ is not implemented.
529
HA_KEY_SWITCH_NONUNIQ_SAVE is not implemented with HEAP.
530
HA_KEY_SWITCH_ALL_SAVE is not implemented with HEAP.
534
HA_ERR_WRONG_COMMAND mode not implemented.
537
int ha_heap::disable_indexes(uint32_t mode)
541
if (mode == HA_KEY_SWITCH_ALL)
543
if (!(error= heap_disable_indexes(file)))
544
set_keys_for_scanning();
548
/* mode not implemented */
549
error= HA_ERR_WRONG_COMMAND;
560
mode mode of operation:
561
HA_KEY_SWITCH_NONUNIQ enable all non-unique keys
562
HA_KEY_SWITCH_ALL enable all keys
563
HA_KEY_SWITCH_NONUNIQ_SAVE en. non-uni. and make persistent
564
HA_KEY_SWITCH_ALL_SAVE en. all keys and make persistent
567
Enable indexes and set keys to use for scanning.
568
The indexes might have been disabled by disable_index() before.
569
The function works only if both data and indexes are empty,
570
since the heap storage engine cannot repair the indexes.
571
To be sure, call Cursor::delete_all_rows() before.
574
HA_KEY_SWITCH_NONUNIQ is not implemented.
575
HA_KEY_SWITCH_NONUNIQ_SAVE is not implemented with HEAP.
576
HA_KEY_SWITCH_ALL_SAVE is not implemented with HEAP.
580
HA_ERR_CRASHED data or index is non-empty. Delete all rows and retry.
581
HA_ERR_WRONG_COMMAND mode not implemented.
584
int ha_heap::enable_indexes(uint32_t mode)
588
if (mode == HA_KEY_SWITCH_ALL)
590
if (!(error= heap_enable_indexes(file)))
591
set_keys_for_scanning();
595
/* mode not implemented */
596
error= HA_ERR_WRONG_COMMAND;
603
Test if indexes are disabled.
606
indexes_are_disabled()
610
0 indexes are not disabled
611
1 all indexes are disabled
612
[2 non-unique indexes are disabled - NOT YET IMPLEMENTED]
615
int ha_heap::indexes_are_disabled(void)
617
return heap_indexes_are_disabled(file);
620
void ha_heap::drop_table(const char *)
622
file->getShare()->delete_on_close= 1;
627
int HeapEngine::doRenameTable(Session &session, const TableIdentifier &from, const TableIdentifier &to)
629
session.getMessageCache().renameTableMessage(from, to);
630
return heap_rename(from.getPath().c_str(), to.getPath().c_str());
634
ha_rows ha_heap::records_in_range(uint32_t inx, key_range *min_key,
637
KeyInfo *key= &getTable()->key_info[inx];
639
if (!min_key || !max_key ||
640
min_key->length != max_key->length ||
641
min_key->length != key->key_length ||
642
min_key->flag != HA_READ_KEY_EXACT ||
643
max_key->flag != HA_READ_AFTER_KEY)
644
return HA_POS_ERROR; // Can only use exact keys
646
if (stats.records <= 1)
647
return stats.records;
649
/* Assert that info() did run. We need current statistics here. */
650
assert(key_stat_version == file->getShare()->key_stat_version);
651
return key->rec_per_key[key->key_parts-1];
654
int HeapEngine::doCreateTable(Session &session,
656
const TableIdentifier &identifier,
657
message::Table& create_proto)
660
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);
677
int HeapEngine::heap_create_table(Session *session, const char *table_name,
680
message::Table &create_proto,
681
HP_SHARE **internal_share)
683
uint32_t key, parts, mem_per_row_keys= 0;
684
uint32_t keys= table_arg->getShare()->sizeKeys();
685
uint32_t auto_key= 0, auto_key_type= 0;
686
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;
690
bool found_real_auto_increment= 0;
693
* We cannot create tables with more rows than UINT32_MAX. This is a
694
* limitation of the HEAP engine. Here, since TableShare::getMaxRows()
695
* can return a number more than that, we trap it here instead of casting
696
* to a truncated integer.
698
uint64_t num_rows= table_arg->getShare()->getMaxRows();
699
if (num_rows > UINT32_MAX)
702
for (key= parts= 0; key < keys; key++)
703
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];
710
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;
716
keydef[key].keysegs= (uint) pos->key_parts;
717
keydef[key].flag= (pos->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL));
718
keydef[key].seg= seg;
720
mem_per_row_keys+= sizeof(char*) * 2; // = sizeof(HASH_INFO)
722
for (; key_part != key_part_end; key_part++, seg++)
724
Field *field= key_part->field;
727
if ((seg->type = field->key_type()) != (int) HA_KEYTYPE_TEXT &&
728
seg->type != HA_KEYTYPE_VARTEXT1 &&
729
seg->type != HA_KEYTYPE_VARTEXT2 &&
730
seg->type != HA_KEYTYPE_VARBINARY1 &&
731
seg->type != HA_KEYTYPE_VARBINARY2)
732
seg->type= HA_KEYTYPE_BINARY;
734
seg->start= (uint) key_part->offset;
735
seg->length= (uint) key_part->length;
736
seg->flag= key_part->key_part_flag;
738
next_field_pos= seg->start + seg->length;
739
if (field->type() == DRIZZLE_TYPE_VARCHAR)
741
next_field_pos+= (uint8_t)(((Field_varstring*)field)->pack_length_no_ptr());
744
if (next_field_pos > key_part_size) {
745
key_part_size= next_field_pos;
748
if (field->flags & ENUM_FLAG)
749
seg->charset= &my_charset_bin;
751
seg->charset= field->charset();
754
seg->null_bit= field->null_bit;
755
seg->null_pos= (uint) (field->null_ptr - (unsigned char*) table_arg->getInsertRecord());
762
if (field->flags & AUTO_INCREMENT_FLAG &&
763
table_arg->found_next_number_field &&
764
key == table_arg->getShare()->next_number_index)
767
Store key number and type for found auto_increment key
768
We have to store type as seg->type can differ from it
771
auto_key_type= field->key_type();
773
if ((uint)field->position() + 1 > max_key_fieldnr)
775
/* Do not use seg->fieldnr as it's not reliable in case of temp tables */
776
max_key_fieldnr= field->position() + 1;
781
if (key_part_size < table_arg->getShare()->null_bytes + ((table_arg->getShare()->last_null_bit_pos+7) >> 3))
783
/* 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);
789
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;
794
HP_CREATE_INFO hp_create_info;
795
hp_create_info.auto_key= auto_key;
796
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);
799
hp_create_info.max_table_size=session->variables.max_heap_table_size;
800
hp_create_info.with_auto_increment= found_real_auto_increment;
801
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);
817
void ha_heap::get_auto_increment(uint64_t, uint64_t, uint64_t,
818
uint64_t *first_value,
819
uint64_t *nb_reserved_values)
821
ha_heap::info(HA_STATUS_AUTO);
822
*first_value= stats.auto_increment_value;
823
/* such table has only table-level locking so reserves up to +inf */
824
*nb_reserved_values= UINT64_MAX;
828
int ha_heap::cmp_ref(const unsigned char *ref1, const unsigned char *ref2)
830
return memcmp(ref1, ref2, sizeof(HEAP_PTR));
834
DRIZZLE_DECLARE_PLUGIN
840
"Hash based, stored in memory, useful for temporary tables",
843
NULL, /* system variables */
844
NULL /* config options */
846
DRIZZLE_DECLARE_PLUGIN_END;