Commit 02d88c39 authored by serg@serg.mylan's avatar serg@serg.mylan

bug#8151 - truncate leaves a transaction open

deadlock in MYSQL_LOG::new_file()
style fixes
parent 8f5ca748
...@@ -906,6 +906,7 @@ truncate table t1; ...@@ -906,6 +906,7 @@ truncate table t1;
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
commit; commit;
truncate table t1; truncate table t1;
truncate table t1;
select * from t1; select * from t1;
a a
insert into t1 values(1),(2); insert into t1 values(1),(2);
...@@ -924,6 +925,7 @@ a ...@@ -924,6 +925,7 @@ a
1 1
2 2
truncate table t1; truncate table t1;
truncate table t1;
insert into t1 values(1),(2); insert into t1 values(1),(2);
delete from t1; delete from t1;
select * from t1; select * from t1;
...@@ -1637,14 +1639,14 @@ t2 CREATE TABLE `t2` ( ...@@ -1637,14 +1639,14 @@ t2 CREATE TABLE `t2` (
drop table t2, t1; drop table t2, t1;
show status like "binlog_cache_use"; show status like "binlog_cache_use";
Variable_name Value Variable_name Value
Binlog_cache_use 152 Binlog_cache_use 154
show status like "binlog_cache_disk_use"; show status like "binlog_cache_disk_use";
Variable_name Value Variable_name Value
Binlog_cache_disk_use 0 Binlog_cache_disk_use 0
create table t1 (a int) engine=innodb; create table t1 (a int) engine=innodb;
show status like "binlog_cache_use"; show status like "binlog_cache_use";
Variable_name Value Variable_name Value
Binlog_cache_use 153 Binlog_cache_use 155
show status like "binlog_cache_disk_use"; show status like "binlog_cache_disk_use";
Variable_name Value Variable_name Value
Binlog_cache_disk_use 1 Binlog_cache_disk_use 1
...@@ -1653,7 +1655,7 @@ delete from t1; ...@@ -1653,7 +1655,7 @@ delete from t1;
commit; commit;
show status like "binlog_cache_use"; show status like "binlog_cache_use";
Variable_name Value Variable_name Value
Binlog_cache_use 154 Binlog_cache_use 156
show status like "binlog_cache_disk_use"; show status like "binlog_cache_disk_use";
Variable_name Value Variable_name Value
Binlog_cache_disk_use 1 Binlog_cache_disk_use 1
......
...@@ -591,6 +591,7 @@ insert into t1 values(1),(2); ...@@ -591,6 +591,7 @@ insert into t1 values(1),(2);
truncate table t1; truncate table t1;
commit; commit;
truncate table t1; truncate table t1;
truncate table t1;
select * from t1; select * from t1;
insert into t1 values(1),(2); insert into t1 values(1),(2);
delete from t1; delete from t1;
...@@ -605,6 +606,7 @@ truncate table t1; ...@@ -605,6 +606,7 @@ truncate table t1;
insert into t1 values(1),(2); insert into t1 values(1),(2);
select * from t1; select * from t1;
truncate table t1; truncate table t1;
truncate table t1;
insert into t1 values(1),(2); insert into t1 values(1),(2);
delete from t1; delete from t1;
select * from t1; select * from t1;
......
...@@ -4256,8 +4256,6 @@ ha_innobase::delete_all_rows(void) ...@@ -4256,8 +4256,6 @@ ha_innobase::delete_all_rows(void)
goto fallback; goto fallback;
} }
innobase_commit(thd, 1);
error = convert_error_code_to_mysql(error, NULL); error = convert_error_code_to_mysql(error, NULL);
DBUG_RETURN(error); DBUG_RETURN(error);
......
...@@ -1606,7 +1606,12 @@ int handler::rename_table(const char * from, const char * to) ...@@ -1606,7 +1606,12 @@ int handler::rename_table(const char * from, const char * to)
} }
/* /*
Tell the handler to turn on or off transaction in the handler Tell the storage engine that it is allowed to "disable transaction" in the
handler. It is a hint that ACID is not required - it is used in NDB for
ALTER TABLE, for example, when data are copied to temporary table.
A storage engine may treat this hint any way it likes. NDB for example
starts to commit every now and then automatically.
This hint can be safely ignored.
*/ */
int ha_enable_transaction(THD *thd, bool on) int ha_enable_transaction(THD *thd, bool on)
...@@ -1616,7 +1621,15 @@ int ha_enable_transaction(THD *thd, bool on) ...@@ -1616,7 +1621,15 @@ int ha_enable_transaction(THD *thd, bool on)
DBUG_ENTER("ha_enable_transaction"); DBUG_ENTER("ha_enable_transaction");
thd->transaction.on= on; thd->transaction.on= on;
if (on) if (on)
ha_commit(thd); {
/*
Now all storage engines should have transaction handling enabled.
But some may have it enabled all the time - "disabling" transactions
is an optimization hint that storage engine is free to ignore.
So, let's commit an open transaction (if any) now.
*/
error= end_trans(thd, COMMIT);
}
DBUG_RETURN(error); DBUG_RETURN(error);
} }
......
...@@ -113,7 +113,7 @@ class DTCollation { ...@@ -113,7 +113,7 @@ class DTCollation {
typedef bool (Item::*Item_processor)(byte *arg); typedef bool (Item::*Item_processor)(byte *arg);
typedef Item* (Item::*Item_transformer) (byte *arg); typedef Item* (Item::*Item_transformer) (byte *arg);
typedef void (*Item_cond_traverser) (const Item *item, void *arg); typedef void (*Cond_traverser) (const Item *item, void *arg);
class Item { class Item {
Item(const Item &); /* Prevent use of these */ Item(const Item &); /* Prevent use of these */
...@@ -398,9 +398,8 @@ class Item { ...@@ -398,9 +398,8 @@ class Item {
return (this->*transformer)(arg); return (this->*transformer)(arg);
} }
virtual void traverse_cond(Item_cond_traverser traverser, virtual void traverse_cond(Cond_traverser traverser,
void *arg, void *arg, traverse_order order)
traverse_order order = POSTFIX)
{ {
(*traverser)(this, arg); (*traverser)(this, arg);
} }
......
...@@ -2363,9 +2363,8 @@ Item *Item_cond::transform(Item_transformer transformer, byte *arg) ...@@ -2363,9 +2363,8 @@ Item *Item_cond::transform(Item_transformer transformer, byte *arg)
return Item_func::transform(transformer, arg); return Item_func::transform(transformer, arg);
} }
void Item_cond::traverse_cond(Item_cond_traverser traverser, void Item_cond::traverse_cond(Cond_traverser traverser,
void *arg, void *arg, traverse_order order)
traverse_order order)
{ {
List_iterator<Item> li(list); List_iterator<Item> li(list);
Item *item; Item *item;
......
...@@ -1028,9 +1028,7 @@ class Item_cond :public Item_bool_func ...@@ -1028,9 +1028,7 @@ class Item_cond :public Item_bool_func
void copy_andor_arguments(THD *thd, Item_cond *item); void copy_andor_arguments(THD *thd, Item_cond *item);
bool walk(Item_processor processor, byte *arg); bool walk(Item_processor processor, byte *arg);
Item *transform(Item_transformer transformer, byte *arg); Item *transform(Item_transformer transformer, byte *arg);
void traverse_cond(Item_cond_traverser, void traverse_cond(Cond_traverser, void *arg, traverse_order order);
void *arg,
traverse_order order = POSTFIX);
void neg_arguments(THD *thd); void neg_arguments(THD *thd);
}; };
......
...@@ -360,9 +360,8 @@ bool Item_func::walk (Item_processor processor, byte *argument) ...@@ -360,9 +360,8 @@ bool Item_func::walk (Item_processor processor, byte *argument)
return (this->*processor)(argument); return (this->*processor)(argument);
} }
void Item_func::traverse_cond(Item_cond_traverser traverser, void Item_func::traverse_cond(Cond_traverser traverser,
void *argument, void *argument, traverse_order order)
traverse_order order)
{ {
if (arg_count) if (arg_count)
{ {
......
...@@ -163,9 +163,8 @@ class Item_func :public Item_result_field ...@@ -163,9 +163,8 @@ class Item_func :public Item_result_field
uint flags= 0); uint flags= 0);
bool walk(Item_processor processor, byte *arg); bool walk(Item_processor processor, byte *arg);
Item *transform(Item_transformer transformer, byte *arg); Item *transform(Item_transformer transformer, byte *arg);
void traverse_cond(Item_cond_traverser traverser, void traverse_cond(Cond_traverser traverser,
void * arg, void * arg, traverse_order order);
traverse_order order = POSTFIX);
}; };
......
...@@ -1296,10 +1296,9 @@ void MYSQL_LOG::new_file(bool need_lock) ...@@ -1296,10 +1296,9 @@ void MYSQL_LOG::new_file(bool need_lock)
} }
if (need_lock) if (need_lock)
{
pthread_mutex_lock(&LOCK_log); pthread_mutex_lock(&LOCK_log);
pthread_mutex_lock(&LOCK_index); pthread_mutex_lock(&LOCK_index);
}
safe_mutex_assert_owner(&LOCK_log); safe_mutex_assert_owner(&LOCK_log);
safe_mutex_assert_owner(&LOCK_index); safe_mutex_assert_owner(&LOCK_index);
...@@ -1377,10 +1376,9 @@ void MYSQL_LOG::new_file(bool need_lock) ...@@ -1377,10 +1376,9 @@ void MYSQL_LOG::new_file(bool need_lock)
end: end:
if (need_lock) if (need_lock)
{
pthread_mutex_unlock(&LOCK_index);
pthread_mutex_unlock(&LOCK_log); pthread_mutex_unlock(&LOCK_log);
} pthread_mutex_unlock(&LOCK_index);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -1404,11 +1402,7 @@ bool MYSQL_LOG::append(Log_event* ev) ...@@ -1404,11 +1402,7 @@ bool MYSQL_LOG::append(Log_event* ev)
bytes_written+= ev->data_written; bytes_written+= ev->data_written;
DBUG_PRINT("info",("max_size: %lu",max_size)); DBUG_PRINT("info",("max_size: %lu",max_size));
if ((uint) my_b_append_tell(&log_file) > max_size) if ((uint) my_b_append_tell(&log_file) > max_size)
{
pthread_mutex_lock(&LOCK_index);
new_file(0); new_file(0);
pthread_mutex_unlock(&LOCK_index);
}
err: err:
pthread_mutex_unlock(&LOCK_log); pthread_mutex_unlock(&LOCK_log);
...@@ -1438,11 +1432,7 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...) ...@@ -1438,11 +1432,7 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...)
} while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint))); } while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint)));
DBUG_PRINT("info",("max_size: %lu",max_size)); DBUG_PRINT("info",("max_size: %lu",max_size));
if ((uint) my_b_append_tell(&log_file) > max_size) if ((uint) my_b_append_tell(&log_file) > max_size)
{
pthread_mutex_lock(&LOCK_index);
new_file(0); new_file(0);
pthread_mutex_unlock(&LOCK_index);
}
err: err:
pthread_mutex_unlock(&LOCK_log); pthread_mutex_unlock(&LOCK_log);
...@@ -1774,15 +1764,10 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u", ...@@ -1774,15 +1764,10 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
void MYSQL_LOG::rotate_and_purge(uint flags) void MYSQL_LOG::rotate_and_purge(uint flags)
{ {
if (!prepared_xids && // see new_file() for the explanation if ((flags & RP_FORCE_ROTATE) ||
((flags & RP_FORCE_ROTATE) || (my_b_tell(&log_file) >= (my_off_t) max_size))
(my_b_tell(&log_file) >= (my_off_t) max_size)))
{ {
if (flags & RP_LOCK_LOG_IS_ALREADY_LOCKED)
pthread_mutex_lock(&LOCK_index);
new_file(!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED)); new_file(!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED));
if (flags & RP_LOCK_LOG_IS_ALREADY_LOCKED)
pthread_mutex_unlock(&LOCK_index);
#ifdef HAVE_REPLICATION #ifdef HAVE_REPLICATION
// QQ why do we need #ifdef here ??? // QQ why do we need #ifdef here ???
if (expire_logs_days) if (expire_logs_days)
...@@ -1828,9 +1813,8 @@ uint MYSQL_LOG::next_file_id() ...@@ -1828,9 +1813,8 @@ uint MYSQL_LOG::next_file_id()
bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event) bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
{ {
bool error= 0;
VOID(pthread_mutex_lock(&LOCK_log));
DBUG_ENTER("MYSQL_LOG::write(THD *, IO_CACHE *, Log_event *)"); DBUG_ENTER("MYSQL_LOG::write(THD *, IO_CACHE *, Log_event *)");
VOID(pthread_mutex_lock(&LOCK_log));
if (likely(is_open())) // Should always be true if (likely(is_open())) // Should always be true
{ {
...@@ -1888,12 +1872,22 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event) ...@@ -1888,12 +1872,22 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
goto err; goto err;
} }
signal_update(); signal_update();
DBUG_PRINT("info",("max_size: %lu",max_size)); /*
if commit_event is Xid_log_event, increase the number of
prepared_xids (it's decreasd in ::unlog()). Binlog cannot be rotated
if there're prepared xids in it - see the comment in new_file() for
an explanation.
If the commit_event is not Xid_log_event (then it's a Query_log_event)
rotate binlog, if necessary.
*/
if (commit_event->get_type_code() == XID_EVENT)
thread_safe_increment(prepared_xids, &LOCK_prep_xids);
else
rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
} }
VOID(pthread_mutex_unlock(&LOCK_log)); VOID(pthread_mutex_unlock(&LOCK_log));
DBUG_RETURN(error); DBUG_RETURN(0);
err: err:
if (!write_error) if (!write_error)
...@@ -2992,7 +2986,6 @@ int TC_LOG_BINLOG::log(THD *thd, my_xid xid) ...@@ -2992,7 +2986,6 @@ int TC_LOG_BINLOG::log(THD *thd, my_xid xid)
{ {
Xid_log_event xle(thd, xid); Xid_log_event xle(thd, xid);
IO_CACHE *trans_log= (IO_CACHE*)thd->ha_data[binlog_hton.slot]; IO_CACHE *trans_log= (IO_CACHE*)thd->ha_data[binlog_hton.slot];
thread_safe_increment(prepared_xids, &LOCK_prep_xids);
return !binlog_end_trans(thd, trans_log, &xle); // invert return value return !binlog_end_trans(thd, trans_log, &xle); // invert return value
} }
...@@ -3000,7 +2993,7 @@ void TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid) ...@@ -3000,7 +2993,7 @@ void TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
{ {
if (thread_safe_dec_and_test(prepared_xids, &LOCK_prep_xids)) if (thread_safe_dec_and_test(prepared_xids, &LOCK_prep_xids))
pthread_cond_signal(&COND_prep_xids); pthread_cond_signal(&COND_prep_xids);
rotate_and_purge(0); // in case ::write() was not able to rotate rotate_and_purge(0); // as ::write() did not rotate
} }
int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle) int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
......
...@@ -1684,6 +1684,9 @@ void Start_log_event_v3::print(FILE* file, bool short_form, LAST_EVENT_INFO* las ...@@ -1684,6 +1684,9 @@ void Start_log_event_v3::print(FILE* file, bool short_form, LAST_EVENT_INFO* las
if (created) if (created)
fprintf(file," at startup"); fprintf(file," at startup");
fputc('\n', file); fputc('\n', file);
if (flags & LOG_EVENT_BINLOG_IN_USE_F)
fprintf(file, "# Warning: this binlog was not closed properly. "
"Most probably mysqld crashed writing it.\n");
} }
if (!artificial_event && created) if (!artificial_event && created)
{ {
......
...@@ -1061,9 +1061,9 @@ class THD :public ilink, ...@@ -1061,9 +1061,9 @@ class THD :public ilink,
SAVEPOINT *savepoints; SAVEPOINT *savepoints;
THD_TRANS all; // Trans since BEGIN WORK THD_TRANS all; // Trans since BEGIN WORK
THD_TRANS stmt; // Trans for current statement THD_TRANS stmt; // Trans for current statement
bool on; bool on; // see ha_enable_transaction()
XID xid; XID xid; // transaction identifier
enum xa_states xa_state; enum xa_states xa_state; // used by external XA only
/* /*
Tables changed in transaction (that must be invalidated in query cache). Tables changed in transaction (that must be invalidated in query cache).
List contain only transactional tables, that not invalidated in query List contain only transactional tables, that not invalidated in query
......
...@@ -1271,7 +1271,7 @@ int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1, ...@@ -1271,7 +1271,7 @@ int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1,
bool mysql_show_binlog_events(THD* thd) bool mysql_show_binlog_events(THD* thd)
{ {
Protocol *protocol= thd->protocol; Protocol *protocol= thd->protocol;
DBUG_ENTER("show_binlog_events"); DBUG_ENTER("mysql_show_binlog_events");
List<Item> field_list; List<Item> field_list;
const char *errmsg = 0; const char *errmsg = 0;
IO_CACHE log; IO_CACHE log;
......
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