diff options
Diffstat (limited to 'sql/sql_table.cc')
-rw-r--r-- | sql/sql_table.cc | 211 |
1 files changed, 202 insertions, 9 deletions
diff --git a/sql/sql_table.cc b/sql/sql_table.cc index ae4aa8c5cd5..d089d7020ab 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -8912,6 +8912,181 @@ simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list, DBUG_RETURN(error != 0); } +//static void alter_runtime_locks +/* +void free_domain_lookup_element(void *p) +{ + struct Binlog_gtid_state_validator::audit_elem *audit_elem= + (struct Binlog_gtid_state_validator::audit_elem *) p; + delete_dynamic(&audit_elem->late_gtids_previous); + delete_dynamic(&audit_elem->late_gtids_real); + my_free(audit_elem); +} + +Binlog_gtid_state_validator::Binlog_gtid_state_validator() +{ + my_hash_init(PSI_INSTRUMENT_ME, &m_audit_elem_domain_lookup, &my_charset_bin, 32, + offsetof(struct audit_elem, domain_id), sizeof(uint32), + NULL, free_domain_lookup_element, HASH_UNIQUE); +} + +Binlog_gtid_state_validator::~Binlog_gtid_state_validator() +{ + my_hash_free(&m_audit_elem_domain_lookup); +} +*/ +typedef struct _alter_safety_elem +{ + uint64 hash_val; + char *db; + size_t db_len; + char *table_name; + size_t table_name_len; + double mdl_timeout_override; + void (*error_func)(); + mysql_mutex_t alter_tbl_lock; +} alter_safety_elem; + +void free_alter_safety_elem(void *p) +{ + alter_safety_elem *e= (alter_safety_elem *) p; + my_free(e->db); + my_free(e->table_name); + my_free(e); +} + +/* + Write up why this is needed.. +*/ +static uint64 hash_table_qualifier(const char *db, size_t db_len, + const char *table_name, + size_t table_name_len) +{ + uint64 hash_val= 47; + size_t i; + + for (i= 0; i < db_len; i++) + { + hash_val ^= (*db++ << 1) | 1; + } + + hash_val ^= ('.' << 1); + + for (i= 0; i < table_name_len; i++) + { + hash_val ^= (*table_name++ << 1) | 1; + } + + return hash_val; +} + +static HASH alter_safety_hash; + +/* + Make an enum for tracking alter state? + ALTER_NOT_PROTECTED + ALTER_SAFE + ALTER UNSAFE +*/ + +int validate_alter_safety(const char *db, size_t db_len, const char *table_name, size_t table_name_len) +{ + uint64 hash_val= hash_table_qualifier(db, db_len, table_name, table_name_len); + alter_safety_elem *elem= (alter_safety_elem *) my_hash_search( + &alter_safety_hash, (const uchar *) &hash_val, 0); + /* + Double check that the hash corresponds to the intended database in case of + hash collision + */ + if (elem && !(strncmp(elem->db, db, elem->db_len) || + strncmp(elem->table_name, table_name, elem->table_name_len))) + { + if (mysql_mutex_trylock(&(elem->alter_tbl_lock))) + { + elem->error_func(); + return 1; + } + mysql_mutex_unlock(&(elem->alter_tbl_lock)); + } + + return 0; +} + +void set_table_unsafe_for_alter(const char *db, size_t db_len, + const char *table_name, size_t table_name_len) +{ + uint64 hash_val= hash_table_qualifier(db, db_len, table_name, table_name_len); + alter_safety_elem *elem= (alter_safety_elem *) my_hash_search( + &alter_safety_hash, (const uchar *) &hash_val, 0); + DBUG_ASSERT(elem); + mysql_mutex_lock(&(elem->alter_tbl_lock)); +} + +double get_alter_mdl_timeout(THD *thd, const char *db, size_t db_len, const char *table_name, + size_t table_name_len) +{ + uint64 hash_val= hash_table_qualifier(db, db_len, table_name, table_name_len); + alter_safety_elem *elem= (alter_safety_elem *) my_hash_search( + &alter_safety_hash, (const uchar *) &hash_val, 0); + if (!elem) + return thd->variables.lock_wait_timeout; + return elem->mdl_timeout_override; +} + +void set_table_safe_for_alter(const char *db, size_t db_len, + const char *table_name, size_t table_name_len) +{ + uint64 hash_val= hash_table_qualifier(db, db_len, table_name, table_name_len); + alter_safety_elem *elem= (alter_safety_elem *) my_hash_search( + &alter_safety_hash, (const uchar *) &hash_val, 0); + DBUG_ASSERT(elem); + mysql_mutex_unlock(&(elem->alter_tbl_lock)); +} + +void register_alter_safety_check(const char *db, size_t db_len, const char *table_name, size_t table_name_len, + void (*err_f)()) +{ + static int32 is_hash_inited= 0; + static int32 false_ref= 0; + + fprintf(stderr, "\n\nHash inited is %d\n",is_hash_inited); + if (my_atomic_cas32(&is_hash_inited, &false_ref, TRUE)) + { + my_hash_init(&alter_safety_hash, &my_charset_bin, 4, + offsetof(alter_safety_elem, hash_val), + sizeof(decltype(alter_safety_elem::hash_val)), NULL, + free_alter_safety_elem, HASH_UNIQUE); + fprintf(stderr, "We have initialized our alter_safety_hash\n"); + } + + uint64 table_hash= + hash_table_qualifier(db, db_len, table_name, table_name_len); + + alter_safety_elem *new_el= + (alter_safety_elem *) my_malloc(sizeof(alter_safety_elem), MYF(MY_WME)); + new_el->hash_val= table_hash; + new_el->db= (char *) my_malloc(db_len * sizeof(char) + 1, + MYF(MY_WME)); + new_el->table_name= + (char *) my_malloc(table_name_len * sizeof(char) + 1, MYF(MY_WME)); + new_el->db_len= db_len; + new_el->table_name_len= table_name_len; + strncpy(new_el->db, db, db_len); + new_el->db[db_len] = '\0'; + strncpy(new_el->table_name, table_name, table_name_len); + new_el->table_name[table_name_len] = '\0'; + new_el->mdl_timeout_override= 0; + new_el->error_func= err_f; + mysql_mutex_init(key_LOCK_alter_safety, &new_el->alter_tbl_lock, + MY_MUTEX_INIT_FAST); + + fprintf(stderr, "db %lu tl %lu\n", db_len, table_name_len); + fprintf(stderr, "Added new element for table %s.%s (%llu)\n", new_el->db, + new_el->table_name, new_el->hash_val); + my_hash_insert(&alter_safety_hash, (const uchar*) new_el); +} + + /** Alter table @@ -9059,6 +9234,9 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, Alter_table_ctx alter_ctx(thd, table_list, tables_opened, new_db, new_name); MDL_request target_mdl_request; + double mdl_wait_timeout= get_alter_mdl_timeout( + thd, alter_ctx.db, strlen(alter_ctx.db), alter_ctx.table_name, + strlen(alter_ctx.table_name)); /* Check that we are not trying to rename to an existing table */ if (alter_ctx.is_table_renamed()) @@ -9107,8 +9285,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, "", "", MDL_INTENTION_EXCLUSIVE)); - if (thd->mdl_context.acquire_locks(&mdl_requests, - thd->variables.lock_wait_timeout)) + if (thd->mdl_context.acquire_locks(&mdl_requests, mdl_wait_timeout)) + //thd->variables.lock_wait_timeout)) DBUG_RETURN(true); DEBUG_SYNC(thd, "locked_table_name"); @@ -9205,14 +9383,28 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, } #ifdef HAVE_REPLICATION - if (thd->lex && thd->lex->sql_command == SQLCOM_ALTER_TABLE && - table->s->db_type() != create_info->db_type && - is_alter_allowed_by_rpl_state(alter_ctx.db, alter_ctx.table_name)) + /* + rename to something like `unsafe_alter_locks` hashmap? + */ + if (thd->lex && thd->lex->sql_command == SQLCOM_ALTER_TABLE) { - DBUG_PRINT("info", ("illegal alter")); - /* is_alter_allowed_by_rpl_state() sets the error details */ - DBUG_RETURN(true); + if (validate_alter_safety(alter_ctx.db, strlen(alter_ctx.db), + alter_ctx.table_name, strlen(alter_ctx.table_name))) + { + DBUG_PRINT("info", ("illegal alter")); + /* validate_alter_safety() sets the error details */ + DBUG_RETURN(true); + } } + +// if (thd->lex && thd->lex->sql_command == SQLCOM_ALTER_TABLE && +// table->s->db_type() != create_info->db_type && +// is_alter_allowed_by_rpl_state(alter_ctx.db, alter_ctx.table_name)) +// { +// DBUG_PRINT("info", ("illegal alter")); +// /* is_alter_allowed_by_rpl_state() sets the error details */ +// DBUG_RETURN(true); +// } #endif if (table->s->tmp_table == NO_TMP_TABLE) @@ -9744,7 +9936,8 @@ do_continue:; */ if (alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE && thd->mdl_context.upgrade_shared_lock(mdl_ticket, MDL_SHARED_NO_WRITE, - thd->variables.lock_wait_timeout)) + mdl_wait_timeout)) + //thd->variables.lock_wait_timeout)) goto err_new_table_cleanup; DEBUG_SYNC(thd, "alter_table_copy_after_lock_upgrade"); |