diff options
author | Sergei Golubchik <sergii@pisem.net> | 2013-04-09 15:35:57 +0200 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2013-04-09 15:35:57 +0200 |
commit | 6a839ff40d1be946b4391eb7a316b0404e1cd82b (patch) | |
tree | 770dce5797a309f58d4741856fa4b4b7ba735a68 /sql | |
parent | 934115184b52a28a30d576a8a47d0ec66b1b0712 (diff) | |
download | mariadb-git-6a839ff40d1be946b4391eb7a316b0404e1cd82b.tar.gz |
handlerton::discover_table_existence() method
Diffstat (limited to 'sql')
-rw-r--r-- | sql/handler.cc | 97 | ||||
-rw-r--r-- | sql/handler.h | 23 | ||||
-rw-r--r-- | sql/sql_base.cc | 58 | ||||
-rw-r--r-- | sql/sql_base.h | 9 | ||||
-rw-r--r-- | sql/sql_db.cc | 2 | ||||
-rw-r--r-- | sql/sql_table.cc | 11 |
6 files changed, 133 insertions, 67 deletions
diff --git a/sql/handler.cc b/sql/handler.cc index 8da997c2df2..f4987b9b36f 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -383,6 +383,11 @@ static int ha_finish_errors(void) return 0; } +volatile int32 need_full_discover_for_existence= 0; +static int full_discover_for_existence(handlerton *, const char *, const char *) +{ return 1; } +static int ext_based_existence(handlerton *, const char *, const char *) +{ return 1; } int ha_finalize_handlerton(st_plugin_int *plugin) { @@ -433,6 +438,9 @@ int ha_finalize_handlerton(st_plugin_int *plugin) hton2plugin[hton->slot]= NULL; } + if (hton->discover_table_existence == full_discover_for_existence) + my_atomic_add32(&need_full_discover_for_existence, -1); + if (hton->discover_table_names) my_atomic_add32(&engines_with_discover_table_names, -1); @@ -486,6 +494,18 @@ int ha_initialize_handlerton(st_plugin_int *plugin) hton->discover && hton->tablefile_extensions[0]) hton->discover_table_names= hton_ext_based_table_discovery; + // default discover_table_existence implementation + if (!hton->discover_table_existence && hton->discover) + { + if (hton->tablefile_extensions[0]) + hton->discover_table_existence= ext_based_existence; + else + { + hton->discover_table_existence= full_discover_for_existence; + my_atomic_add32(&need_full_discover_for_existence, 1); + } + } + /* the switch below and hton->state should be removed when command-line options for plugins will be implemented @@ -4377,6 +4397,83 @@ int ha_discover(THD *thd, const char *db, const char *name, DBUG_RETURN(error); } +/** + Check if a given table exists, without doing a full discover, if possible +*/ + +static my_bool file_ext_exists(char *path, size_t path_len, const char *ext) +{ + strmake(path + path_len, ext, FN_REFLEN - path_len); + return !access(path, F_OK); +} + +struct st_discover_existence_args +{ + char *path; + size_t path_len; + const char *db, *table_name; +}; + +static my_bool discover_existence(THD *thd, plugin_ref plugin, + void *arg) +{ + st_discover_existence_args *args= (st_discover_existence_args*)arg; + handlerton *ht= plugin_data(plugin, handlerton *); + if (ht->state != SHOW_OPTION_YES || !ht->discover_table_existence) + return FALSE; + + if (ht->discover_table_existence == ext_based_existence) + return file_ext_exists(args->path, args->path_len, + ht->tablefile_extensions[0]); + + return ht->discover_table_existence(ht, args->db, args->table_name); +} + +bool ha_table_exists(THD *thd, const char *db, const char *table_name) +{ + DBUG_ENTER("ha_discover_table_existence"); + + if (need_full_discover_for_existence) + { + enum open_frm_error err; + TABLE_LIST table; + + DBUG_ASSERT(0); + TABLE_SHARE *share= get_table_share(thd, db, table_name, + FRM_READ_TABLE_ONLY, &err); + + if (share) + { + mysql_mutex_lock(&LOCK_open); + release_table_share(share); + mysql_mutex_unlock(&LOCK_open); + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); + } + + mysql_mutex_lock(&LOCK_open); + TABLE_SHARE *share= get_cached_table_share(db, table_name); + mysql_mutex_unlock(&LOCK_open); + + if (share) + DBUG_RETURN(TRUE); + + char path[FN_REFLEN + 1]; + size_t path_len = build_table_filename(path, sizeof(path) - 1, + db, table_name, "", 0); + + if (file_ext_exists(path, path_len, reg_ext)) + DBUG_RETURN(TRUE); + + st_discover_existence_args args= {path, path_len, db, table_name}; + + if (plugin_foreach(thd, discover_existence, MYSQL_STORAGE_ENGINE_PLUGIN, + &args)) + DBUG_RETURN(TRUE); + + DBUG_RETURN(FALSE); +} /** Discover all table names in a given database diff --git a/sql/handler.h b/sql/handler.h index 79e757c5649..ee1d54c3253 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1136,6 +1136,27 @@ struct handlerton */ int (*discover_table_names)(handlerton *hton, LEX_STRING *db, MY_DIR *dir, discovered_list *result); + + /* + This is a method that allows to server to check if a table exists without + an overhead of the complete discovery. + + By default (if not implemented by the engine, but the discovery_table() is + implemented) it will try to perform a file-based discovery: + + - if tablefile_extensions[0] is not null this will look for a file name + with the tablefile_extensions[0] extension. + + - if tablefile_extensions[0] is null, this will resort to discover_table(). + + Note that resorting to discover_table() is slow and the engine + should probably implement its own discover_table_existence() method, + if its tablefile_extensions[0] is null. + + Returns 1 if the table exists and 0 if it does not. + */ + int (*discover_table_existence)(handlerton *hton, const char *db, + const char *table_name); }; @@ -3072,6 +3093,8 @@ int ha_discover(THD* thd, const char* dbname, const char* name, uchar** frmblob, size_t* frmlen); int ha_discover_table_names(THD *thd, LEX_STRING *db, MY_DIR *dirp, handlerton::discovered_list *result); +bool ha_table_exists(THD *thd, const char *db, const char *table_name); + #ifdef MYSQL_SERVER extern volatile int32 engines_with_discover_table_names; #endif diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 14389e840e9..d1feba264f1 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -771,7 +771,7 @@ void release_table_share(TABLE_SHARE *share) # TABLE_SHARE for table */ -static TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name) +TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name) { char key[SAFE_NAME_LEN*2+2]; uint key_length; @@ -2338,58 +2338,6 @@ void drop_open_table(THD *thd, TABLE *table, const char *db_name, /** - Check that table exists in table definition cache, on disk - or in some storage engine. - - @param thd Thread context - @param db database name - @param table_name table name - @param path (optional) path to the frm file - - @note This function acquires LOCK_open internally. - - @note If there is no .FRM file for the table but it exists in one - of engines (e.g. it was created on another node of NDB cluster) - this function will fetch and create proper .FRM file for it. - - @retval TRUE Some error occurred - @retval FALSE No error. 'exists' out parameter set accordingly. -*/ - -bool table_exists(THD *thd, const char *db, const char *table_name, - const char *path) -{ - char path_buf[FN_REFLEN + 1]; - TABLE_SHARE *share; - DBUG_ENTER("table_exists"); - - mysql_mutex_lock(&LOCK_open); - share= get_cached_table_share(db, table_name); - mysql_mutex_unlock(&LOCK_open); - - if (share) - DBUG_RETURN(TRUE); - - if (!path) - { - build_table_filename(path_buf, sizeof(path_buf) - 1, - db, table_name, reg_ext, 0); - path= path_buf; - } - - if (!access(path, F_OK)) - DBUG_RETURN(TRUE); - - /* .FRM file doesn't exist. Try to discover it */ - uchar *frmblob= NULL; - size_t frmlen; - bool exists= ! ha_discover(thd, db, table_name, &frmblob, &frmlen); - my_free(frmblob); - DBUG_RETURN(exists); -} - - -/** An error handler which converts, if possible, ER_LOCK_DEADLOCK error that can occur when we are trying to acquire a metadata lock to a request for back-off and re-start of open_tables() process. @@ -2926,7 +2874,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, if (table_list->open_strategy == TABLE_LIST::OPEN_IF_EXISTS) { - if (!table_exists(thd, table_list)) + if (!ha_table_exists(thd, table_list->db, table_list->table_name)) DBUG_RETURN(FALSE); /* Table exists. Let us try to open it. */ @@ -4705,7 +4653,7 @@ lock_table_names(THD *thd, We come here in the case of lock timeout when executing CREATE TABLE. Verify that table does exist (it usually does, as we got a lock conflict) */ - if (table_exists(thd, tables_start)) + if (ha_table_exists(thd, tables_start->db, tables_start->table_name)) { if (thd->lex->create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS) { diff --git a/sql/sql_base.h b/sql/sql_base.h index e0ced3992eb..1880b4f4321 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -113,7 +113,7 @@ TABLE_SHARE *get_table_share(THD *thd, const char *db, const char *table_name, enum open_frm_error *error, my_hash_value_type hash_value); void release_table_share(TABLE_SHARE *share); - +TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name); // convenience helper: call get_table_share() without precomputed hash_value static inline TABLE_SHARE *get_table_share(THD *thd, const char *db, @@ -369,13 +369,6 @@ TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db, bool no_error); void mark_tmp_table_for_reuse(TABLE *table); -bool table_exists(THD *thd, const char *db, const char *table_name, - const char *path); -static inline bool table_exists(THD *thd, TABLE_LIST *table) -{ - return table_exists(thd, table->db, table->table_name, NULL); -} - int update_virtual_fields(THD *thd, TABLE *table, enum enum_vcol_update_mode vcol_update_mode= VCOL_UPDATE_FOR_READ); int dynamic_column_error_message(enum_dyncol_func_result rc); diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 359f74155db..6dee6b4bcc5 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -937,7 +937,7 @@ update_binlog: char quoted_name[FN_REFLEN+3]; // Only write drop table to the binlog for tables that no longer exist. - if (table_exists(thd, tbl)) + if (ha_table_exists(thd, tbl->db, tbl->table_name)) continue; my_snprintf(quoted_name, sizeof(quoted_name), "%`s", tbl->table_name); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index ea1b7b3398b..b19e179f022 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2279,8 +2279,9 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, } DEBUG_SYNC(thd, "rm_table_no_locks_before_delete_table"); error= 0; - if (drop_temporary || !table_exists(thd, db, alias, path) || - (!drop_view && dd_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE)) + if (!table->internal_tmp_table && + (drop_temporary || !ha_table_exists(thd, db, alias) || + (!drop_view && dd_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE))) { /* One of the following cases happened: @@ -2288,6 +2289,10 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, . "DROP" but table was not found on disk and table can't be created from engine. . ./sql/datadict.cc +32 /Alfranio - TODO: We need to test this. + + Table->internal_tmp_table is set when one of the #sql-xxx files + was left in the datadir after a crash during ALTER TABLE. + See Bug#30152. */ if (if_exists) push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, @@ -4317,7 +4322,7 @@ bool mysql_create_table_no_lock(THD *thd, if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE)) { - if (table_exists(thd, db, table_name, path)) + if (ha_table_exists(thd, db, table_name)) { if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) goto warn; |