===== sql/sql_db.cc 1.135 vs edited ===== --- 1.135/sql/sql_db.cc 2006-06-02 14:55:10 +02:00 +++ edited/sql/sql_db.cc 2006-06-13 20:41:35 +02:00 @@ -45,13 +45,28 @@ HASH lock_db_cache; pthread_mutex_t LOCK_lock_db; int creating_database= 0; // how many database locks are made +static int +lock_databases(THD *thd, const char *db1, uint length1, + const char *db2, uint length2); +static int +unlock_databases(THD *thd, const char *db1, uint length1, + const char *db2, uint length2); /* Structure for database lock */ +enum Lock_db_type +{ + Lock_db_nolock, + Lock_db_shared, + Lock_db_exclusive +}; + typedef struct my_dblock_st { char *name; /* Database name */ uint name_length; /* Database length name */ + enum Lock_db_type lock_type; + uint lock_count; } my_dblock_t; @@ -89,7 +104,8 @@ 1 on error. */ -static my_bool lock_db_insert(const char *dbname, uint length) +my_bool lock_db_insert(const char *dbname, uint length, + enum Lock_db_type lock_db_type) { my_dblock_t *opt; my_bool error= 0; @@ -113,18 +129,35 @@ opt->name= tmp_name; strmov(opt->name, dbname); opt->name_length= length; - + opt->lock_type= lock_db_type; + opt->lock_count= 1; + if ((error= my_hash_insert(&lock_db_cache, (byte*) opt))) { my_free((gptr) opt, MYF(0)); goto end; } } + else + { + DBUG_ASSERT(opt->lock_count > 0); + DBUG_ASSERT(opt->lock_type == lock_db_type); + opt->lock_count++; + } end: DBUG_RETURN(error); } +enum Lock_db_type lock_db_get(const char *name, uint length) +{ + my_dblock_t *opt; + safe_mutex_assert_owner(&LOCK_lock_db); + if (opt= (my_dblock_t *)hash_search(&lock_db_cache, + (const byte*) name, length)) + return opt->lock_type; + return Lock_db_nolock; +} /* Delete a database lock entry from hash. @@ -136,7 +169,8 @@ safe_mutex_assert_owner(&LOCK_lock_db); opt= (my_dblock_t *)hash_search(&lock_db_cache, (const byte*) name, length); DBUG_ASSERT(opt != NULL); - hash_delete(&lock_db_cache, (byte*) opt); + if (--opt->lock_count == 0) + hash_delete(&lock_db_cache, (byte*) opt); } @@ -520,8 +554,8 @@ */ -bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, - bool silent) +bool mysql_create_db_internal(THD *thd, char *db, HA_CREATE_INFO *create_info, + bool silent, bool lock_database) { char path[FN_REFLEN+16]; char tmp_query[FN_REFLEN+16]; @@ -529,7 +563,7 @@ int error= 0; MY_STAT stat_info; uint create_options= create_info ? create_info->options : 0; - uint path_len; + uint path_len, db_len= strlen(db); DBUG_ENTER("mysql_create_db"); /* do not create 'information_schema' db */ @@ -557,7 +591,11 @@ goto exit2; } - VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); + if (lock_database && lock_databases(thd, db, db_len, 0, 0)) + { + error= -1; + goto exit2; + } /* Check directory */ path_len= build_table_filename(path, sizeof(path), db, "", ""); @@ -658,7 +696,7 @@ # database does not exist. */ qinfo.db = db; - qinfo.db_len = strlen(db); + qinfo.db_len = db_len; mysql_bin_log.write(&qinfo); } @@ -666,20 +704,29 @@ } exit: - VOID(pthread_mutex_unlock(&LOCK_mysql_create_db)); + if (lock_database) + unlock_databases(thd, db, db_len, 0, 0); start_waiting_global_read_lock(thd); exit2: DBUG_RETURN(error); } +bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, + bool silent) +{ + return mysql_create_db_internal(thd, db, create_info, silent, 1); +} /* db-name is already validated when we come here */ -bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) +static +bool mysql_alter_db_internal(THD *thd, const char *db, + HA_CREATE_INFO *create_info, bool lock_database) { char path[FN_REFLEN+16]; long result=1; int error= 0; + uint db_len= strlen(db); DBUG_ENTER("mysql_alter_db"); /* @@ -697,7 +744,11 @@ if ((error=wait_if_global_read_lock(thd,0,1))) goto exit2; - VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); + if (lock_database && lock_databases(thd, db, db_len, 0, 0)) + { + error= -1; + goto exit2; + } /* Recreate db options file: /dbpath/.db.opt @@ -735,7 +786,7 @@ default. */ qinfo.db = db; - qinfo.db_len = strlen(db); + qinfo.db_len = db_len; thd->clear_error(); mysql_bin_log.write(&qinfo); @@ -743,12 +794,18 @@ send_ok(thd, result); exit: - VOID(pthread_mutex_unlock(&LOCK_mysql_create_db)); + if (lock_database) + unlock_databases(thd, db, db_len, 0, 0); start_waiting_global_read_lock(thd); exit2: DBUG_RETURN(error); } +bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) +{ + return mysql_alter_db_internal(thd, db, create_info, 1); +} + /* Drop all tables in a database and the database itself @@ -767,13 +824,15 @@ ERROR Error */ -bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) +static +bool mysql_rm_db_internal(THD *thd,char *db,bool if_exists, + bool silent, bool lock_database) { long deleted=0; int error= 0; char path[FN_REFLEN+16]; MY_DIR *dirp; - uint length; + uint length, db_len= strlen(db); TABLE_LIST* dropped_tables= 0; DBUG_ENTER("mysql_rm_db"); @@ -795,7 +854,11 @@ goto exit2; } - VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); + if (lock_database && lock_databases(thd, db, db_len, 0, 0)) + { + error= -1; + goto exit2; + } length= build_table_filename(path, sizeof(path), db, "", ""); strmov(path+length, MY_DB_OPT_FILE); // Append db option file name @@ -857,7 +920,7 @@ default. */ qinfo.db = db; - qinfo.db_len = strlen(db); + qinfo.db_len = db_len; thd->clear_error(); mysql_bin_log.write(&qinfo); @@ -870,13 +933,11 @@ { char *query, *query_pos, *query_end, *query_data_start; TABLE_LIST *tbl; - uint db_len; if (!(query= thd->alloc(MAX_DROP_TABLE_Q_LEN))) goto exit; /* not much else we can do */ query_pos= query_data_start= strmov(query,"drop table "); query_end= query + MAX_DROP_TABLE_Q_LEN; - db_len= strlen(db); for (tbl= dropped_tables; tbl; tbl= tbl->next_local) { @@ -933,12 +994,18 @@ thd->db= 0; thd->db_length= 0; } - VOID(pthread_mutex_unlock(&LOCK_mysql_create_db)); + if (lock_database) + unlock_databases(thd, db, db_len, 0, 0); start_waiting_global_read_lock(thd); exit2: DBUG_RETURN(error); } +bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) +{ + return mysql_rm_db_internal(thd, db, if_exists, silent, 1); +} + /* Removes files with known extensions plus all found subdirectories that are 2 hex digits (raid directories). @@ -1379,10 +1446,11 @@ lock_databases(THD *thd, const char *db1, uint length1, const char *db2, uint length2) { + DBUG_ENTER("lock_databases"); pthread_mutex_lock(&LOCK_lock_db); while (!thd->killed && (hash_search(&lock_db_cache,(byte*) db1, length1) || - hash_search(&lock_db_cache,(byte*) db2, length2))) + (db2 && hash_search(&lock_db_cache,(byte*) db2, length2)))) { wait_for_condition(thd, &LOCK_lock_db, &COND_refresh); pthread_mutex_lock(&LOCK_lock_db); @@ -1391,41 +1459,37 @@ if (thd->killed) { pthread_mutex_unlock(&LOCK_lock_db); - return 1; + DBUG_RETURN(1); } - lock_db_insert(db1, length1); - lock_db_insert(db2, length2); + lock_db_insert(db1, length1, Lock_db_exclusive); + if (db2) + lock_db_insert(db2, length2, Lock_db_exclusive); creating_database++; /* - Wait if a concurent thread is creating a table at the same time. - The assumption here is that it will not take too long until - there is a point in time when a table is not created. - */ - - while (!thd->killed && creating_table) - { - wait_for_condition(thd, &LOCK_lock_db, &COND_refresh); - pthread_mutex_lock(&LOCK_lock_db); - } - - if (thd->killed) - { - lock_db_delete(db1, length1); - lock_db_delete(db2, length2); - creating_database--; - pthread_mutex_unlock(&LOCK_lock_db); - pthread_cond_signal(&COND_refresh); - return(1); - } - - /* We can unlock now as the hash will protect against anyone creating a table in the databases we are using */ pthread_mutex_unlock(&LOCK_lock_db); - return 0; + DBUG_RETURN(0); +} + +static int +unlock_databases(THD *thd, const char *db1, uint length1, + const char *db2, uint length2) +{ + DBUG_ENTER("unlock databases"); + pthread_mutex_lock(&LOCK_lock_db); + /* Remove the databases from db lock cache */ + lock_db_delete(db1, length1); + if (db2) + lock_db_delete(db2, length2); + creating_database--; + /* Signal waiting CREATE TABLE's to continue */ + pthread_cond_signal(&COND_refresh); + pthread_mutex_unlock(&LOCK_lock_db); + DBUG_RETURN(0); } @@ -1499,7 +1563,7 @@ } /* Step1: Create the new database */ - if ((error= mysql_create_db(thd, new_db->str, &create_info, 1))) + if ((error= mysql_create_db_internal(thd, new_db->str, &create_info, 1, 0))) goto exit; /* Step2: Move tables to the new database */ @@ -1656,7 +1720,7 @@ are done inside mysql_rm_db(), no needs to execute them again. mysql_rm_db() also "unuses" if we drop the current database. */ - error= mysql_rm_db(thd, old_db->str, 0, 1); + error= mysql_rm_db_internal(thd, old_db->str, 0, 1, 0); /* Step8: logging */ if (mysql_bin_log.is_open()) @@ -1671,14 +1735,8 @@ error|= mysql_change_db(thd, new_db->str, 0); exit: - pthread_mutex_lock(&LOCK_lock_db); - /* Remove the databases from db lock cache */ - lock_db_delete(old_db->str, old_db->length); - lock_db_delete(new_db->str, new_db->length); - creating_database--; - /* Signal waiting CREATE TABLE's to continue */ - pthread_cond_signal(&COND_refresh); - pthread_mutex_unlock(&LOCK_lock_db); + unlock_databases(thd, old_db->str, old_db->length, + new_db->str, new_db->length); DBUG_RETURN(error); } ===== sql/sql_plugin.cc 1.24 vs edited ===== --- 1.24/sql/sql_plugin.cc 2006-06-06 13:48:09 +02:00 +++ edited/sql/sql_plugin.cc 2006-06-13 20:41:35 +02:00 @@ -925,10 +925,13 @@ my_bool plugin_foreach(THD *thd, plugin_foreach_func *func, int type, void *arg) { - uint idx; + uint idx, no_plugins= 0; struct st_plugin_int *plugin; - DBUG_ENTER("mysql_uninstall_plugin"); - rw_rdlock(&THR_LOCK_plugin); + struct st_plugin_int **plugins= 0; + + my_bool error= FALSE; + DBUG_ENTER("plugin_foreach"); + rw_wrlock(&THR_LOCK_plugin); if (type == MYSQL_ANY_PLUGIN) { @@ -937,9 +940,15 @@ plugin= dynamic_element(&plugin_array, idx, struct st_plugin_int *); /* FREED records may have garbage pointers */ - if ((plugin->state != PLUGIN_IS_FREED) && - func(thd, plugin, arg)) - goto err; + if (plugin->state != PLUGIN_IS_FREED) + { + if (plugins == 0) + plugins= (struct st_plugin_int **) + my_malloc(plugin_array.elements * sizeof(struct st_plugin_int *), + MYF(MY_WME)); + plugin->ref_count++; + plugins[no_plugins++]= plugin; + } } } else @@ -949,15 +958,33 @@ { plugin= (struct st_plugin_int *) hash_element(hash, idx); if ((plugin->state != PLUGIN_IS_FREED) && - (plugin->state != PLUGIN_IS_DELETED) && - func(thd, plugin, arg)) - goto err; + (plugin->state != PLUGIN_IS_DELETED)) + { + if (plugins == 0) + plugins= (struct st_plugin_int **) + my_malloc(hash->records * sizeof(struct st_plugin_int *), + MYF(MY_WME)); + plugin->ref_count++; + plugins[no_plugins++]= plugin; + } } } - - rw_unlock(&THR_LOCK_plugin); - DBUG_RETURN(FALSE); -err: rw_unlock(&THR_LOCK_plugin); - DBUG_RETURN(TRUE); + + if (no_plugins) + { + for (idx= 0; idx < no_plugins; idx++) + if (func(thd, plugins[idx], arg)) + { + error= TRUE; + break; + } + + rw_wrlock(&THR_LOCK_plugin); + for (idx= 0; idx < no_plugins; idx++) + plugins[idx]->ref_count--; + rw_unlock(&THR_LOCK_plugin); + my_free((char*)plugins, MYF(0)); + } + DBUG_RETURN(error); } ===== sql/sql_table.cc 1.344 vs edited ===== --- 1.344/sql/sql_table.cc 2006-06-12 20:42:02 +02:00 +++ edited/sql/sql_table.cc 2006-06-13 20:41:35 +02:00 @@ -3354,6 +3354,17 @@ Database locking aware wrapper for mysql_create_table_internal(), */ +enum Lock_db_type +{ + Lock_db_nolock, + Lock_db_shared, + Lock_db_exclusive +}; +my_bool lock_db_insert(const char *dbname, uint length, + enum Lock_db_type lock_db_type); +void lock_db_delete(const char *name, uint length); +enum Lock_db_type lock_db_get(const char *name, uint length); + bool mysql_create_table(THD *thd, const char *db, const char *table_name, HA_CREATE_INFO *create_info, List &fields, @@ -3361,12 +3372,13 @@ uint select_field_count) { bool result; + uint db_len= strlen(db); DBUG_ENTER("mysql_create_table"); /* Wait for any database locks */ pthread_mutex_lock(&LOCK_lock_db); while (!thd->killed && - hash_search(&lock_db_cache,(byte*) db, strlen(db))) + lock_db_get(db, db_len) == Lock_db_exclusive) { wait_for_condition(thd, &LOCK_lock_db, &COND_refresh); pthread_mutex_lock(&LOCK_lock_db); @@ -3377,7 +3389,9 @@ pthread_mutex_unlock(&LOCK_lock_db); DBUG_RETURN(TRUE); } - creating_table++; + + lock_db_insert(db, db_len, Lock_db_shared); + pthread_mutex_unlock(&LOCK_lock_db); result= mysql_create_table_internal(thd, db, table_name, create_info, @@ -3385,9 +3399,9 @@ select_field_count); pthread_mutex_lock(&LOCK_lock_db); - if (!--creating_table && creating_database) - pthread_cond_signal(&COND_refresh); + lock_db_delete(db, db_len); + pthread_cond_signal(&COND_refresh); pthread_mutex_unlock(&LOCK_lock_db); DBUG_RETURN(result); }