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,
bool drop_temporary, bool log_query);
int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables,
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,
const char *table_name);
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
......
......@@ -31,7 +31,7 @@ static TYPELIB deletable_extentions=
static long mysql_rm_known_files(THD *thd, MY_DIR *dirp,
const char *db, const char *path,
uint level);
uint level, List<String> *dropped_tables);
/* Database options hash */
static HASH dboptions;
......@@ -584,6 +584,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
int error= 0;
char path[FN_REFLEN+16], tmp_db[NAME_LEN+1];
MY_DIR *dirp;
List<String> dropped_tables;
uint length;
DBUG_ENTER("mysql_rm_db");
......@@ -621,8 +622,10 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
remove_db_from_cache(db);
pthread_mutex_unlock(&LOCK_open);
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);
query_cache_invalidate1(db);
......@@ -672,6 +675,37 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
send_ok(thd, (ulong) deleted);
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:
start_waiting_global_read_lock(thd);
......@@ -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,
const char *org_path, uint level)
const char *org_path, uint level, List<String> *dropped_tables)
{
long deleted=0;
ulong found_other_files=0;
......@@ -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))))
{
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;
if (!(copy_of_path= thd->memdup(newpath, length+1)) ||
!(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,
}
}
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;
/* Remove RAID directories */
......
......@@ -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,
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;
thd->mysys_var->current_mutex= &LOCK_open;
......@@ -165,6 +166,23 @@ int mysql_rm_table_part2_with_lock(THD *thd,
error=mysql_rm_table_part2(thd,tables, if_exists, drop_temporary,
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);
......
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