00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "heap_priv.h"
00017 #include <drizzled/error.h>
00018 #include <drizzled/table.h>
00019 #include <drizzled/session.h>
00020 #include <drizzled/field/varstring.h>
00021 #include <drizzled/plugin/daemon.h>
00022 #include <drizzled/plugin/storage_engine.h>
00023
00024 #include <boost/thread/mutex.hpp>
00025
00026 #include "heap.h"
00027 #include "ha_heap.h"
00028
00029 #include <string>
00030
00031
00032 using namespace drizzled;
00033 using namespace std;
00034
00035 static const string engine_name("MEMORY");
00036
00037 boost::mutex THR_LOCK_heap;
00038
00039 static const char *ha_heap_exts[] = {
00040 NULL
00041 };
00042
00043 class HeapEngine : public plugin::StorageEngine
00044 {
00045 public:
00046 explicit HeapEngine(string name_arg) :
00047 plugin::StorageEngine(name_arg,
00048 HTON_STATS_RECORDS_IS_EXACT |
00049 HTON_NULL_IN_KEY |
00050 HTON_FAST_KEY_READ |
00051 HTON_NO_BLOBS |
00052 HTON_HAS_RECORDS |
00053 HTON_SKIP_STORE_LOCK |
00054 HTON_TEMPORARY_ONLY)
00055 {
00056 }
00057
00058 virtual ~HeapEngine()
00059 {
00060 hp_panic(HA_PANIC_CLOSE);
00061 }
00062
00063 virtual Cursor *create(Table &table)
00064 {
00065 return new ha_heap(*this, table);
00066 }
00067
00068 const char **bas_ext() const {
00069 return ha_heap_exts;
00070 }
00071
00072 int doCreateTable(Session &session,
00073 Table &table_arg,
00074 const identifier::Table &identifier,
00075 const message::Table &create_proto);
00076
00077
00078
00079
00080
00081
00082 int heap_create_table(Session *session, const char *table_name,
00083 Table *table_arg,
00084 bool internal_table,
00085 const message::Table &create_proto,
00086 HP_SHARE **internal_share);
00087
00088 int doRenameTable(Session&, const identifier::Table &from, const identifier::Table &to);
00089
00090 int doDropTable(Session&, const identifier::Table &identifier);
00091
00092 int doGetTableDefinition(Session& session,
00093 const identifier::Table &identifier,
00094 message::Table &table_message);
00095
00096 uint32_t max_supported_keys() const { return MAX_KEY; }
00097 uint32_t max_supported_key_part_length() const { return MAX_KEY_LENGTH; }
00098
00099 uint32_t index_flags(enum ha_key_alg ) const
00100 {
00101 return ( HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR);
00102 }
00103
00104 bool doDoesTableExist(Session& session, const identifier::Table &identifier);
00105 void doGetTableIdentifiers(CachedDirectory &directory,
00106 const identifier::Schema &schema_identifier,
00107 identifier::Table::vector &set_of_identifiers);
00108 };
00109
00110 void HeapEngine::doGetTableIdentifiers(CachedDirectory&,
00111 const identifier::Schema&,
00112 identifier::Table::vector&)
00113 {
00114 }
00115
00116 bool HeapEngine::doDoesTableExist(Session& session, const identifier::Table &identifier)
00117 {
00118 return session.getMessageCache().doesTableMessageExist(identifier);
00119 }
00120
00121 int HeapEngine::doGetTableDefinition(Session &session,
00122 const identifier::Table &identifier,
00123 message::Table &table_proto)
00124 {
00125 if (session.getMessageCache().getTableMessage(identifier, table_proto))
00126 return EEXIST;
00127
00128 return ENOENT;
00129 }
00130
00131
00132
00133
00134 int HeapEngine::doDropTable(Session &session, const identifier::Table &identifier)
00135 {
00136 session.getMessageCache().removeTableMessage(identifier);
00137
00138 int error= heap_delete_table(identifier.getPath().c_str());
00139
00140 if (error == ENOENT)
00141 error= 0;
00142
00143 return error;
00144 }
00145
00146 static HeapEngine *heap_storage_engine= NULL;
00147
00148 static int heap_init(module::Context &context)
00149 {
00150 heap_storage_engine= new HeapEngine(engine_name);
00151 context.add(heap_storage_engine);
00152 return 0;
00153 }
00154
00155
00156
00157
00158
00159
00160 ha_heap::ha_heap(plugin::StorageEngine &engine_arg,
00161 Table &table_arg)
00162 :Cursor(engine_arg, table_arg), file(0), records_changed(0), key_stat_version(0),
00163 internal_table(0)
00164 {}
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177 #define MEMORY_STATS_UPDATE_THRESHOLD 10
00178
00179 int ha_heap::doOpen(const drizzled::identifier::Table &identifier, int mode, uint32_t test_if_locked)
00180 {
00181 if ((test_if_locked & HA_OPEN_INTERNAL_TABLE) || (!(file= heap_open(identifier.getPath().c_str(), mode)) && errno == ENOENT))
00182 {
00183 internal_table= test(test_if_locked & HA_OPEN_INTERNAL_TABLE);
00184 file= 0;
00185 HP_SHARE *internal_share= NULL;
00186 message::Table create_proto;
00187
00188 if (not heap_storage_engine->heap_create_table(getTable()->in_use,
00189 identifier.getPath().c_str(),
00190 getTable(),
00191 internal_table,
00192 create_proto,
00193 &internal_share))
00194 {
00195 file= internal_table ?
00196 heap_open_from_share(internal_share, mode) :
00197 heap_open_from_share_and_register(internal_share, mode);
00198 if (!file)
00199 {
00200
00201 THR_LOCK_heap.lock();
00202 hp_free(internal_share);
00203 THR_LOCK_heap.unlock();
00204 }
00205 }
00206 }
00207 ref_length= sizeof(HEAP_PTR);
00208 if (file)
00209 {
00210
00211 set_keys_for_scanning();
00212
00213
00214
00215
00216
00217
00218
00219
00220 key_stat_version= file->getShare()->key_stat_version - 1;
00221 }
00222 return (file ? 0 : 1);
00223 }
00224
00225 int ha_heap::close(void)
00226 {
00227 return internal_table ? hp_close(file) : heap_close(file);
00228 }
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241 Cursor *ha_heap::clone(memory::Root *)
00242 {
00243 Cursor *new_handler= getTable()->getMutableShare()->db_type()->getCursor(*getTable());
00244 identifier::Table identifier(getTable()->getShare()->getSchemaName(),
00245 getTable()->getShare()->getTableName(),
00246 getTable()->getShare()->getPath());
00247
00248 if (new_handler && !new_handler->ha_open(identifier, getTable()->db_stat,
00249 HA_OPEN_IGNORE_IF_LOCKED))
00250 return new_handler;
00251 return NULL;
00252 }
00253
00254
00255 const char *ha_heap::index_type(uint32_t )
00256 {
00257 return ("HASH");
00258 }
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277 void ha_heap::set_keys_for_scanning(void)
00278 {
00279 }
00280
00281
00282 void ha_heap::update_key_stats()
00283 {
00284 for (uint32_t i= 0; i < getTable()->getShare()->sizeKeys(); i++)
00285 {
00286 KeyInfo *key= &getTable()->key_info[i];
00287
00288 if (!key->rec_per_key)
00289 continue;
00290
00291 {
00292 if (key->flags & HA_NOSAME)
00293 key->rec_per_key[key->key_parts-1]= 1;
00294 else
00295 {
00296 ha_rows hash_buckets= file->getShare()->keydef[i].hash_buckets;
00297 uint32_t no_records= hash_buckets ? (uint) (file->getShare()->records/hash_buckets) : 2;
00298 if (no_records < 2)
00299 no_records= 2;
00300 key->rec_per_key[key->key_parts-1]= no_records;
00301 }
00302 }
00303 }
00304 records_changed= 0;
00305
00306 key_stat_version= file->getShare()->key_stat_version;
00307 }
00308
00309
00310 int ha_heap::doInsertRecord(unsigned char * buf)
00311 {
00312 int res;
00313 if (getTable()->next_number_field && buf == getTable()->getInsertRecord())
00314 {
00315 if ((res= update_auto_increment()))
00316 return res;
00317 }
00318 res= heap_write(file,buf);
00319 if (!res && (++records_changed*MEMORY_STATS_UPDATE_THRESHOLD >
00320 file->getShare()->records))
00321 {
00322
00323
00324
00325
00326 file->getShare()->key_stat_version++;
00327 }
00328 return res;
00329 }
00330
00331 int ha_heap::doUpdateRecord(const unsigned char * old_data, unsigned char * new_data)
00332 {
00333 int res;
00334
00335 res= heap_update(file,old_data,new_data);
00336 if (!res && ++records_changed*MEMORY_STATS_UPDATE_THRESHOLD >
00337 file->getShare()->records)
00338 {
00339
00340
00341
00342
00343 file->getShare()->key_stat_version++;
00344 }
00345 return res;
00346 }
00347
00348 int ha_heap::doDeleteRecord(const unsigned char * buf)
00349 {
00350 int res;
00351
00352 res= heap_delete(file,buf);
00353 if (!res && getTable()->getShare()->getType() == message::Table::STANDARD &&
00354 ++records_changed*MEMORY_STATS_UPDATE_THRESHOLD > file->getShare()->records)
00355 {
00356
00357
00358
00359
00360 file->getShare()->key_stat_version++;
00361 }
00362 return res;
00363 }
00364
00365 int ha_heap::index_read_map(unsigned char *buf, const unsigned char *key,
00366 key_part_map keypart_map,
00367 enum ha_rkey_function find_flag)
00368 {
00369 assert(inited==INDEX);
00370 ha_statistic_increment(&system_status_var::ha_read_key_count);
00371 int error = heap_rkey(file,buf,active_index, key, keypart_map, find_flag);
00372 getTable()->status = error ? STATUS_NOT_FOUND : 0;
00373 return error;
00374 }
00375
00376 int ha_heap::index_read_last_map(unsigned char *buf, const unsigned char *key,
00377 key_part_map keypart_map)
00378 {
00379 assert(inited==INDEX);
00380 ha_statistic_increment(&system_status_var::ha_read_key_count);
00381 int error= heap_rkey(file, buf, active_index, key, keypart_map,
00382 HA_READ_PREFIX_LAST);
00383 getTable()->status= error ? STATUS_NOT_FOUND : 0;
00384 return error;
00385 }
00386
00387 int ha_heap::index_read_idx_map(unsigned char *buf, uint32_t index, const unsigned char *key,
00388 key_part_map keypart_map,
00389 enum ha_rkey_function find_flag)
00390 {
00391 ha_statistic_increment(&system_status_var::ha_read_key_count);
00392 int error = heap_rkey(file, buf, index, key, keypart_map, find_flag);
00393 getTable()->status = error ? STATUS_NOT_FOUND : 0;
00394 return error;
00395 }
00396
00397 int ha_heap::index_next(unsigned char * buf)
00398 {
00399 assert(inited==INDEX);
00400 ha_statistic_increment(&system_status_var::ha_read_next_count);
00401 int error=heap_rnext(file,buf);
00402 getTable()->status=error ? STATUS_NOT_FOUND: 0;
00403 return error;
00404 }
00405
00406 int ha_heap::index_prev(unsigned char * buf)
00407 {
00408 assert(inited==INDEX);
00409 ha_statistic_increment(&system_status_var::ha_read_prev_count);
00410 int error=heap_rprev(file,buf);
00411 getTable()->status=error ? STATUS_NOT_FOUND: 0;
00412 return error;
00413 }
00414
00415 int ha_heap::index_first(unsigned char * buf)
00416 {
00417 assert(inited==INDEX);
00418 ha_statistic_increment(&system_status_var::ha_read_first_count);
00419 int error=heap_rfirst(file, buf, active_index);
00420 getTable()->status=error ? STATUS_NOT_FOUND: 0;
00421 return error;
00422 }
00423
00424 int ha_heap::index_last(unsigned char * buf)
00425 {
00426 assert(inited==INDEX);
00427 ha_statistic_increment(&system_status_var::ha_read_last_count);
00428 int error=heap_rlast(file, buf, active_index);
00429 getTable()->status=error ? STATUS_NOT_FOUND: 0;
00430 return error;
00431 }
00432
00433 int ha_heap::doStartTableScan(bool scan)
00434 {
00435 return scan ? heap_scan_init(file) : 0;
00436 }
00437
00438 int ha_heap::rnd_next(unsigned char *buf)
00439 {
00440 ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
00441 int error=heap_scan(file, buf);
00442 getTable()->status=error ? STATUS_NOT_FOUND: 0;
00443 return error;
00444 }
00445
00446 int ha_heap::rnd_pos(unsigned char * buf, unsigned char *pos)
00447 {
00448 int error;
00449 HEAP_PTR heap_position;
00450 ha_statistic_increment(&system_status_var::ha_read_rnd_count);
00451 memcpy(&heap_position, pos, sizeof(HEAP_PTR));
00452 error=heap_rrnd(file, buf, heap_position);
00453 getTable()->status=error ? STATUS_NOT_FOUND: 0;
00454 return error;
00455 }
00456
00457 void ha_heap::position(const unsigned char *)
00458 {
00459 *(HEAP_PTR*) ref= heap_position(file);
00460 }
00461
00462 int ha_heap::info(uint32_t flag)
00463 {
00464 HEAPINFO hp_info;
00465 (void) heap_info(file,&hp_info,flag);
00466
00467 errkey= hp_info.errkey;
00468 stats.records= hp_info.records;
00469 stats.deleted= hp_info.deleted;
00470 stats.mean_rec_length= hp_info.reclength;
00471 stats.data_file_length= hp_info.data_length;
00472 stats.index_file_length= hp_info.index_length;
00473 stats.max_data_file_length= hp_info.max_records * hp_info.reclength;
00474 stats.delete_length= hp_info.deleted * hp_info.reclength;
00475 if (flag & HA_STATUS_AUTO)
00476 stats.auto_increment_value= hp_info.auto_increment;
00477
00478
00479
00480
00481
00482 if (key_stat_version != file->getShare()->key_stat_version)
00483 update_key_stats();
00484 return 0;
00485 }
00486
00487 int ha_heap::extra(enum ha_extra_function operation)
00488 {
00489 return heap_extra(file,operation);
00490 }
00491
00492
00493 int ha_heap::reset()
00494 {
00495 return heap_reset(file);
00496 }
00497
00498
00499 int ha_heap::delete_all_rows()
00500 {
00501 heap_clear(file);
00502 if (getTable()->getShare()->getType() == message::Table::STANDARD)
00503 {
00504
00505
00506
00507
00508 file->getShare()->key_stat_version++;
00509 }
00510 return 0;
00511 }
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537 int ha_heap::disable_indexes(uint32_t mode)
00538 {
00539 int error;
00540
00541 if (mode == HA_KEY_SWITCH_ALL)
00542 {
00543 if (!(error= heap_disable_indexes(file)))
00544 set_keys_for_scanning();
00545 }
00546 else
00547 {
00548
00549 error= HA_ERR_WRONG_COMMAND;
00550 }
00551 return error;
00552 }
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584 int ha_heap::enable_indexes(uint32_t mode)
00585 {
00586 int error;
00587
00588 if (mode == HA_KEY_SWITCH_ALL)
00589 {
00590 if (!(error= heap_enable_indexes(file)))
00591 set_keys_for_scanning();
00592 }
00593 else
00594 {
00595
00596 error= HA_ERR_WRONG_COMMAND;
00597 }
00598 return error;
00599 }
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615 int ha_heap::indexes_are_disabled(void)
00616 {
00617 return heap_indexes_are_disabled(file);
00618 }
00619
00620 void ha_heap::drop_table(const char *)
00621 {
00622 file->getShare()->delete_on_close= 1;
00623 close();
00624 }
00625
00626
00627 int HeapEngine::doRenameTable(Session &session, const identifier::Table &from, const identifier::Table &to)
00628 {
00629 session.getMessageCache().renameTableMessage(from, to);
00630 return heap_rename(from.getPath().c_str(), to.getPath().c_str());
00631 }
00632
00633
00634 ha_rows ha_heap::records_in_range(uint32_t inx, key_range *min_key,
00635 key_range *max_key)
00636 {
00637 KeyInfo *key= &getTable()->key_info[inx];
00638
00639 if (!min_key || !max_key ||
00640 min_key->length != max_key->length ||
00641 min_key->length != key->key_length ||
00642 min_key->flag != HA_READ_KEY_EXACT ||
00643 max_key->flag != HA_READ_AFTER_KEY)
00644 return HA_POS_ERROR;
00645
00646 if (stats.records <= 1)
00647 return stats.records;
00648
00649
00650 assert(key_stat_version == file->getShare()->key_stat_version);
00651 return key->rec_per_key[key->key_parts-1];
00652 }
00653
00654 int HeapEngine::doCreateTable(Session &session,
00655 Table &table_arg,
00656 const identifier::Table &identifier,
00657 const message::Table& create_proto)
00658 {
00659 int error;
00660 HP_SHARE *internal_share;
00661 const char *table_name= identifier.getPath().c_str();
00662
00663 error= heap_create_table(&session, table_name, &table_arg,
00664 false,
00665 create_proto,
00666 &internal_share);
00667
00668 if (error == 0)
00669 {
00670 session.getMessageCache().storeTableMessage(identifier, create_proto);
00671 }
00672
00673 return error;
00674 }
00675
00676
00677 int HeapEngine::heap_create_table(Session *session, const char *table_name,
00678 Table *table_arg,
00679 bool internal_table,
00680 const message::Table &create_proto,
00681 HP_SHARE **internal_share)
00682 {
00683 uint32_t key, parts, mem_per_row_keys= 0;
00684 uint32_t keys= table_arg->getShare()->sizeKeys();
00685 uint32_t auto_key= 0, auto_key_type= 0;
00686 uint32_t max_key_fieldnr = 0, key_part_size = 0, next_field_pos = 0;
00687 uint32_t column_count= table_arg->getShare()->sizeFields();
00688 std::vector<HP_KEYDEF> keydef;
00689 int error;
00690 bool found_real_auto_increment= 0;
00691
00692
00693
00694
00695
00696
00697
00698 uint64_t num_rows= table_arg->getShare()->getMaxRows();
00699 if (num_rows > UINT32_MAX)
00700 return -1;
00701
00702 for (key= parts= 0; key < keys; key++)
00703 parts+= table_arg->key_info[key].key_parts;
00704
00705 keydef.resize(keys);
00706 std::vector<HA_KEYSEG> seg_buffer;
00707 seg_buffer.resize(parts);
00708 HA_KEYSEG *seg= &seg_buffer[0];
00709
00710 for (key= 0; key < keys; key++)
00711 {
00712 KeyInfo *pos= &table_arg->key_info[key];
00713 KeyPartInfo *key_part= pos->key_part;
00714 KeyPartInfo *key_part_end= key_part + pos->key_parts;
00715
00716 keydef[key].keysegs= (uint) pos->key_parts;
00717 keydef[key].flag= (pos->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL));
00718 keydef[key].seg= seg;
00719
00720 mem_per_row_keys+= sizeof(char*) * 2;
00721
00722 for (; key_part != key_part_end; key_part++, seg++)
00723 {
00724 Field *field= key_part->field;
00725
00726 {
00727 if ((seg->type = field->key_type()) != (int) HA_KEYTYPE_TEXT &&
00728 seg->type != HA_KEYTYPE_VARTEXT1 &&
00729 seg->type != HA_KEYTYPE_VARTEXT2 &&
00730 seg->type != HA_KEYTYPE_VARBINARY1 &&
00731 seg->type != HA_KEYTYPE_VARBINARY2)
00732 seg->type= HA_KEYTYPE_BINARY;
00733 }
00734 seg->start= (uint) key_part->offset;
00735 seg->length= (uint) key_part->length;
00736 seg->flag= key_part->key_part_flag;
00737
00738 next_field_pos= seg->start + seg->length;
00739 if (field->type() == DRIZZLE_TYPE_VARCHAR)
00740 {
00741 next_field_pos+= (uint8_t)(((Field_varstring*)field)->pack_length_no_ptr());
00742 }
00743
00744 if (next_field_pos > key_part_size) {
00745 key_part_size= next_field_pos;
00746 }
00747
00748 if (field->flags & ENUM_FLAG)
00749 seg->charset= &my_charset_bin;
00750 else
00751 seg->charset= field->charset();
00752 if (field->null_ptr)
00753 {
00754 seg->null_bit= field->null_bit;
00755 seg->null_pos= (uint) (field->null_ptr - (unsigned char*) table_arg->getInsertRecord());
00756 }
00757 else
00758 {
00759 seg->null_bit= 0;
00760 seg->null_pos= 0;
00761 }
00762 if (field->flags & AUTO_INCREMENT_FLAG &&
00763 table_arg->found_next_number_field &&
00764 key == table_arg->getShare()->next_number_index)
00765 {
00766
00767
00768
00769
00770 auto_key= key+ 1;
00771 auto_key_type= field->key_type();
00772 }
00773 if ((uint)field->position() + 1 > max_key_fieldnr)
00774 {
00775
00776 max_key_fieldnr= field->position() + 1;
00777 }
00778 }
00779 }
00780
00781 if (key_part_size < table_arg->getShare()->null_bytes + ((table_arg->getShare()->last_null_bit_pos+7) >> 3))
00782 {
00783
00784 key_part_size = table_arg->getShare()->null_bytes + ((table_arg->getShare()->last_null_bit_pos+7) >> 3);
00785 }
00786
00787
00788
00789 if (table_arg->found_next_number_field)
00790 {
00791 keydef[table_arg->getShare()->next_number_index].flag|= HA_AUTO_KEY;
00792 found_real_auto_increment= table_arg->getShare()->next_number_key_offset == 0;
00793 }
00794 HP_CREATE_INFO hp_create_info;
00795 hp_create_info.auto_key= auto_key;
00796 hp_create_info.auto_key_type= auto_key_type;
00797 hp_create_info.auto_increment= (create_proto.options().has_auto_increment_value() ?
00798 create_proto.options().auto_increment_value() - 1 : 0);
00799 hp_create_info.max_table_size=session->variables.max_heap_table_size;
00800 hp_create_info.with_auto_increment= found_real_auto_increment;
00801 hp_create_info.internal_table= internal_table;
00802 hp_create_info.max_chunk_size= table_arg->getShare()->block_size;
00803
00804 error= heap_create(table_name,
00805 keys, &keydef[0],
00806 column_count,
00807 key_part_size,
00808 table_arg->getShare()->getRecordLength(), mem_per_row_keys,
00809 static_cast<uint32_t>(num_rows),
00810 0,
00811 &hp_create_info, internal_share);
00812
00813 return (error);
00814 }
00815
00816
00817 void ha_heap::get_auto_increment(uint64_t, uint64_t, uint64_t,
00818 uint64_t *first_value,
00819 uint64_t *nb_reserved_values)
00820 {
00821 ha_heap::info(HA_STATUS_AUTO);
00822 *first_value= stats.auto_increment_value;
00823
00824 *nb_reserved_values= UINT64_MAX;
00825 }
00826
00827
00828 int ha_heap::cmp_ref(const unsigned char *ref1, const unsigned char *ref2)
00829 {
00830 return memcmp(ref1, ref2, sizeof(HEAP_PTR));
00831 }
00832
00833
00834 DRIZZLE_DECLARE_PLUGIN
00835 {
00836 DRIZZLE_VERSION_ID,
00837 "MEMORY",
00838 "1.0",
00839 "MySQL AB",
00840 "Hash based, stored in memory, useful for temporary tables",
00841 PLUGIN_LICENSE_GPL,
00842 heap_init,
00843 NULL,
00844 NULL
00845 }
00846 DRIZZLE_DECLARE_PLUGIN_END;