~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/heap/ha_heap.cc

MergedĀ inĀ trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
   along with this program; if not, write to the Free Software
14
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
 
#define DRIZZLE_SERVER 1
17
16
#include <drizzled/server_includes.h>
 
17
#include <drizzled/error.h>
 
18
#include <drizzled/table.h>
 
19
#include <drizzled/session.h>
 
20
#include <drizzled/current_session.h>
 
21
#include <drizzled/field/timestamp.h>
 
22
#include <drizzled/field/varstring.h>
 
23
 
 
24
#include "heap.h"
18
25
#include "ha_heap.h"
19
26
#include "heapdef.h"
20
27
 
21
 
static handler *heap_create_handler(handlerton *hton,
22
 
                                    TABLE_SHARE *table, 
23
 
                                    MEM_ROOT *mem_root);
24
 
 
25
 
int heap_deinit(void *p __attribute__((unused)))
26
 
            
27
 
{
28
 
  return hp_panic(HA_PANIC_CLOSE);
 
28
#include <string>
 
29
 
 
30
using namespace std;
 
31
 
 
32
static const string engine_name("MEMORY");
 
33
 
 
34
pthread_mutex_t THR_LOCK_heap= PTHREAD_MUTEX_INITIALIZER;
 
35
 
 
36
static const char *ha_heap_exts[] = {
 
37
  NULL
 
38
};
 
39
 
 
40
class HeapEngine : public drizzled::plugin::StorageEngine
 
41
{
 
42
public:
 
43
  HeapEngine(string name_arg)
 
44
   : drizzled::plugin::StorageEngine(name_arg,
 
45
                                     HTON_CAN_RECREATE|HTON_TEMPORARY_ONLY)
 
46
  {
 
47
    addAlias("HEAP");
 
48
  }
 
49
 
 
50
  virtual handler *create(TableShare *table,
 
51
                          MEM_ROOT *mem_root)
 
52
  {
 
53
    return new (mem_root) ha_heap(this, table);
 
54
  }
 
55
 
 
56
  const char **bas_ext() const {
 
57
    return ha_heap_exts;
 
58
  }
 
59
 
 
60
  int createTableImplementation(Session *session, const char *table_name,
 
61
                                Table *table_arg, HA_CREATE_INFO *create_info,
 
62
                                drizzled::message::Table*);
 
63
 
 
64
  /* For whatever reason, internal tables can be created by handler::open()
 
65
     for HEAP.
 
66
     Instead of diving down a rat hole, let's just cry ourselves to sleep
 
67
     at night with this odd hackish workaround.
 
68
   */
 
69
  int heap_create_table(Session *session, const char *table_name,
 
70
                        Table *table_arg, HA_CREATE_INFO *create_info,
 
71
                        bool internal_table,
 
72
                        HP_SHARE **internal_share);
 
73
 
 
74
  int renameTableImplementation(Session*, const char * from, const char * to);
 
75
 
 
76
  int deleteTableImplementation(Session *, const string table_path);
 
77
};
 
78
 
 
79
/*
 
80
  We have to ignore ENOENT entries as the HEAP table is created on open and
 
81
  not when doing a CREATE on the table.
 
82
*/
 
83
int HeapEngine::deleteTableImplementation(Session*, const string table_path)
 
84
{
 
85
  return heap_delete_table(table_path.c_str());
29
86
}
30
87
 
 
88
static HeapEngine *heap_storage_engine= NULL;
31
89
 
32
 
int heap_init(void *p)
 
90
static int heap_init(drizzled::plugin::Registry &registry)
33
91
{
34
 
  handlerton *heap_hton;
35
 
 
36
 
  heap_hton= (handlerton *)p;
37
 
  heap_hton->state=      SHOW_OPTION_YES;
38
 
  heap_hton->create=     heap_create_handler;
39
 
  heap_hton->flags=      HTON_CAN_RECREATE;
40
 
 
 
92
  heap_storage_engine= new HeapEngine(engine_name);
 
93
  registry.add(heap_storage_engine);
 
94
  pthread_mutex_init(&THR_LOCK_heap, MY_MUTEX_INIT_FAST);
41
95
  return 0;
42
96
}
43
97
 
44
 
static handler *heap_create_handler(handlerton *hton,
45
 
                                    TABLE_SHARE *table, 
46
 
                                    MEM_ROOT *mem_root)
 
98
static int heap_deinit(drizzled::plugin::Registry &registry)
47
99
{
48
 
  return new (mem_root) ha_heap(hton, table);
 
100
  registry.remove(heap_storage_engine);
 
101
  delete heap_storage_engine;
 
102
 
 
103
  int ret= hp_panic(HA_PANIC_CLOSE);
 
104
 
 
105
  pthread_mutex_destroy(&THR_LOCK_heap);
 
106
 
 
107
  return ret;
49
108
}
50
109
 
51
110
 
 
111
 
52
112
/*****************************************************************************
53
113
** HEAP tables
54
114
*****************************************************************************/
55
115
 
56
 
ha_heap::ha_heap(handlerton *hton, TABLE_SHARE *table_arg)
57
 
  :handler(hton, table_arg), file(0), records_changed(0), key_stat_version(0), 
 
116
ha_heap::ha_heap(drizzled::plugin::StorageEngine *engine_arg,
 
117
                 TableShare *table_arg)
 
118
  :handler(engine_arg, table_arg), file(0), records_changed(0), key_stat_version(0),
58
119
  internal_table(0)
59
120
{}
60
121
 
61
 
 
62
 
static const char *ha_heap_exts[] = {
63
 
  NULL
64
 
};
65
 
 
66
 
const char **ha_heap::bas_ext() const
67
 
{
68
 
  return ha_heap_exts;
69
 
}
70
 
 
71
122
/*
72
 
  Hash index statistics is updated (copied from HP_KEYDEF::hash_buckets to 
73
 
  rec_per_key) after 1/HEAP_STATS_UPDATE_THRESHOLD fraction of table records 
74
 
  have been inserted/updated/deleted. delete_all_rows() and table flush cause 
 
123
  Hash index statistics is updated (copied from HP_KEYDEF::hash_buckets to
 
124
  rec_per_key) after 1/HEAP_STATS_UPDATE_THRESHOLD fraction of table records
 
125
  have been inserted/updated/deleted. delete_all_rows() and table flush cause
75
126
  immediate update.
76
127
 
77
128
  NOTE
78
129
   hash index statistics must be updated when number of table records changes
79
 
   from 0 to non-zero value and vice versa. Otherwise records_in_range may 
 
130
   from 0 to non-zero value and vice versa. Otherwise records_in_range may
80
131
   erroneously return 0 and 'range' may miss records.
81
132
*/
82
133
#define HEAP_STATS_UPDATE_THRESHOLD 10
89
140
    internal_table= test(test_if_locked & HA_OPEN_INTERNAL_TABLE);
90
141
    memset(&create_info, 0, sizeof(create_info));
91
142
    file= 0;
92
 
    if (!create(name, table, &create_info))
 
143
    HP_SHARE *internal_share= NULL;
 
144
    if (!heap_storage_engine->heap_create_table(ha_session(), name, table,
 
145
                                                &create_info,
 
146
                                                internal_table,&internal_share))
93
147
    {
94
148
        file= internal_table ?
95
149
          heap_open_from_share(internal_share, mode) :
132
186
  Create a copy of this table
133
187
 
134
188
  DESCRIPTION
135
 
    Do same as default implementation but use file->s->name instead of 
 
189
    Do same as default implementation but use file->s->name instead of
136
190
    table->s->path. This is needed by Windows where the clone() call sees
137
 
    '/'-delimited path in table->s->path, while ha_peap::open() was called 
 
191
    '/'-delimited path in table->s->path, while ha_peap::open() was called
138
192
    with '\'-delimited path.
139
193
*/
140
194
 
144
198
  if (new_handler && !new_handler->ha_open(table, file->s->name, table->db_stat,
145
199
                                           HA_OPEN_IGNORE_IF_LOCKED))
146
200
    return new_handler;
147
 
  return NULL;  /* purecov: inspected */
 
201
  return NULL;
 
202
}
 
203
 
 
204
 
 
205
const char *ha_heap::index_type(uint32_t inx)
 
206
{
 
207
  return ((table_share->key_info[inx].algorithm == HA_KEY_ALG_BTREE) ?
 
208
          "BTREE" : "HASH");
 
209
}
 
210
 
 
211
 
 
212
uint32_t ha_heap::index_flags(uint32_t inx, uint32_t, bool) const
 
213
{
 
214
  return ((table_share->key_info[inx].algorithm == HA_KEY_ALG_BTREE) ?
 
215
          HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER | HA_READ_RANGE :
 
216
          HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR);
148
217
}
149
218
 
150
219
 
166
235
 
167
236
void ha_heap::set_keys_for_scanning(void)
168
237
{
169
 
  btree_keys.clear_all();
 
238
  btree_keys.reset();
170
239
  for (uint32_t i= 0 ; i < table->s->keys ; i++)
171
240
  {
172
241
    if (table->key_info[i].algorithm == HA_KEY_ALG_BTREE)
173
 
      btree_keys.set_bit(i);
 
242
      btree_keys.set(i);
174
243
  }
175
244
}
176
245
 
206
275
{
207
276
  int res;
208
277
  ha_statistic_increment(&SSV::ha_write_count);
209
 
  if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
210
 
    table->timestamp_field->set_time();
211
278
  if (table->next_number_field && buf == table->record[0])
212
279
  {
213
280
    if ((res= update_auto_increment()))
214
281
      return res;
215
282
  }
216
283
  res= heap_write(file,buf);
217
 
  if (!res && (++records_changed*HEAP_STATS_UPDATE_THRESHOLD > 
 
284
  if (!res && (++records_changed*HEAP_STATS_UPDATE_THRESHOLD >
218
285
               file->s->records))
219
286
  {
220
287
    /*
233
300
  if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
234
301
    table->timestamp_field->set_time();
235
302
  res= heap_update(file,old_data,new_data);
236
 
  if (!res && ++records_changed*HEAP_STATS_UPDATE_THRESHOLD > 
 
303
  if (!res && ++records_changed*HEAP_STATS_UPDATE_THRESHOLD >
237
304
              file->s->records)
238
305
  {
239
306
    /*
250
317
  int res;
251
318
  ha_statistic_increment(&SSV::ha_delete_count);
252
319
  res= heap_delete(file,buf);
253
 
  if (!res && table->s->tmp_table == NO_TMP_TABLE && 
 
320
  if (!res && table->s->tmp_table == NO_TMP_TABLE &&
254
321
      ++records_changed*HEAP_STATS_UPDATE_THRESHOLD > file->s->records)
255
322
  {
256
323
    /*
354
421
  return error;
355
422
}
356
423
 
357
 
void ha_heap::position(const unsigned char *record __attribute__((unused)))
 
424
void ha_heap::position(const unsigned char *)
358
425
{
359
426
  *(HEAP_PTR*) ref= heap_position(file);        // Ref is aligned
360
427
}
419
486
  return 0;
420
487
}
421
488
 
422
 
int ha_heap::external_lock(THD *thd __attribute__((unused)),
423
 
                           int lock_type __attribute__((unused)))
 
489
int ha_heap::external_lock(Session *, int)
424
490
{
425
491
  return 0;                                     // No external locking
426
492
}
533
599
  return heap_indexes_are_disabled(file);
534
600
}
535
601
 
536
 
THR_LOCK_DATA **ha_heap::store_lock(THD *thd __attribute__((unused)),
 
602
THR_LOCK_DATA **ha_heap::store_lock(Session *,
537
603
                                    THR_LOCK_DATA **to,
538
604
                                    enum thr_lock_type lock_type)
539
605
{
543
609
  return to;
544
610
}
545
611
 
546
 
/*
547
 
  We have to ignore ENOENT entries as the HEAP table is created on open and
548
 
  not when doing a CREATE on the table.
549
 
*/
550
 
 
551
 
int ha_heap::delete_table(const char *name)
552
 
{
553
 
  int error= heap_delete_table(name);
554
 
  return error == ENOENT ? 0 : error;
555
 
}
556
 
 
557
 
 
558
 
void ha_heap::drop_table(const char *name __attribute__((unused)))
 
612
void ha_heap::drop_table(const char *)
559
613
{
560
614
  file->s->delete_on_close= 1;
561
615
  close();
562
616
}
563
617
 
564
618
 
565
 
int ha_heap::rename_table(const char * from, const char * to)
 
619
int HeapEngine::renameTableImplementation(Session*,
 
620
                                          const char *from, const char *to)
566
621
{
567
622
  return heap_rename(from,to);
568
623
}
590
645
  return key->rec_per_key[key->key_parts-1];
591
646
}
592
647
 
593
 
 
594
 
int ha_heap::create(const char *name, Table *table_arg,
595
 
                    HA_CREATE_INFO *create_info)
 
648
int HeapEngine::createTableImplementation(Session *session,
 
649
                                          const char *table_name,
 
650
                                          Table *table_arg,
 
651
                                          HA_CREATE_INFO *create_info,
 
652
                                          drizzled::message::Table*)
 
653
{
 
654
  HP_SHARE *internal_share;
 
655
  return heap_create_table(session, table_name, table_arg, create_info,
 
656
                           false, &internal_share);
 
657
}
 
658
 
 
659
 
 
660
int HeapEngine::heap_create_table(Session *session, const char *table_name,
 
661
                             Table *table_arg, HA_CREATE_INFO *create_info,
 
662
                             bool internal_table, HP_SHARE **internal_share)
596
663
{
597
664
  uint32_t key, parts, mem_per_row_keys= 0, keys= table_arg->s->keys;
598
665
  uint32_t auto_key= 0, auto_key_type= 0;
603
670
  HA_KEYSEG *seg;
604
671
  char buff[FN_REFLEN];
605
672
  int error;
606
 
  TABLE_SHARE *share= table_arg->s;
 
673
  TableShare *share= table_arg->s;
607
674
  bool found_real_auto_increment= 0;
608
675
 
609
 
  if (!(columndef= (HP_COLUMNDEF*) my_malloc(column_count * sizeof(HP_COLUMNDEF), MYF(MY_WME))))
 
676
  /* 
 
677
   * We cannot create tables with more rows than UINT32_MAX.  This is a
 
678
   * limitation of the HEAP engine.  Here, since TableShare::getMaxRows()
 
679
   * can return a number more than that, we trap it here instead of casting
 
680
   * to a truncated integer.
 
681
   */
 
682
  uint64_t num_rows= share->getMaxRows();
 
683
  if (num_rows > UINT32_MAX)
 
684
    return -1;
 
685
 
 
686
  if (!(columndef= (HP_COLUMNDEF*) malloc(column_count * sizeof(HP_COLUMNDEF))))
610
687
    return my_errno;
611
688
 
612
689
  for (column_idx= 0; column_idx < column_count; column_idx++)
641
718
  for (key= parts= 0; key < keys; key++)
642
719
    parts+= table_arg->key_info[key].key_parts;
643
720
 
644
 
  if (!(keydef= (HP_KEYDEF*) my_malloc(keys * sizeof(HP_KEYDEF) +
645
 
                                       parts * sizeof(HA_KEYSEG),
646
 
                                       MYF(MY_WME))))
 
721
  if (!(keydef= (HP_KEYDEF*) malloc(keys * sizeof(HP_KEYDEF) +
 
722
                                    parts * sizeof(HA_KEYSEG))))
647
723
  {
648
724
    free((void *) columndef);
649
725
    return my_errno;
735
811
      }
736
812
    }
737
813
  }
738
 
  
 
814
 
739
815
  if (key_part_size < share->null_bytes + ((share->last_null_bit_pos+7) >> 3))
740
816
  {
741
817
    /* Make sure to include null fields regardless of the presense of keys */
742
818
    key_part_size = share->null_bytes + ((share->last_null_bit_pos+7) >> 3);
743
819
  }
744
820
 
745
 
  
746
 
  
 
821
 
 
822
 
747
823
  if (table_arg->found_next_number_field)
748
824
  {
749
825
    keydef[share->next_number_index].flag|= HA_AUTO_KEY;
754
830
  hp_create_info.auto_key_type= auto_key_type;
755
831
  hp_create_info.auto_increment= (create_info->auto_increment_value ?
756
832
                                  create_info->auto_increment_value - 1 : 0);
757
 
  hp_create_info.max_table_size=current_thd->variables.max_heap_table_size;
 
833
  hp_create_info.max_table_size=session->variables.max_heap_table_size;
758
834
  hp_create_info.with_auto_increment= found_real_auto_increment;
759
835
  hp_create_info.internal_table= internal_table;
760
836
  hp_create_info.max_chunk_size= share->block_size;
761
837
  hp_create_info.is_dynamic= (share->row_type == ROW_TYPE_DYNAMIC);
762
 
  error= heap_create(fn_format(buff,name,"","",
763
 
                               MY_REPLACE_EXT|MY_UNPACK_FILENAME),
764
 
                   keys, keydef,
765
 
         column_count, columndef,
766
 
         max_key_fieldnr, key_part_size,
767
 
         share->reclength, mem_per_row_keys,
768
 
         (uint32_t) share->max_rows, (uint32_t) share->min_rows,
769
 
         &hp_create_info, &internal_share);
770
 
  
 
838
 
 
839
  error= heap_create(fn_format(buff,table_name,"","",
 
840
                              MY_REPLACE_EXT|MY_UNPACK_FILENAME),
 
841
                    keys, keydef,
 
842
                    column_count, columndef,
 
843
                    max_key_fieldnr, key_part_size,
 
844
                    share->reclength, mem_per_row_keys,
 
845
                    static_cast<uint32_t>(num_rows), /* We check for overflow above, so cast is fine here. */
 
846
                    0, // Factor out MIN
 
847
                    &hp_create_info, internal_share);
 
848
 
771
849
  free((unsigned char*) keydef);
772
850
  free((void *) columndef);
773
 
  assert(file == 0);
 
851
 
774
852
  return (error);
775
853
}
776
854
 
777
855
 
778
 
void ha_heap::update_create_info(HA_CREATE_INFO *create_info)
779
 
{
780
 
  table->file->info(HA_STATUS_AUTO);
781
 
  if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
782
 
    create_info->auto_increment_value= stats.auto_increment_value;
783
 
  if (!(create_info->used_fields & HA_CREATE_USED_BLOCK_SIZE))
784
 
  {
785
 
    if (file->s->recordspace.is_variable_size)
786
 
      create_info->block_size= file->s->recordspace.chunk_length;
787
 
    else
788
 
      create_info->block_size= 0;
789
 
  }
790
 
}
791
 
 
792
 
void ha_heap::get_auto_increment(uint64_t offset __attribute__((unused)),
793
 
                                 uint64_t increment __attribute__((unused)),
794
 
                                 uint64_t nb_desired_values __attribute__((unused)),
 
856
void ha_heap::get_auto_increment(uint64_t, uint64_t, uint64_t,
795
857
                                 uint64_t *first_value,
796
858
                                 uint64_t *nb_reserved_values)
797
859
{
802
864
}
803
865
 
804
866
 
805
 
bool ha_heap::check_if_incompatible_data(HA_CREATE_INFO *info,
806
 
                                         uint32_t table_changes)
 
867
int ha_heap::cmp_ref(const unsigned char *ref1, const unsigned char *ref2)
807
868
{
808
 
  /* Check that auto_increment value was not changed */
809
 
  if ((info->used_fields & HA_CREATE_USED_AUTO &&
810
 
       info->auto_increment_value != 0) ||
811
 
      table_changes == IS_EQUAL_NO ||
812
 
      table_changes & IS_EQUAL_PACK_LENGTH) // Not implemented yet
813
 
    return COMPATIBLE_DATA_NO;
814
 
  return COMPATIBLE_DATA_YES;
 
869
  return memcmp(ref1, ref2, sizeof(HEAP_PTR));
815
870
}
816
871
 
817
 
mysql_declare_plugin(heap)
 
872
 
 
873
drizzle_declare_plugin(heap)
818
874
{
819
 
  DRIZZLE_STORAGE_ENGINE_PLUGIN,
820
875
  "MEMORY",
821
876
  "1.0",
822
877
  "MySQL AB",
828
883
  NULL,                       /* system variables                */
829
884
  NULL                        /* config options                  */
830
885
}
831
 
mysql_declare_plugin_end;
 
886
drizzle_declare_plugin_end;