diff options
Diffstat (limited to 'sql/sql_table.cc')
-rw-r--r-- | sql/sql_table.cc | 255 |
1 files changed, 148 insertions, 107 deletions
diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 541a7909f46..ce9d91bec72 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2011, Oracle and/or its affiliates. + Copyright (c) 2000, 2012, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -618,13 +618,6 @@ uint build_tmptable_filename(THD* thd, char *buff, size_t bufflen) struct st_global_ddl_log { - /* - We need to adjust buffer size to be able to handle downgrades/upgrades - where IO_SIZE has changed. We'll set the buffer size such that we can - handle that the buffer size was upto 4 times bigger in the version - that wrote the DDL log. - */ - char file_entry_buf[4*IO_SIZE]; char file_name_str[FN_REFLEN]; char *file_name; DDL_LOG_MEMORY_ENTRY *first_free; @@ -652,51 +645,60 @@ pthread_mutex_t LOCK_gdl; #define DDL_LOG_NUM_ENTRY_POS 0 #define DDL_LOG_NAME_LEN_POS 4 #define DDL_LOG_IO_SIZE_POS 8 +#define DDL_LOG_HEADER_SIZE 12 -/* - Read one entry from ddl log file - SYNOPSIS - read_ddl_log_file_entry() - entry_no Entry number to read - RETURN VALUES - TRUE Error - FALSE Success +/** + Read one entry from ddl log file. + @param[out] file_entry_buf Buffer to read into + @param entry_no Entry number to read + @param size Number of bytes of the entry to read + + @return Operation status + @retval true Error + @retval false Success */ -static bool read_ddl_log_file_entry(uint entry_no) +static bool read_ddl_log_file_entry(uchar *file_entry_buf, + uint entry_no, + uint size) { bool error= FALSE; File file_id= global_ddl_log.file_id; - uchar *file_entry_buf= (uchar*)global_ddl_log.file_entry_buf; uint io_size= global_ddl_log.io_size; DBUG_ENTER("read_ddl_log_file_entry"); + DBUG_ASSERT(io_size >= size); - if (my_pread(file_id, file_entry_buf, io_size, io_size * entry_no, - MYF(MY_WME)) != io_size) + if (my_pread(file_id, file_entry_buf, size, io_size * entry_no, + MYF(MY_WME)) != size) error= TRUE; DBUG_RETURN(error); } -/* - Write one entry from ddl log file - SYNOPSIS - write_ddl_log_file_entry() - entry_no Entry number to write - RETURN VALUES - TRUE Error - FALSE Success +/** + Write one entry to ddl log file. + + @param file_entry_buf Buffer to write + @param entry_no Entry number to write + @param size Number of bytes of the entry to write + + @return Operation status + @retval true Error + @retval false Success */ -static bool write_ddl_log_file_entry(uint entry_no) +static bool write_ddl_log_file_entry(uchar *file_entry_buf, + uint entry_no, + uint size) { bool error= FALSE; File file_id= global_ddl_log.file_id; - char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; + uint io_size= global_ddl_log.io_size; DBUG_ENTER("write_ddl_log_file_entry"); + DBUG_ASSERT(io_size >= size); - if (my_pwrite(file_id, (uchar*)file_entry_buf, - IO_SIZE, IO_SIZE * entry_no, MYF(MY_WME)) != IO_SIZE) + if (my_pwrite(file_id, file_entry_buf, size, + io_size * entry_no, MYF(MY_WME)) != size) error= TRUE; DBUG_RETURN(error); } @@ -715,17 +717,20 @@ static bool write_ddl_log_header() { uint16 const_var; bool error= FALSE; + uchar file_entry_buf[DDL_LOG_HEADER_SIZE]; DBUG_ENTER("write_ddl_log_header"); + DBUG_ASSERT((DDL_LOG_NAME_POS + 3 * global_ddl_log.name_len) + <= global_ddl_log.io_size); - int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NUM_ENTRY_POS], + int4store(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS], global_ddl_log.num_entries); - const_var= FN_LEN; - int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_LEN_POS], + const_var= global_ddl_log.name_len; + int4store(&file_entry_buf[DDL_LOG_NAME_LEN_POS], (ulong) const_var); - const_var= IO_SIZE; - int4store(&global_ddl_log.file_entry_buf[DDL_LOG_IO_SIZE_POS], + const_var= global_ddl_log.io_size; + int4store(&file_entry_buf[DDL_LOG_IO_SIZE_POS], (ulong) const_var); - if (write_ddl_log_file_entry(0UL)) + if (write_ddl_log_file_entry(file_entry_buf, 0UL, DDL_LOG_HEADER_SIZE)) { sql_print_error("Error writing ddl log header"); DBUG_RETURN(TRUE); @@ -765,17 +770,19 @@ static inline void create_ddl_log_file_name(char *file_name) static uint read_ddl_log_header() { - char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; + char file_entry_buf[DDL_LOG_HEADER_SIZE]; char file_name[FN_REFLEN]; uint entry_no; bool successful_open= FALSE; DBUG_ENTER("read_ddl_log_header"); + DBUG_ASSERT(global_ddl_log.io_size <= IO_SIZE); create_ddl_log_file_name(file_name); if ((global_ddl_log.file_id= my_open(file_name, O_RDWR | O_BINARY, MYF(0))) >= 0) { - if (read_ddl_log_file_entry(0UL)) + if (read_ddl_log_file_entry((uchar *) file_entry_buf, 0UL, + DDL_LOG_HEADER_SIZE)) { /* Write message into error log */ sql_print_error("Failed to read ddl log file in recovery"); @@ -788,8 +795,6 @@ static uint read_ddl_log_header() entry_no= uint4korr(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS]); global_ddl_log.name_len= uint4korr(&file_entry_buf[DDL_LOG_NAME_LEN_POS]); global_ddl_log.io_size= uint4korr(&file_entry_buf[DDL_LOG_IO_SIZE_POS]); - DBUG_ASSERT(global_ddl_log.io_size <= - sizeof(global_ddl_log.file_entry_buf)); } else { @@ -804,30 +809,22 @@ static uint read_ddl_log_header() } -/* - Read a ddl log entry - SYNOPSIS - read_ddl_log_entry() - read_entry Number of entry to read - out:entry_info Information from entry - RETURN VALUES - TRUE Error - FALSE Success - DESCRIPTION - Read a specified entry in the ddl log +/** + Set ddl log entry struct from buffer + @param read_entry Entry number + @param file_entry_buf Buffer to use + @param ddl_log_entry Entry to be set + + @note Pointers in ddl_log_entry will point into file_entry_buf! */ -bool read_ddl_log_entry(uint read_entry, DDL_LOG_ENTRY *ddl_log_entry) +static void set_ddl_log_entry_from_buf(uint read_entry, + uchar *file_entry_buf, + DDL_LOG_ENTRY *ddl_log_entry) { - char *file_entry_buf= (char*)&global_ddl_log.file_entry_buf; uint inx; uchar single_char; - DBUG_ENTER("read_ddl_log_entry"); - - if (read_ddl_log_file_entry(read_entry)) - { - DBUG_RETURN(TRUE); - } + DBUG_ENTER("set_ddl_log_entry_from_buf"); ddl_log_entry->entry_pos= read_entry; single_char= file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]; ddl_log_entry->entry_type= (enum ddl_log_entry_code)single_char; @@ -835,14 +832,14 @@ bool read_ddl_log_entry(uint read_entry, DDL_LOG_ENTRY *ddl_log_entry) ddl_log_entry->action_type= (enum ddl_log_action_code)single_char; ddl_log_entry->phase= file_entry_buf[DDL_LOG_PHASE_POS]; ddl_log_entry->next_entry= uint4korr(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS]); - ddl_log_entry->name= &file_entry_buf[DDL_LOG_NAME_POS]; + ddl_log_entry->name= (char*) &file_entry_buf[DDL_LOG_NAME_POS]; inx= DDL_LOG_NAME_POS + global_ddl_log.name_len; - ddl_log_entry->from_name= &file_entry_buf[inx]; + ddl_log_entry->from_name= (char*) &file_entry_buf[inx]; inx+= global_ddl_log.name_len; - ddl_log_entry->handler_name= &file_entry_buf[inx]; - DBUG_RETURN(FALSE); + ddl_log_entry->handler_name= (char*) &file_entry_buf[inx]; + DBUG_VOID_RETURN; } - + /* Initialise ddl log @@ -1045,6 +1042,7 @@ static bool get_free_ddl_log_entry(DDL_LOG_MEMORY_ENTRY **active_entry, DDL_LOG_MEMORY_ENTRY *first_used= global_ddl_log.first_used; DBUG_ENTER("get_free_ddl_log_entry"); + safe_mutex_assert_owner(&LOCK_gdl); if (global_ddl_log.first_free == NULL) { if (!(used_entry= (DDL_LOG_MEMORY_ENTRY*)my_malloc( @@ -1101,34 +1099,36 @@ bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, DDL_LOG_MEMORY_ENTRY **active_entry) { bool error, write_header; + char file_entry_buf[IO_SIZE]; DBUG_ENTER("write_ddl_log_entry"); if (init_ddl_log()) { DBUG_RETURN(TRUE); } - global_ddl_log.file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= + memset(file_entry_buf, 0, sizeof(file_entry_buf)); + file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_LOG_ENTRY_CODE; - global_ddl_log.file_entry_buf[DDL_LOG_ACTION_TYPE_POS]= + file_entry_buf[DDL_LOG_ACTION_TYPE_POS]= (char)ddl_log_entry->action_type; - global_ddl_log.file_entry_buf[DDL_LOG_PHASE_POS]= 0; - int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], + file_entry_buf[DDL_LOG_PHASE_POS]= 0; + int4store(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], ddl_log_entry->next_entry); - DBUG_ASSERT(strlen(ddl_log_entry->name) < FN_LEN); - strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS], - ddl_log_entry->name, FN_LEN - 1); + DBUG_ASSERT(strlen(ddl_log_entry->name) < global_ddl_log.name_len); + strmake(&file_entry_buf[DDL_LOG_NAME_POS], ddl_log_entry->name, + global_ddl_log.name_len - 1); if (ddl_log_entry->action_type == DDL_LOG_RENAME_ACTION || ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION) { - DBUG_ASSERT(strlen(ddl_log_entry->from_name) < FN_LEN); - strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_LEN], - ddl_log_entry->from_name, FN_LEN - 1); + DBUG_ASSERT(strlen(ddl_log_entry->from_name) < global_ddl_log.name_len); + strmake(&file_entry_buf[DDL_LOG_NAME_POS + global_ddl_log.name_len], + ddl_log_entry->from_name, global_ddl_log.name_len - 1); } else - global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_LEN]= 0; - DBUG_ASSERT(strlen(ddl_log_entry->handler_name) < FN_LEN); - strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + (2*FN_LEN)], - ddl_log_entry->handler_name, FN_LEN - 1); + file_entry_buf[DDL_LOG_NAME_POS + global_ddl_log.name_len]= 0; + DBUG_ASSERT(strlen(ddl_log_entry->handler_name) < global_ddl_log.name_len); + strmake(&file_entry_buf[DDL_LOG_NAME_POS + (2*global_ddl_log.name_len)], + ddl_log_entry->handler_name, global_ddl_log.name_len - 1); if (get_free_ddl_log_entry(active_entry, &write_header)) { DBUG_RETURN(TRUE); @@ -1136,14 +1136,15 @@ bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, error= FALSE; DBUG_PRINT("ddl_log", ("write type %c next %u name '%s' from_name '%s' handler '%s'", - (char) global_ddl_log.file_entry_buf[DDL_LOG_ACTION_TYPE_POS], + (char) file_entry_buf[DDL_LOG_ACTION_TYPE_POS], ddl_log_entry->next_entry, - (char*) &global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS], - (char*) &global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS - + FN_LEN], - (char*) &global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS - + (2*FN_LEN)])); - if (write_ddl_log_file_entry((*active_entry)->entry_pos)) + (char*) &file_entry_buf[DDL_LOG_NAME_POS], + (char*) &file_entry_buf[DDL_LOG_NAME_POS + + global_ddl_log.name_len], + (char*) &file_entry_buf[DDL_LOG_NAME_POS + + (2*global_ddl_log.name_len)])); + if (write_ddl_log_file_entry((uchar*) file_entry_buf, + (*active_entry)->entry_pos, IO_SIZE)) { error= TRUE; sql_print_error("Failed to write entry_no = %u", @@ -1193,13 +1194,14 @@ bool write_execute_ddl_log_entry(uint first_entry, DDL_LOG_MEMORY_ENTRY **active_entry) { bool write_header= FALSE; - char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; + char file_entry_buf[IO_SIZE]; DBUG_ENTER("write_execute_ddl_log_entry"); if (init_ddl_log()) { DBUG_RETURN(TRUE); } + memset(file_entry_buf, 0, sizeof(file_entry_buf)); if (!complete) { /* @@ -1213,12 +1215,7 @@ bool write_execute_ddl_log_entry(uint first_entry, } else file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_IGNORE_LOG_ENTRY_CODE; - file_entry_buf[DDL_LOG_ACTION_TYPE_POS]= 0; /* Ignored for execute entries */ - file_entry_buf[DDL_LOG_PHASE_POS]= 0; int4store(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], first_entry); - file_entry_buf[DDL_LOG_NAME_POS]= 0; - file_entry_buf[DDL_LOG_NAME_POS + FN_LEN]= 0; - file_entry_buf[DDL_LOG_NAME_POS + 2*FN_LEN]= 0; if (!(*active_entry)) { if (get_free_ddl_log_entry(active_entry, &write_header)) @@ -1226,7 +1223,9 @@ bool write_execute_ddl_log_entry(uint first_entry, DBUG_RETURN(TRUE); } } - if (write_ddl_log_file_entry((*active_entry)->entry_pos)) + if (write_ddl_log_file_entry((uchar*) file_entry_buf, + (*active_entry)->entry_pos, + IO_SIZE)) { sql_print_error("Error writing execute entry in ddl log"); release_ddl_log_memory_entry(*active_entry); @@ -1271,10 +1270,16 @@ bool write_execute_ddl_log_entry(uint first_entry, bool deactivate_ddl_log_entry(uint entry_no) { - char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; + uchar file_entry_buf[DDL_LOG_NAME_POS]; DBUG_ENTER("deactivate_ddl_log_entry"); - if (!read_ddl_log_file_entry(entry_no)) + + /* + Only need to read and write the first bytes of the entry, where + ENTRY_TYPE, ACTION_TYPE and PHASE reside. Using DDL_LOG_NAME_POS + to include all info except for the names. + */ + if (!read_ddl_log_file_entry(file_entry_buf, entry_no, DDL_LOG_NAME_POS)) { if (file_entry_buf[DDL_LOG_ENTRY_TYPE_POS] == DDL_LOG_ENTRY_CODE) { @@ -1292,7 +1297,7 @@ bool deactivate_ddl_log_entry(uint entry_no) { DBUG_ASSERT(0); } - if (write_ddl_log_file_entry(entry_no)) + if (write_ddl_log_file_entry(file_entry_buf, entry_no, DDL_LOG_NAME_POS)) { sql_print_error("Error in deactivating log entry. Position = %u", entry_no); @@ -1353,6 +1358,7 @@ void release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry) DDL_LOG_MEMORY_ENTRY *next_log_entry= log_entry->next_log_entry; DDL_LOG_MEMORY_ENTRY *prev_log_entry= log_entry->prev_log_entry; DBUG_ENTER("release_ddl_log_memory_entry"); + safe_mutex_assert_owner(&LOCK_gdl); global_ddl_log.first_free= log_entry; log_entry->next_log_entry= first_free; @@ -1382,24 +1388,26 @@ bool execute_ddl_log_entry(THD *thd, uint first_entry) { DDL_LOG_ENTRY ddl_log_entry; uint read_entry= first_entry; + uchar file_entry_buf[IO_SIZE]; DBUG_ENTER("execute_ddl_log_entry"); pthread_mutex_lock(&LOCK_gdl); do { - if (read_ddl_log_entry(read_entry, &ddl_log_entry)) + if (read_ddl_log_file_entry(file_entry_buf, read_entry, IO_SIZE)) { - /* Write to error log and continue with next log entry */ + /* Print the error to the log and continue with next log entry */ sql_print_error("Failed to read entry = %u from ddl log", read_entry); break; } + set_ddl_log_entry_from_buf(read_entry, file_entry_buf, &ddl_log_entry); DBUG_ASSERT(ddl_log_entry.entry_type == DDL_LOG_ENTRY_CODE || ddl_log_entry.entry_type == DDL_IGNORE_LOG_ENTRY_CODE); if (execute_ddl_log_action(thd, &ddl_log_entry)) { - /* Write to error log and continue with next log entry */ + /* Print the error to the log and continue with next log entry */ sql_print_error("Failed to execute action for entry = %u from ddl log", read_entry); break; @@ -1444,13 +1452,14 @@ void execute_ddl_log_recovery() uint num_entries, i; THD *thd; DDL_LOG_ENTRY ddl_log_entry; + uchar *file_entry_buf; + uint io_size; char file_name[FN_REFLEN]; DBUG_ENTER("execute_ddl_log_recovery"); /* Initialise global_ddl_log struct */ - bzero(global_ddl_log.file_entry_buf, sizeof(global_ddl_log.file_entry_buf)); global_ddl_log.inited= FALSE; global_ddl_log.recovery_phase= TRUE; global_ddl_log.io_size= IO_SIZE; @@ -1465,14 +1474,23 @@ void execute_ddl_log_recovery() thd->store_globals(); num_entries= read_ddl_log_header(); + io_size= global_ddl_log.io_size; + file_entry_buf= (uchar*) my_malloc(io_size, MYF(0)); + if (!file_entry_buf) + { + sql_print_error("Failed to allocate buffer for recover ddl log"); + DBUG_VOID_RETURN; + } for (i= 1; i < num_entries + 1; i++) { - if (read_ddl_log_entry(i, &ddl_log_entry)) + if (read_ddl_log_file_entry(file_entry_buf, i, io_size)) { sql_print_error("Failed to read entry no = %u from ddl log", i); continue; } + + set_ddl_log_entry_from_buf(i, file_entry_buf, &ddl_log_entry); if (ddl_log_entry.entry_type == DDL_LOG_EXECUTE_CODE) { if (execute_ddl_log_entry(thd, ddl_log_entry.next_entry)) @@ -1487,6 +1505,7 @@ void execute_ddl_log_recovery() VOID(my_delete(file_name, MYF(0))); global_ddl_log.recovery_phase= FALSE; delete thd; + my_free(file_entry_buf, MYF(0)); /* Remember that we don't have a THD */ my_pthread_setspecific_ptr(THR_THD, 0); DBUG_VOID_RETURN; @@ -1503,14 +1522,16 @@ void execute_ddl_log_recovery() void release_ddl_log() { - DDL_LOG_MEMORY_ENTRY *free_list= global_ddl_log.first_free; - DDL_LOG_MEMORY_ENTRY *used_list= global_ddl_log.first_used; + DDL_LOG_MEMORY_ENTRY *free_list; + DDL_LOG_MEMORY_ENTRY *used_list; DBUG_ENTER("release_ddl_log"); if (!global_ddl_log.do_release) DBUG_VOID_RETURN; pthread_mutex_lock(&LOCK_gdl); + free_list= global_ddl_log.first_free; + used_list= global_ddl_log.first_used; while (used_list) { DDL_LOG_MEMORY_ENTRY *tmp= used_list->next_log_entry; @@ -4991,6 +5012,11 @@ send_result_message: case HA_ADMIN_TRY_ALTER: { + uint save_flags; + Alter_info *alter_info= &lex->alter_info; + + /* Store the original value of alter_info->flags */ + save_flags= alter_info->flags; /* This is currently used only by InnoDB. ha_innobase::optimize() answers "try with alter", so here we close the table, do an ALTER TABLE, @@ -4998,9 +5024,18 @@ send_result_message: We have to end the row, so analyze could return more rows. */ protocol->store(STRING_WITH_LEN("note"), system_charset_info); - protocol->store(STRING_WITH_LEN( - "Table does not support optimize, doing recreate + analyze instead"), - system_charset_info); + if(alter_info->flags & ALTER_ADMIN_PARTITION) + { + protocol->store(STRING_WITH_LEN( + "Table does not support optimize on partitions. All partitions " + "will be rebuilt and analyzed."),system_charset_info); + } + else + { + protocol->store(STRING_WITH_LEN( + "Table does not support optimize, doing recreate + analyze instead"), + system_charset_info); + } if (protocol->write()) goto err; DBUG_PRINT("info", ("HA_ADMIN_TRY_ALTER, trying analyze...")); @@ -5014,9 +5049,15 @@ send_result_message: close_thread_tables(thd); if (!result_code) // recreation went ok { + /* + Reset the ALTER_ADMIN_PARTITION bit in alter_info->flags + to force analyze on all partitions. + */ + alter_info->flags &= ~(ALTER_ADMIN_PARTITION); if ((table->table= open_ltable(thd, table, lock_type, 0)) && ((result_code= table->table->file->ha_analyze(thd, check_opt)) > 0)) result_code= 0; // analyze went ok + alter_info->flags= save_flags; } /* Start a new row for the final status row */ protocol->prepare_for_resend(); |