Commit c44fe70d authored by sasha@asksasha.com's avatar sasha@asksasha.com

patch for BUG#4680 - drop database breaking replication if there were extra files

in the database directory on the master
parent bb76e143
stop slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
drop database if exists d1;
create database d1;
create table d1.t1 (n int);
insert into d1.t1 values (1);
select * from d1.t1 into outfile 'd1/f1.txt';
create table d1.t2 (n int);
create table d1.t3 (n int);
drop database d1;
ERROR HY000: Error dropping database (can't rmdir './d1/', errno: 17)
use d1;
show tables;
Tables_in_d1
use test;
create table t1 (n int);
insert into t1 values (1234);
use d1;
show tables;
Tables_in_d1
use test;
select * from t1;
n
1234
drop table t1;
stop slave;
# test case for BUG#4680 -- if there are extra files in the db directory
# dropping the db on the master causes replication problems
-- source include/master-slave.inc
connection master;
--disable_warnings
drop database if exists d1;
--enable_warnings
create database d1;
create table d1.t1 (n int);
insert into d1.t1 values (1);
select * from d1.t1 into outfile 'd1/f1.txt';
create table d1.t2 (n int);
create table d1.t3 (n int);
--error 1010
drop database d1;
use d1;
show tables;
use test;
create table t1 (n int);
insert into t1 values (1234);
sync_slave_with_master;
connection slave;
use d1;
show tables;
use test;
select * from t1;
connection master;
drop table t1;
sync_slave_with_master;
#cleanup
connection slave;
stop slave;
system rm -rf var/master-data/d1;
...@@ -441,7 +441,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -441,7 +441,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
bool drop_temporary, bool log_query); bool drop_temporary, bool log_query);
int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables, int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables,
bool if_exists, bool drop_temporary, bool if_exists, bool drop_temporary,
bool log_query); bool log_query, List<String> *dropped_tables);
int quick_rm_table(enum db_type base,const char *db, int quick_rm_table(enum db_type base,const char *db,
const char *table_name); const char *table_name);
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list); bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
......
...@@ -31,7 +31,7 @@ static TYPELIB deletable_extentions= ...@@ -31,7 +31,7 @@ static TYPELIB deletable_extentions=
static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, static long mysql_rm_known_files(THD *thd, MY_DIR *dirp,
const char *db, const char *path, const char *db, const char *path,
uint level); uint level, List<String> *dropped_tables);
/* Database options hash */ /* Database options hash */
static HASH dboptions; static HASH dboptions;
...@@ -584,6 +584,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) ...@@ -584,6 +584,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
int error= 0; int error= 0;
char path[FN_REFLEN+16], tmp_db[NAME_LEN+1]; char path[FN_REFLEN+16], tmp_db[NAME_LEN+1];
MY_DIR *dirp; MY_DIR *dirp;
List<String> dropped_tables;
uint length; uint length;
DBUG_ENTER("mysql_rm_db"); DBUG_ENTER("mysql_rm_db");
...@@ -621,8 +622,10 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) ...@@ -621,8 +622,10 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
remove_db_from_cache(db); remove_db_from_cache(db);
pthread_mutex_unlock(&LOCK_open); pthread_mutex_unlock(&LOCK_open);
error= -1; error= -1;
if ((deleted= mysql_rm_known_files(thd, dirp, db, path, 0)) >= 0) if ((deleted= mysql_rm_known_files(thd, dirp, db, path, 0,
&dropped_tables)) >= 0)
{ {
ha_drop_database(path); ha_drop_database(path);
query_cache_invalidate1(db); query_cache_invalidate1(db);
...@@ -672,6 +675,37 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) ...@@ -672,6 +675,37 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
send_ok(thd, (ulong) deleted); send_ok(thd, (ulong) deleted);
thd->server_status&= ~SERVER_STATUS_DB_DROPPED; thd->server_status&= ~SERVER_STATUS_DB_DROPPED;
} }
else if (!dropped_tables.is_empty() && mysql_bin_log.is_open())
{
List_iterator<String> it(dropped_tables);
String* dropped_table;
int q_len= 11; /* drop table */
int db_len= strlen(db);
for (;(dropped_table= it++);)
{
q_len += dropped_table->length() + 2 + db_len;
}
q_len--; /* no last comma */
char* query= thd->alloc(q_len);
if (!query)
goto exit; /* not much else we can do */
char* p= strmov(query,"drop table ");
it.rewind();
for (;(dropped_table= it++);)
{
p= strmov(p,db);
*p++ = '.';
p= strnmov(p,dropped_table->ptr(),dropped_table->length());
*p++ = ',';
}
*--p= 0;
Query_log_event qinfo(thd, query, q_len, 0, 0);
qinfo.error_code= 0;
mysql_bin_log.write(&qinfo);
}
exit: exit:
start_waiting_global_read_lock(thd); start_waiting_global_read_lock(thd);
...@@ -716,7 +750,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) ...@@ -716,7 +750,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
*/ */
static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
const char *org_path, uint level) const char *org_path, uint level, List<String> *dropped_tables)
{ {
long deleted=0; long deleted=0;
ulong found_other_files=0; ulong found_other_files=0;
...@@ -758,7 +792,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, ...@@ -758,7 +792,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
if ((new_dirp = my_dir(newpath,MYF(MY_DONT_SORT)))) if ((new_dirp = my_dir(newpath,MYF(MY_DONT_SORT))))
{ {
DBUG_PRINT("my",("New subdir found: %s", newpath)); DBUG_PRINT("my",("New subdir found: %s", newpath));
if ((mysql_rm_known_files(thd, new_dirp, NullS, newpath,1)) < 0) if ((mysql_rm_known_files(thd, new_dirp, NullS, newpath,1,0)) < 0)
goto err; goto err;
if (!(copy_of_path= thd->memdup(newpath, length+1)) || if (!(copy_of_path= thd->memdup(newpath, length+1)) ||
!(dir= new (thd->mem_root) String(copy_of_path, length, !(dir= new (thd->mem_root) String(copy_of_path, length,
...@@ -805,7 +839,8 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, ...@@ -805,7 +839,8 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
} }
} }
if (thd->killed || if (thd->killed ||
(tot_list && mysql_rm_table_part2_with_lock(thd, tot_list, 1, 0, 1))) (tot_list && mysql_rm_table_part2_with_lock(thd, tot_list, 1, 0,
1,dropped_tables)))
goto err; goto err;
/* Remove RAID directories */ /* Remove RAID directories */
......
...@@ -156,7 +156,8 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, ...@@ -156,7 +156,8 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
int mysql_rm_table_part2_with_lock(THD *thd, int mysql_rm_table_part2_with_lock(THD *thd,
TABLE_LIST *tables, bool if_exists, TABLE_LIST *tables, bool if_exists,
bool drop_temporary, bool dont_log_query) bool drop_temporary, bool dont_log_query,
List<String>* dropped_tables)
{ {
int error; int error;
thd->mysys_var->current_mutex= &LOCK_open; thd->mysys_var->current_mutex= &LOCK_open;
...@@ -165,6 +166,23 @@ int mysql_rm_table_part2_with_lock(THD *thd, ...@@ -165,6 +166,23 @@ int mysql_rm_table_part2_with_lock(THD *thd,
error=mysql_rm_table_part2(thd,tables, if_exists, drop_temporary, error=mysql_rm_table_part2(thd,tables, if_exists, drop_temporary,
dont_log_query); dont_log_query);
/*
For now we assume that if we got success all the tables in the list
were actually dropped, otherwise, assume none were dropped.
TODO: fix it to work with a partial drop - extremely rare case, but
can happen.
*/
if (!error && dropped_tables)
{
TABLE_LIST* tbl;
for (tbl= tables; tbl; tbl= tbl->next)
{
String *dropped_table= new (thd->mem_root)
String(tbl->real_name,&my_charset_latin1);
dropped_tables->push_back(dropped_table);
}
}
pthread_mutex_unlock(&LOCK_open); pthread_mutex_unlock(&LOCK_open);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment