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 */
19
#include "drizzled/internal/my_bit.h"
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18
#include <drizzled/server_includes.h>
19
#include <mysys/my_bit.h>
20
20
#include "myisampack.h"
21
21
#include "ha_myisam.h"
22
#include "myisam_priv.h"
23
#include "drizzled/option.h"
24
#include "drizzled/internal/my_bit.h"
25
#include "drizzled/internal/m_string.h"
26
#include "drizzled/util/test.h"
27
#include "drizzled/error.h"
28
#include "drizzled/errmsg_print.h"
29
#include "drizzled/gettext.h"
30
#include "drizzled/session.h"
31
#include "drizzled/plugin.h"
32
#include "drizzled/plugin/client.h"
33
#include "drizzled/table.h"
34
#include "drizzled/field/timestamp.h"
35
#include "drizzled/memory/multi_malloc.h"
36
#include "drizzled/plugin/daemon.h"
38
#include <boost/algorithm/string.hpp>
39
#include <boost/scoped_ptr.hpp>
46
#include <boost/program_options.hpp>
47
#include <drizzled/module/option_map.h>
49
namespace po= boost::program_options;
52
using namespace drizzled;
54
static const string engine_name("MyISAM");
56
boost::mutex THR_LOCK_myisam;
58
static uint32_t myisam_key_cache_block_size= KEY_CACHE_BLOCK_SIZE;
59
static uint32_t myisam_key_cache_size;
60
static uint32_t myisam_key_cache_division_limit;
61
static uint32_t myisam_key_cache_age_threshold;
22
#include "myisamdef.h"
23
#include <drizzled/util/test.h>
24
#include <drizzled/error.h>
25
#include <drizzled/errmsg_print.h>
26
#include <drizzled/gettext.h>
27
#include <drizzled/session.h>
28
#include <drizzled/protocol.h>
29
#include <drizzled/table.h>
30
#include <drizzled/field/timestamp.h>
32
ulong myisam_recover_options= HA_RECOVER_NONE;
33
pthread_mutex_t THR_LOCK_myisam= PTHREAD_MUTEX_INITIALIZER;
35
static uint32_t repair_threads;
36
static uint32_t block_size;
62
37
static uint64_t max_sort_file_size;
63
typedef constrained_check<size_t, SIZE_MAX, 1024, 1024> sort_buffer_constraint;
64
static sort_buffer_constraint sort_buffer_size;
66
void st_mi_isam_share::setKeyCache()
68
(void)init_key_cache(&key_cache,
69
myisam_key_cache_block_size,
70
myisam_key_cache_size,
71
myisam_key_cache_division_limit,
72
myisam_key_cache_age_threshold);
38
static uint64_t sort_buffer_size;
40
/* bits in myisam_recover_options */
41
const char *myisam_recover_names[] =
42
{ "DEFAULT", "BACKUP", "FORCE", "QUICK", NULL};
43
TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"",
44
myisam_recover_names, NULL};
46
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
47
"nulls_ignored", NULL};
48
TYPELIB myisam_stats_method_typelib= {
49
array_elements(myisam_stats_method_names) - 1, "",
50
myisam_stats_method_names, NULL};
75
53
/*****************************************************************************
77
55
*****************************************************************************/
79
static const char *ha_myisam_exts[] = {
85
class MyisamEngine : public plugin::StorageEngine
88
MyisamEngine(const MyisamEngine&);
89
MyisamEngine& operator=(const MyisamEngine&);
91
explicit MyisamEngine(string name_arg) :
92
plugin::StorageEngine(name_arg,
93
HTON_CAN_INDEX_BLOBS |
94
HTON_STATS_RECORDS_IS_EXACT |
100
HTON_SKIP_STORE_LOCK)
104
virtual ~MyisamEngine()
106
mi_panic(HA_PANIC_CLOSE);
109
virtual Cursor *create(Table &table)
111
return new ha_myisam(*this, table);
114
const char **bas_ext() const {
115
return ha_myisam_exts;
118
int doCreateTable(Session&,
120
const TableIdentifier &identifier,
123
int doRenameTable(Session&, const TableIdentifier &from, const TableIdentifier &to);
125
int doDropTable(Session&, const TableIdentifier &identifier);
127
int doGetTableDefinition(Session& session,
128
const TableIdentifier &identifier,
129
message::Table &table_message);
131
uint32_t max_supported_keys() const { return MI_MAX_KEY; }
132
uint32_t max_supported_key_length() const { return MI_MAX_KEY_LENGTH; }
133
uint32_t max_supported_key_part_length() const { return MI_MAX_KEY_LENGTH; }
135
uint32_t index_flags(enum ha_key_alg) const
137
return (HA_READ_NEXT |
143
bool doDoesTableExist(Session& session, const TableIdentifier &identifier);
145
void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
146
const drizzled::SchemaIdentifier &schema_identifier,
147
drizzled::TableIdentifier::vector &set_of_identifiers);
148
bool validateCreateTableOption(const std::string &key, const std::string &state)
151
if (boost::iequals(key, "ROW_FORMAT"))
160
void MyisamEngine::doGetTableIdentifiers(drizzled::CachedDirectory&,
161
const drizzled::SchemaIdentifier&,
162
drizzled::TableIdentifier::vector&)
166
bool MyisamEngine::doDoesTableExist(Session &session, const TableIdentifier &identifier)
168
return session.getMessageCache().doesTableMessageExist(identifier);
171
int MyisamEngine::doGetTableDefinition(Session &session,
172
const TableIdentifier &identifier,
173
message::Table &table_message)
175
if (session.getMessageCache().getTableMessage(identifier, table_message))
181
Convert to push_Warnings if you ever care about this, otherwise, it is a no-op.
184
static void mi_check_print_msg(MI_CHECK *, const char* ,
185
const char *, va_list )
57
static handler *myisam_create_handler(handlerton *hton,
61
return new (mem_root) ha_myisam(hton, table);
64
// collect errors printed by mi_check routines
66
static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
67
const char *fmt, va_list args)
69
Session* session = (Session*)param->session;
70
Protocol *protocol= session->protocol;
71
uint32_t length, msg_length;
72
char msgbuf[MI_MAX_MSG_BUF];
73
char name[NAME_LEN*2+2];
75
msg_length= vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
76
msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia
78
if (!session->vio_ok())
80
errmsg_printf(ERRMSG_LVL_ERROR, "%s",msgbuf);
84
if (param->testflag & (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR |
87
my_message(ER_NOT_KEYFILE,msgbuf,MYF(MY_WME));
90
length= sprintf(name,"%s.%s",param->db_name,param->table_name);
93
TODO: switch from protocol to push_warning here. The main reason we didn't
94
it yet is parallel repair. Due to following trace:
95
mi_check_print_msg/push_warning/sql_alloc/my_pthread_getspecific_ptr.
97
Also we likely need to lock mutex here (in both cases with protocol and
100
protocol->prepare_for_resend();
101
protocol->store(name, length, system_charset_info);
102
protocol->store(param->op_name, system_charset_info);
103
protocol->store(msg_type, system_charset_info);
104
protocol->store(msgbuf, msg_length, system_charset_info);
105
if (protocol->write())
106
errmsg_printf(ERRMSG_LVL_ERROR, "Failed on my_net_write, writing to stderr instead: %s\n",
214
static int table2myisam(Table *table_arg, MI_KEYDEF **keydef_out,
215
MI_COLUMNDEF **recinfo_out, uint32_t *records_out)
136
int table2myisam(Table *table_arg, MI_KEYDEF **keydef_out,
137
MI_COLUMNDEF **recinfo_out, uint32_t *records_out)
217
139
uint32_t i, j, recpos, minpos, fieldpos, temp_length, length;
218
140
enum ha_base_keytype type= HA_KEYTYPE_BINARY;
219
141
unsigned char *record;
220
143
MI_KEYDEF *keydef;
221
144
MI_COLUMNDEF *recinfo, *recinfo_pos;
222
145
HA_KEYSEG *keyseg;
223
TableShare *share= table_arg->getMutableShare();
146
TABLE_SHARE *share= table_arg->s;
224
147
uint32_t options= share->db_options_in_use;
225
if (!(memory::multi_malloc(false,
226
recinfo_out, (share->sizeFields() * 2 + 2) * sizeof(MI_COLUMNDEF),
227
keydef_out, share->sizeKeys() * sizeof(MI_KEYDEF),
228
&keyseg, (share->key_parts + share->sizeKeys()) * sizeof(HA_KEYSEG),
148
if (!(my_multi_malloc(MYF(MY_WME),
149
recinfo_out, (share->fields * 2 + 2) * sizeof(MI_COLUMNDEF),
150
keydef_out, share->keys * sizeof(MI_KEYDEF),
152
(share->key_parts + share->keys) * sizeof(HA_KEYSEG),
230
return(HA_ERR_OUT_OF_MEM);
154
return(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
231
155
keydef= *keydef_out;
232
156
recinfo= *recinfo_out;
233
for (i= 0; i < share->sizeKeys(); i++)
157
pos= table_arg->key_info;
158
for (i= 0; i < share->keys; i++, pos++)
235
KeyInfo *pos= &table_arg->key_info[i];
236
160
keydef[i].flag= ((uint16_t) pos->flags & (HA_NOSAME));
237
161
keydef[i].key_alg= HA_KEY_ALG_BTREE;
238
162
keydef[i].block_length= pos->block_size;
537
461
errmsg_printf(ERRMSG_LVL_ERROR, _("Got an error from unknown thread, %s:%d"), sfile, sline);
539
463
errmsg_printf(ERRMSG_LVL_ERROR, "%s", message);
540
list<Session *>::iterator it= file->s->in_use->begin();
541
while (it != file->s->in_use->end())
464
for (element= file->s->in_use; element; element= list_rest(element))
543
466
errmsg_printf(ERRMSG_LVL_ERROR, "%s", _("Unknown thread accessing table"));
548
ha_myisam::ha_myisam(plugin::StorageEngine &engine_arg,
550
: Cursor(engine_arg, table_arg),
552
can_enable_indexes(true),
556
Cursor *ha_myisam::clone(memory::Root *mem_root)
468
pthread_mutex_unlock(&file->s->intern_lock);
473
ha_myisam::ha_myisam(handlerton *hton, TABLE_SHARE *table_arg)
474
:handler(hton, table_arg), file(0),
475
int_table_flags(HA_NULL_IN_KEY |
476
HA_BINLOG_ROW_CAPABLE |
477
HA_BINLOG_STMT_CAPABLE |
484
HA_STATS_RECORDS_IS_EXACT |
485
HA_NEED_READ_RANGE_BUFFER |
487
can_enable_indexes(1)
490
handler *ha_myisam::clone(MEM_ROOT *mem_root)
558
ha_myisam *new_handler= static_cast <ha_myisam *>(Cursor::clone(mem_root));
492
ha_myisam *new_handler= static_cast <ha_myisam *>(handler::clone(mem_root));
560
494
new_handler->file->state= file->state;
561
495
return new_handler;
564
const char *ha_myisam::index_type(uint32_t )
499
static const char *ha_myisam_exts[] = {
505
const char **ha_myisam::bas_ext() const
507
return ha_myisam_exts;
511
const char *ha_myisam::index_type(uint32_t key_number __attribute__((unused)))
569
516
/* Name is here without an extension */
570
int ha_myisam::doOpen(const drizzled::TableIdentifier &identifier, int mode, uint32_t test_if_locked)
517
int ha_myisam::open(const char *name, int mode, uint32_t test_if_locked)
572
519
MI_KEYDEF *keyinfo;
573
520
MI_COLUMNDEF *recinfo= 0;
589
536
open of a table that is in use by other threads already (if the
590
537
MyISAM share exists already).
592
if (!(file= mi_open(identifier, mode, test_if_locked)))
593
return (errno ? errno : -1);
595
if (!getTable()->getShare()->getType()) /* No need to perform a check for tmp table */
539
if (!(file=mi_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER)))
540
return (my_errno ? my_errno : -1);
541
if (!table->s->tmp_table) /* No need to perform a check for tmp table */
597
if ((errno= table2myisam(getTable(), &keyinfo, &recinfo, &recs)))
543
if ((my_errno= table2myisam(table, &keyinfo, &recinfo, &recs)))
545
/* purecov: begin inspected */
601
if (check_definition(keyinfo, recinfo, getTable()->getShare()->sizeKeys(), recs,
549
if (check_definition(keyinfo, recinfo, table->s->keys, recs,
602
550
file->s->keyinfo, file->s->rec,
603
551
file->s->base.keys, file->s->base.fields, true))
605
errno= HA_ERR_CRASHED;
553
/* purecov: begin inspected */
554
my_errno= HA_ERR_CRASHED;
610
assert(test_if_locked);
611
560
if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE))
612
561
mi_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0);
614
563
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
615
564
if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
616
565
mi_extra(file, HA_EXTRA_WAIT_LOCK, 0);
617
if (!getTable()->getShare()->db_record_offset)
621
keys_with_parts.reset();
622
for (i= 0; i < getTable()->getShare()->sizeKeys(); i++)
566
if (!table->s->db_record_offset)
567
int_table_flags|=HA_REC_NOT_IN_SEQ;
568
if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
569
int_table_flags|=HA_HAS_CHECKSUM;
571
keys_with_parts.clear_all();
572
for (i= 0; i < table->s->keys; i++)
624
getTable()->key_info[i].block_size= file->s->keyinfo[i].block_length;
574
table->key_info[i].block_size= file->s->keyinfo[i].block_length;
626
KeyPartInfo *kp= getTable()->key_info[i].key_part;
627
KeyPartInfo *kp_end= kp + getTable()->key_info[i].key_parts;
576
KEY_PART_INFO *kp= table->key_info[i].key_part;
577
KEY_PART_INFO *kp_end= kp + table->key_info[i].key_parts;
628
578
for (; kp != kp_end; kp++)
630
if (!kp->field->part_of_key.test(i))
580
if (!kp->field->part_of_key.is_set(i))
632
keys_with_parts.set(i);
582
keys_with_parts.set_bit(i);
643
Both recinfo and keydef are allocated by multi_malloc(), thus only
593
Both recinfo and keydef are allocated by my_multi_malloc(), thus only
644
594
recinfo must be freed.
647
597
free((unsigned char*) recinfo);
651
601
int ha_myisam::close(void)
670
626
return mi_write(file,buf);
629
int ha_myisam::check(Session* session, HA_CHECK_OPT* check_opt)
631
if (!file) return HA_ADMIN_INTERNAL_ERROR;
634
MYISAM_SHARE* share = file->s;
635
const char *old_proc_info= session->get_proc_info();
637
session->set_proc_info("Checking table");
638
myisamchk_init(¶m);
639
param.session = session;
640
param.op_name = "check";
641
param.db_name= table->s->db.str;
642
param.table_name= table->alias;
643
param.testflag = check_opt->flags | T_CHECK | T_SILENT;
644
param.stats_method= (enum_mi_stats_method)session->variables.myisam_stats_method;
646
if (!(table->db_stat & HA_READ_ONLY))
647
param.testflag|= T_STATISTICS;
648
param.using_global_keycache = 1;
650
if (!mi_is_crashed(file) &&
651
(((param.testflag & T_CHECK_ONLY_CHANGED) &&
652
!(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
653
STATE_CRASHED_ON_REPAIR)) &&
654
share->state.open_count == 0) ||
655
((param.testflag & T_FAST) && (share->state.open_count ==
656
(uint) (share->global_changed ? 1 : 0)))))
657
return HA_ADMIN_ALREADY_DONE;
659
error = chk_status(¶m, file); // Not fatal
660
error = chk_size(¶m, file);
662
error |= chk_del(¶m, file, param.testflag);
664
error = chk_key(¶m, file);
667
if ((!(param.testflag & T_QUICK) &&
669
(HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ||
670
(param.testflag & (T_EXTEND | T_MEDIUM)))) ||
673
uint32_t old_testflag=param.testflag;
674
param.testflag|=T_MEDIUM;
675
if (!(error= init_io_cache(¶m.read_cache, file->dfile,
676
my_default_record_cache_size, READ_CACHE,
677
share->pack.header_length, 1, MYF(MY_WME))))
679
error= chk_data_link(¶m, file, param.testflag & T_EXTEND);
680
end_io_cache(&(param.read_cache));
682
param.testflag= old_testflag;
687
if ((share->state.changed & (STATE_CHANGED |
688
STATE_CRASHED_ON_REPAIR |
689
STATE_CRASHED | STATE_NOT_ANALYZED)) ||
690
(param.testflag & T_STATISTICS) ||
693
file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
694
pthread_mutex_lock(&share->intern_lock);
695
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
696
STATE_CRASHED_ON_REPAIR);
697
if (!(table->db_stat & HA_READ_ONLY))
698
error=update_state_info(¶m,file,UPDATE_TIME | UPDATE_OPEN_COUNT |
700
pthread_mutex_unlock(&share->intern_lock);
701
info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
705
else if (!mi_is_crashed(file) && !session->killed)
707
mi_mark_crashed(file);
708
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
711
session->set_proc_info(old_proc_info);
712
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
717
analyze the key distribution in the table
718
As the table may be only locked for read, we have to take into account that
719
two threads may do an analyze at the same time!
722
int ha_myisam::analyze(Session *session,
723
HA_CHECK_OPT* check_opt __attribute__((unused)))
727
MYISAM_SHARE* share = file->s;
729
myisamchk_init(¶m);
730
param.session = session;
731
param.op_name= "analyze";
732
param.db_name= table->s->db.str;
733
param.table_name= table->alias;
734
param.testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
735
T_DONT_CHECK_CHECKSUM);
736
param.using_global_keycache = 1;
737
param.stats_method= (enum_mi_stats_method)session->variables.myisam_stats_method;
739
if (!(share->state.changed & STATE_NOT_ANALYZED))
740
return HA_ADMIN_ALREADY_DONE;
742
error = chk_key(¶m, file);
745
pthread_mutex_lock(&share->intern_lock);
746
error=update_state_info(¶m,file,UPDATE_STAT);
747
pthread_mutex_unlock(&share->intern_lock);
749
else if (!mi_is_crashed(file) && !session->killed)
750
mi_mark_crashed(file);
751
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
755
int ha_myisam::repair(Session* session, HA_CHECK_OPT *check_opt)
759
ha_rows start_records;
761
if (!file) return HA_ADMIN_INTERNAL_ERROR;
763
myisamchk_init(¶m);
764
param.session = session;
765
param.op_name= "repair";
766
param.testflag= ((check_opt->flags & ~(T_EXTEND)) |
767
T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM |
768
(check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT));
769
param.sort_buffer_length= sort_buffer_size;
770
start_records=file->state->records;
771
while ((error=repair(session,param,0)) && param.retry_repair)
773
param.retry_repair=0;
774
if (test_all_bits(param.testflag,
775
(uint) (T_RETRY_WITHOUT_QUICK | T_QUICK)))
777
param.testflag&= ~T_RETRY_WITHOUT_QUICK;
778
errmsg_printf(ERRMSG_LVL_INFO, "Retrying repair of: '%s' without quick",
782
param.testflag&= ~T_QUICK;
783
if ((param.testflag & T_REP_BY_SORT))
785
param.testflag= (param.testflag & ~T_REP_BY_SORT) | T_REP;
786
errmsg_printf(ERRMSG_LVL_INFO, "Retrying repair of: '%s' with keycache",
792
if (!error && start_records != file->state->records &&
793
!(check_opt->flags & T_VERY_SILENT))
795
char llbuff[22],llbuff2[22];
796
errmsg_printf(ERRMSG_LVL_INFO, "Found %s of %s rows when repairing '%s'",
797
llstr(file->state->records, llbuff),
798
llstr(start_records, llbuff2),
804
int ha_myisam::optimize(Session* session, HA_CHECK_OPT *check_opt)
807
if (!file) return HA_ADMIN_INTERNAL_ERROR;
810
myisamchk_init(¶m);
811
param.session = session;
812
param.op_name= "optimize";
813
param.testflag= (check_opt->flags | T_SILENT | T_FORCE_CREATE |
814
T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX);
815
param.sort_buffer_length= sort_buffer_size;
816
if ((error= repair(session,param,1)) && param.retry_repair)
818
errmsg_printf(ERRMSG_LVL_WARN, "Warning: Optimize table got errno %d on %s.%s, retrying",
819
my_errno, param.db_name, param.table_name);
820
param.testflag&= ~T_REP_BY_SORT;
821
error= repair(session,param,1);
674
827
int ha_myisam::repair(Session *session, MI_CHECK ¶m, bool do_optimize)
804
970
update_state_info(¶m, file, 0);
806
972
session->set_proc_info(old_proc_info);
807
mi_lock_database(file,F_UNLCK);
973
if (!session->locked_tables)
974
mi_lock_database(file,F_UNLCK);
809
975
return(error ? HA_ADMIN_FAILED :
810
976
!optimize_done ? HA_ADMIN_ALREADY_DONE : HA_ADMIN_OK);
981
Assign table indexes to a specific key cache.
984
int ha_myisam::assign_to_keycache(Session* session, HA_CHECK_OPT *check_opt)
986
KEY_CACHE *new_key_cache= check_opt->key_cache;
987
const char *errmsg= 0;
988
int error= HA_ADMIN_OK;
990
TableList *table_list= table->pos_in_table_list;
992
table->keys_in_use_for_query.clear_all();
994
if (table_list->process_index_hints(table))
995
return(HA_ADMIN_FAILED);
997
if (!table->keys_in_use_for_query.is_clear_all())
998
/* use all keys if there's no list specified by the user through hints */
999
map= table->keys_in_use_for_query.to_uint64_t();
1001
if ((error= mi_assign_to_key_cache(file, map, new_key_cache)))
1003
char buf[STRING_BUFFER_USUAL_SIZE];
1004
snprintf(buf, sizeof(buf),
1005
"Failed to flush to index file (errno: %d)", error);
1007
error= HA_ADMIN_CORRUPT;
1010
if (error != HA_ADMIN_OK)
1012
/* Send error to user */
1014
myisamchk_init(¶m);
1015
param.session= session;
1016
param.op_name= "assign_to_keycache";
1017
param.db_name= table->s->db.str;
1018
param.table_name= table->s->table_name.str;
1020
mi_check_print_error(¶m, errmsg);
815
1027
Disable indexes, making it persistent if requested.
1036
int ha_myisam::doUpdateRecord(const unsigned char *old_data, unsigned char *new_data)
1247
bool ha_myisam::check_and_repair(Session *session)
1252
uint32_t old_query_length;
1253
HA_CHECK_OPT check_opt;
1256
check_opt.flags= T_MEDIUM | T_AUTO_REPAIR;
1257
// Don't use quick if deleted rows
1258
if (!file->state->del && (myisam_recover_options & HA_RECOVER_QUICK))
1259
check_opt.flags|=T_QUICK;
1260
errmsg_printf(ERRMSG_LVL_WARN, "Checking table: '%s'",table->s->path.str);
1262
old_query= session->query;
1263
old_query_length= session->query_length;
1264
pthread_mutex_lock(&LOCK_thread_count);
1265
session->query= table->s->table_name.str;
1266
session->query_length= table->s->table_name.length;
1267
pthread_mutex_unlock(&LOCK_thread_count);
1269
if ((marked_crashed= mi_is_crashed(file)) || check(session, &check_opt))
1271
errmsg_printf(ERRMSG_LVL_WARN, "Recovering table: '%s'",table->s->path.str);
1273
((myisam_recover_options & HA_RECOVER_BACKUP ? T_BACKUP_DATA : 0) |
1274
(marked_crashed ? 0 : T_QUICK) |
1275
(myisam_recover_options & HA_RECOVER_FORCE ? 0 : T_SAFE_REPAIR) |
1277
if (repair(session, &check_opt))
1280
pthread_mutex_lock(&LOCK_thread_count);
1281
session->query= old_query;
1282
session->query_length= old_query_length;
1283
pthread_mutex_unlock(&LOCK_thread_count);
1287
bool ha_myisam::is_crashed() const
1289
return (file->s->state.changed & STATE_CRASHED ||
1290
(file->s->state.open_count));
1293
int ha_myisam::update_row(const unsigned char *old_data, unsigned char *new_data)
1295
ha_statistic_increment(&SSV::ha_update_count);
1296
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
1297
table->timestamp_field->set_time();
1038
1298
return mi_update(file,old_data,new_data);
1041
int ha_myisam::doDeleteRecord(const unsigned char *buf)
1301
int ha_myisam::delete_row(const unsigned char *buf)
1303
ha_statistic_increment(&SSV::ha_delete_count);
1043
1304
return mi_delete(file,buf);
1047
int ha_myisam::doStartIndexScan(uint32_t idx, bool )
1311
bool index_cond_func_myisam(void *arg)
1313
ha_myisam *h= (ha_myisam*)arg;
1314
/*if (h->in_range_read)*/
1317
if (h->compare_key2(h->end_range) > 0)
1318
return 2; /* caller should return HA_ERR_END_OF_FILE already */
1320
return (bool)h->pushed_idx_cond->val_int();
1328
int ha_myisam::index_init(uint32_t idx, bool sorted __attribute__((unused)))
1049
1330
active_index=idx;
1050
1331
//in_range_read= false;
1332
if (pushed_idx_cond_keyno == idx)
1333
mi_set_index_cond_func(file, index_cond_func_myisam, this);
1055
int ha_myisam::doEndIndexScan()
1338
int ha_myisam::index_end()
1057
1340
active_index=MAX_KEY;
1341
//pushed_idx_cond_keyno= MAX_KEY;
1342
mi_set_index_cond_func(file, NULL, 0);
1343
in_range_check_pushed_down= false;
1344
ds_mrr.dsmrr_close();
1349
uint32_t ha_myisam::index_flags(uint32_t inx, uint32_t, bool) const
1351
return ((table_share->key_info[inx].algorithm == HA_KEY_ALG_FULLTEXT) ?
1352
0 : HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE |
1353
HA_READ_ORDER | HA_KEYREAD_ONLY |
1354
(keys_with_parts.is_set(inx)?0:HA_DO_INDEX_COND_PUSHDOWN));
1062
1358
int ha_myisam::index_read_map(unsigned char *buf, const unsigned char *key,
1063
1359
key_part_map keypart_map,
1064
1360
enum ha_rkey_function find_flag)
1066
1362
assert(inited==INDEX);
1067
ha_statistic_increment(&system_status_var::ha_read_key_count);
1363
ha_statistic_increment(&SSV::ha_read_key_count);
1068
1364
int error=mi_rkey(file, buf, active_index, key, keypart_map, find_flag);
1069
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1365
table->status=error ? STATUS_NOT_FOUND: 0;
1084
1380
key_part_map keypart_map)
1086
1382
assert(inited==INDEX);
1087
ha_statistic_increment(&system_status_var::ha_read_key_count);
1383
ha_statistic_increment(&SSV::ha_read_key_count);
1088
1384
int error=mi_rkey(file, buf, active_index, key, keypart_map,
1089
1385
HA_READ_PREFIX_LAST);
1090
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1386
table->status=error ? STATUS_NOT_FOUND: 0;
1094
1390
int ha_myisam::index_next(unsigned char *buf)
1096
1392
assert(inited==INDEX);
1097
ha_statistic_increment(&system_status_var::ha_read_next_count);
1393
ha_statistic_increment(&SSV::ha_read_next_count);
1098
1394
int error=mi_rnext(file,buf,active_index);
1099
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1395
table->status=error ? STATUS_NOT_FOUND: 0;
1103
1399
int ha_myisam::index_prev(unsigned char *buf)
1105
1401
assert(inited==INDEX);
1106
ha_statistic_increment(&system_status_var::ha_read_prev_count);
1402
ha_statistic_increment(&SSV::ha_read_prev_count);
1107
1403
int error=mi_rprev(file,buf, active_index);
1108
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1404
table->status=error ? STATUS_NOT_FOUND: 0;
1112
1408
int ha_myisam::index_first(unsigned char *buf)
1114
1410
assert(inited==INDEX);
1115
ha_statistic_increment(&system_status_var::ha_read_first_count);
1411
ha_statistic_increment(&SSV::ha_read_first_count);
1116
1412
int error=mi_rfirst(file, buf, active_index);
1117
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1413
table->status=error ? STATUS_NOT_FOUND: 0;
1121
1417
int ha_myisam::index_last(unsigned char *buf)
1123
1419
assert(inited==INDEX);
1124
ha_statistic_increment(&system_status_var::ha_read_last_count);
1420
ha_statistic_increment(&SSV::ha_read_last_count);
1125
1421
int error=mi_rlast(file, buf, active_index);
1126
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1422
table->status=error ? STATUS_NOT_FOUND: 0;
1130
1426
int ha_myisam::index_next_same(unsigned char *buf,
1131
const unsigned char *,
1427
const unsigned char *key __attribute__((unused)),
1428
uint32_t length __attribute__((unused)))
1135
1431
assert(inited==INDEX);
1136
ha_statistic_increment(&system_status_var::ha_read_next_count);
1432
ha_statistic_increment(&SSV::ha_read_next_count);
1139
1435
error= mi_rnext_same(file,buf);
1140
1436
} while (error == HA_ERR_RECORD_DELETED);
1141
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1437
table->status=error ? STATUS_NOT_FOUND: 0;
1217
1518
if (flag & HA_STATUS_CONST)
1219
TableShare *share= getTable()->getMutableShare();
1520
TABLE_SHARE *share= table->s;
1220
1521
stats.max_data_file_length= misam_info.max_data_file_length;
1221
1522
stats.max_index_file_length= misam_info.max_index_file_length;
1222
1523
stats.create_time= misam_info.create_time;
1223
1524
ref_length= misam_info.reflength;
1224
1525
share->db_options_in_use= misam_info.options;
1225
stats.block_size= myisam_key_cache_block_size; /* record block size */
1526
stats.block_size= block_size; /* record block size */
1227
set_prefix(share->keys_in_use, share->sizeKeys());
1229
* Due to bug 394932 (32-bit solaris build failure), we need
1230
* to convert the uint64_t key_map member of the misam_info
1231
* structure in to a std::bitset so that we can logically and
1232
* it with the share->key_in_use key_map.
1235
string binary_key_map;
1236
uint64_t num= misam_info.key_map;
1238
* Convert the uint64_t to a binary
1239
* string representation of it.
1243
uint64_t bin_digit= num % 2;
1247
binary_key_map.append(ostr.str());
1249
* Now we have the binary string representation of the
1250
* flags, we need to fill that string representation out
1251
* with the appropriate number of bits. This is needed
1252
* since key_map is declared as a std::bitset of a certain bit
1253
* width that depends on the MAX_INDEXES variable.
1255
if (MAX_INDEXES <= 64)
1257
size_t len= 72 - binary_key_map.length();
1258
string all_zeros(len, '0');
1259
binary_key_map.insert(binary_key_map.begin(),
1265
size_t len= (MAX_INDEXES + 7) / 8 * 8;
1266
string all_zeros(len, '0');
1267
binary_key_map.insert(binary_key_map.begin(),
1271
key_map tmp_map(binary_key_map);
1272
share->keys_in_use&= tmp_map;
1273
share->keys_for_keyread&= share->keys_in_use;
1529
if (share->tmp_table == NO_TMP_TABLE)
1530
pthread_mutex_lock(&share->mutex);
1531
share->keys_in_use.set_prefix(share->keys);
1532
share->keys_in_use.intersect_extended(misam_info.key_map);
1533
share->keys_for_keyread.intersect(share->keys_in_use);
1274
1534
share->db_record_offset= misam_info.record_offset;
1275
1535
if (share->key_parts)
1276
memcpy(getTable()->key_info[0].rec_per_key,
1536
memcpy(table->key_info[0].rec_per_key,
1277
1537
misam_info.rec_per_key,
1278
sizeof(getTable()->key_info[0].rec_per_key)*share->key_parts);
1279
assert(share->getType() != message::Table::STANDARD);
1538
sizeof(table->key_info[0].rec_per_key)*share->key_parts);
1539
if (share->tmp_table == NO_TMP_TABLE)
1540
pthread_mutex_unlock(&share->mutex);
1282
1543
Set data_file_name and index_file_name to point at the symlink value
1283
1544
if table is symlinked (Ie; Real name is not same as generated name)
1285
1546
data_file_name= index_file_name= 0;
1286
internal::fn_format(name_buff, file->filename, "", MI_NAME_DEXT,
1547
fn_format(name_buff, file->filename, "", MI_NAME_DEXT,
1287
1548
MY_APPEND_EXT | MY_UNPACK_FILENAME);
1288
1549
if (strcmp(name_buff, misam_info.data_file_name))
1289
1550
data_file_name=misam_info.data_file_name;
1290
internal::fn_format(name_buff, file->filename, "", MI_NAME_IEXT,
1551
fn_format(name_buff, file->filename, "", MI_NAME_IEXT,
1291
1552
MY_APPEND_EXT | MY_UNPACK_FILENAME);
1292
1553
if (strcmp(name_buff, misam_info.index_file_name))
1293
1554
index_file_name=misam_info.index_file_name;
1328
1593
return mi_delete_all_rows(file);
1331
int MyisamEngine::doDropTable(Session &session,
1332
const TableIdentifier &identifier)
1596
int ha_myisam::delete_table(const char *name)
1334
session.getMessageCache().removeTableMessage(identifier);
1336
return mi_delete_table(identifier.getPath().c_str());
1598
return mi_delete_table(name);
1340
1602
int ha_myisam::external_lock(Session *session, int lock_type)
1342
file->in_use= session;
1343
return mi_lock_database(file, !getTable()->getShare()->getType() ?
1604
file->in_use.data= session;
1605
return mi_lock_database(file, !table->s->tmp_table ?
1344
1606
lock_type : ((lock_type == F_UNLCK) ?
1345
1607
F_UNLCK : F_EXTRA_LCK));
1348
int MyisamEngine::doCreateTable(Session &session,
1350
const TableIdentifier &identifier,
1351
message::Table& create_proto)
1610
THR_LOCK_DATA **ha_myisam::store_lock(Session *session __attribute__((unused)),
1612
enum thr_lock_type lock_type)
1614
if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
1615
file->lock.type=lock_type;
1620
void ha_myisam::update_create_info(HA_CREATE_INFO *create_info)
1622
ha_myisam::info(HA_STATUS_AUTO | HA_STATUS_CONST);
1623
if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
1625
create_info->auto_increment_value= stats.auto_increment_value;
1627
create_info->data_file_name=data_file_name;
1628
create_info->index_file_name=index_file_name;
1632
int ha_myisam::create(const char *name, register Table *table_arg,
1633
HA_CREATE_INFO *ha_create_info)
1354
uint32_t create_flags= 0, create_records;
1636
uint32_t create_flags= 0, records;
1355
1637
char buff[FN_REFLEN];
1356
1638
MI_KEYDEF *keydef;
1357
1639
MI_COLUMNDEF *recinfo;
1358
1640
MI_CREATE_INFO create_info;
1359
TableShare *share= table_arg.getMutableShare();
1641
TABLE_SHARE *share= table_arg->s;
1360
1642
uint32_t options= share->db_options_in_use;
1361
if ((error= table2myisam(&table_arg, &keydef, &recinfo, &create_records)))
1643
if ((error= table2myisam(table_arg, &keydef, &recinfo, &records)))
1644
return(error); /* purecov: inspected */
1363
1645
memset(&create_info, 0, sizeof(create_info));
1364
create_info.max_rows= create_proto.options().max_rows();
1365
create_info.reloc_rows= create_proto.options().min_rows();
1646
create_info.max_rows= share->max_rows;
1647
create_info.reloc_rows= share->min_rows;
1366
1648
create_info.with_auto_increment= share->next_number_key_offset == 0;
1367
create_info.auto_increment= (create_proto.options().has_auto_increment_value() ?
1368
create_proto.options().auto_increment_value() -1 :
1649
create_info.auto_increment= (ha_create_info->auto_increment_value ?
1650
ha_create_info->auto_increment_value -1 :
1370
create_info.data_file_length= (create_proto.options().max_rows() *
1371
create_proto.options().avg_row_length());
1372
create_info.data_file_name= NULL;
1373
create_info.index_file_name= NULL;
1652
create_info.data_file_length= ((uint64_t) share->max_rows *
1653
share->avg_row_length);
1654
create_info.data_file_name= ha_create_info->data_file_name;
1655
create_info.index_file_name= ha_create_info->index_file_name;
1374
1656
create_info.language= share->table_charset->number;
1376
if (create_proto.type() == message::Table::TEMPORARY)
1658
if (ha_create_info->options & HA_LEX_CREATE_TMP_TABLE)
1377
1659
create_flags|= HA_CREATE_TMP_TABLE;
1660
if (ha_create_info->options & HA_CREATE_KEEP_FILES)
1661
create_flags|= HA_CREATE_KEEP_FILES;
1378
1662
if (options & HA_OPTION_PACK_RECORD)
1379
1663
create_flags|= HA_PACK_RECORD;
1664
if (options & HA_OPTION_CHECKSUM)
1665
create_flags|= HA_CREATE_CHECKSUM;
1666
if (options & HA_OPTION_DELAY_KEY_WRITE)
1667
create_flags|= HA_CREATE_DELAY_KEY_WRITE;
1381
/* TODO: Check that the following internal::fn_format is really needed */
1382
error= mi_create(internal::fn_format(buff, identifier.getPath().c_str(), "", "",
1383
MY_UNPACK_FILENAME|MY_APPEND_EXT),
1384
share->sizeKeys(), keydef,
1385
create_records, recinfo,
1669
/* TODO: Check that the following fn_format is really needed */
1670
error= mi_create(fn_format(buff, name, "", "",
1671
MY_UNPACK_FILENAME|MY_APPEND_EXT),
1672
share->keys, keydef,
1386
1674
0, (MI_UNIQUEDEF*) 0,
1387
1675
&create_info, create_flags);
1388
1676
free((unsigned char*) recinfo);
1390
session.getMessageCache().storeTableMessage(identifier, create_proto);
1396
int MyisamEngine::doRenameTable(Session &session, const TableIdentifier &from, const TableIdentifier &to)
1681
int ha_myisam::rename_table(const char * from, const char * to)
1398
session.getMessageCache().renameTableMessage(from, to);
1400
return mi_rename(from.getPath().c_str(), to.getPath().c_str());
1683
return mi_rename(from,to);
1404
void ha_myisam::get_auto_increment(uint64_t ,
1687
void ha_myisam::get_auto_increment(uint64_t offset __attribute__((unused)),
1688
uint64_t increment __attribute__((unused)),
1689
uint64_t nb_desired_values __attribute__((unused)),
1407
1690
uint64_t *first_value,
1408
1691
uint64_t *nb_reserved_values)
1487
1770
return (uint)file->state->checksum;
1490
static int myisam_init(module::Context &context)
1492
context.add(new MyisamEngine(engine_name));
1493
context.registerVariable(new sys_var_constrained_value<size_t>("sort-buffer-size",
1495
context.registerVariable(new sys_var_uint64_t_ptr("max_sort_file_size",
1496
&max_sort_file_size,
1497
context.getOptions()["max-sort-file-size"].as<uint64_t>()));
1774
bool ha_myisam::check_if_incompatible_data(HA_CREATE_INFO *info,
1775
uint32_t table_changes)
1777
uint32_t options= table->s->db_options_in_use;
1779
if (info->auto_increment_value != stats.auto_increment_value ||
1780
info->data_file_name != data_file_name ||
1781
info->index_file_name != index_file_name ||
1782
table_changes == IS_EQUAL_NO ||
1783
table_changes & IS_EQUAL_PACK_LENGTH) // Not implemented yet
1784
return COMPATIBLE_DATA_NO;
1786
if ((options & (HA_OPTION_PACK_RECORD | HA_OPTION_CHECKSUM |
1787
HA_OPTION_DELAY_KEY_WRITE)) !=
1788
(info->table_options & (HA_OPTION_PACK_RECORD | HA_OPTION_CHECKSUM |
1789
HA_OPTION_DELAY_KEY_WRITE)))
1790
return COMPATIBLE_DATA_NO;
1791
return COMPATIBLE_DATA_YES;
1794
int myisam_deinit(void *hton __attribute__((unused)))
1796
pthread_mutex_destroy(&THR_LOCK_myisam);
1798
return mi_panic(HA_PANIC_CLOSE);
1801
static int myisam_init(void *p)
1803
handlerton *myisam_hton;
1805
myisam_hton= (handlerton *)p;
1806
myisam_hton->state= SHOW_OPTION_YES;
1807
myisam_hton->create= myisam_create_handler;
1808
myisam_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES;
1503
static void init_options(drizzled::module::option_context &context)
1505
context("max-sort-file-size",
1506
po::value<uint64_t>(&max_sort_file_size)->default_value(INT32_MAX),
1507
N_("Don't use the fast sort index method to created index if the temporary file would get bigger than this."));
1508
context("sort-buffer-size",
1509
po::value<sort_buffer_constraint>(&sort_buffer_size)->default_value(8192*1024),
1510
N_("The buffer that is allocated when sorting the index when doing a REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE."));
1514
DRIZZLE_DECLARE_PLUGIN
1814
/****************************************************************************
1815
* MyISAM MRR implementation: use DS-MRR
1816
***************************************************************************/
1818
int ha_myisam::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
1819
uint32_t n_ranges, uint32_t mode,
1820
HANDLER_BUFFER *buf)
1822
return ds_mrr.dsmrr_init(this, &table->key_info[active_index],
1823
seq, seq_init_param, n_ranges, mode, buf);
1826
int ha_myisam::multi_range_read_next(char **range_info)
1828
return ds_mrr.dsmrr_next(this, range_info);
1831
ha_rows ha_myisam::multi_range_read_info_const(uint32_t keyno, RANGE_SEQ_IF *seq,
1832
void *seq_init_param,
1833
uint32_t n_ranges, uint32_t *bufsz,
1834
uint32_t *flags, COST_VECT *cost)
1837
This call is here because there is no location where this->table would
1839
TODO: consider moving it into some per-query initialization call.
1841
ds_mrr.init(this, table);
1842
return ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges, bufsz,
1846
int ha_myisam::multi_range_read_info(uint32_t keyno, uint32_t n_ranges, uint32_t keys,
1847
uint32_t *bufsz, uint32_t *flags, COST_VECT *cost)
1849
ds_mrr.init(this, table);
1850
return ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost);
1853
/* MyISAM MRR implementation ends */
1856
/* Index condition pushdown implementation*/
1859
Item *ha_myisam::idx_cond_push(uint32_t keyno_arg, Item* idx_cond_arg)
1861
pushed_idx_cond_keyno= keyno_arg;
1862
pushed_idx_cond= idx_cond_arg;
1863
in_range_check_pushed_down= true;
1864
if (active_index == pushed_idx_cond_keyno)
1865
mi_set_index_cond_func(file, index_cond_func_myisam, this);
1869
static DRIZZLE_SYSVAR_UINT(block_size, block_size,
1870
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1871
N_("Block size to be used for MyISAM index pages."),
1872
NULL, NULL, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
1873
MI_MAX_KEY_BLOCK_LENGTH, 0);
1875
static DRIZZLE_SYSVAR_UINT(repair_threads, repair_threads,
1876
PLUGIN_VAR_RQCMDARG,
1877
N_("Number of threads to use when repairing MyISAM tables. The value of "
1878
"1 disables parallel repair."),
1879
NULL, NULL, 1, 1, UINT32_MAX, 0);
1881
static DRIZZLE_SYSVAR_ULONGLONG(max_sort_file_size, max_sort_file_size,
1882
PLUGIN_VAR_RQCMDARG,
1883
N_("Don't use the fast sort index method to created index if the temporary file would get bigger than this."),
1884
NULL, NULL, INT32_MAX, 0, UINT64_MAX, 0);
1886
static DRIZZLE_SYSVAR_ULONGLONG(sort_buffer_size, sort_buffer_size,
1887
PLUGIN_VAR_RQCMDARG,
1888
N_("The buffer that is allocated when sorting the index when doing a REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE."),
1889
NULL, NULL, 8192*1024, 1024, UINT64_MAX, 0);
1891
extern uint32_t data_pointer_size;
1892
static DRIZZLE_SYSVAR_UINT(data_pointer_size, data_pointer_size,
1893
PLUGIN_VAR_RQCMDARG,
1894
N_("Default pointer size to be used for MyISAM tables."),
1895
NULL, NULL, 6, 2, 7, 0);
1897
static struct st_mysql_sys_var* system_variables[]= {
1898
DRIZZLE_SYSVAR(block_size),
1899
DRIZZLE_SYSVAR(repair_threads),
1900
DRIZZLE_SYSVAR(max_sort_file_size),
1901
DRIZZLE_SYSVAR(sort_buffer_size),
1902
DRIZZLE_SYSVAR(data_pointer_size),
1907
mysql_declare_plugin(myisam)
1909
DRIZZLE_STORAGE_ENGINE_PLUGIN,
1520
1913
"Default engine as of MySQL 3.23 with great performance",
1521
1914
PLUGIN_LICENSE_GPL,
1522
1915
myisam_init, /* Plugin Init */
1523
NULL, /* system variables */
1524
init_options /* config options */
1916
myisam_deinit, /* Plugin Deinit */
1917
NULL, /* status variables */
1918
system_variables, /* system variables */
1919
NULL /* config options */
1526
DRIZZLE_DECLARE_PLUGIN_END;
1921
mysql_declare_plugin_end;