query_id and my_xid -> ulonglong

fix for binlog+autocommit+tclog
comments, style fixes


libmysqld/libmysqld.rc:
  Change mode to -rw-rw-r--
libmysqld/resource.h:
  Change mode to -rw-rw-r--
configure.in:
  check for getpagesize
include/my_global.h:
  typo ?
include/my_pthread.h:
  bug in thread_safe_decrement_and_test()
mysql-test/r/bdb.result:
  results updated
mysql-test/r/innodb.result:
  results updated
mysql-test/r/mix_innodb_myisam_binlog.result:
  results updated
mysql-test/r/rpl_relayrotate.result:
  results updated
sql/ha_berkeley.cc:
  style fixes
sql/ha_innodb.cc:
  fixes to follow innodb coding style
sql/handler.cc:
  more comments. XA COMMIT ONE PHASE fix.
sql/handler.h:
  my_xid -> ulonglong. comments
sql/item_func.cc:
  DO RELEASE_LOCK("...") is no cache_stmt
sql/log.cc:
  comments, better error messages
sql/log_event.cc:
  even in autocommit mode we may need to cache_stmt
  xid is ulonglong
sql/log_event.h:
  more comments.
sql/mysql_priv.h:
  query_id is ulonglong
sql/mysqld.cc:
  default value for --log-tc changed
sql/share/errmsg.txt:
  better error messages
sql/sql_class.h:
  cleanup, comments
sql/sql_delete.cc:
  deleting from temporary tables is not always transactional
sql/sql_insert.cc:
  insert into temporary table is not always transactional
sql/sql_load.cc:
  load data into temp table is not always transactional
sql/sql_parse.cc:
  comments. bad merge fixed. xa_state_names[]
sql/sql_table.cc:
  create/drop temp table is not always transactional
sql/sql_update.cc:
  update temp table is not always transactional
This commit is contained in:
unknown 2005-01-27 22:38:56 +01:00
parent a7401bf7cc
commit 042448aa33
27 changed files with 377 additions and 301 deletions

View file

@ -1914,7 +1914,7 @@ AC_CHECK_FUNCS(alarm bcmp bfill bmove bzero chsize cuserid fchmod fcntl \
getcwd gethostbyaddr_r gethostbyname_r getpass getpassphrase getpwnam \
getpwuid getrlimit getrusage getwd gmtime_r index initgroups isnan \
localtime_r locking longjmp lrand48 madvise mallinfo memcpy memmove \
mkstemp mlockall perror poll pread pthread_attr_create mmap \
mkstemp mlockall perror poll pread pthread_attr_create mmap getpagesize \
pthread_attr_getstacksize pthread_attr_setprio pthread_attr_setschedparam \
pthread_attr_setstacksize pthread_condattr_create pthread_getsequence_np \
pthread_key_delete pthread_rwlock_rdlock pthread_setprio \

View file

@ -751,7 +751,7 @@ typedef long int32;
#endif
typedef unsigned long uint32; /* Short for unsigned integer >= 32 bits */
#else
error "Neither int or long is of 4 bytes width"
#error "Neither int or long is of 4 bytes width"
#endif
#if !defined(HAVE_ULONG) && !defined(HAVE_LINUXTHREADS) && !defined(__USE_MISC)

View file

@ -692,7 +692,7 @@ static inline bool thread_safe_dec_and_test(ulong &V, pthread_mutex_t *L)
{
ulong res;
pthread_mutex_lock(L);
res=V--;
res=--V;
pthread_mutex_unlock(L);
return res==0;
}

0
libmysqld/libmysqld.rc Executable file → Normal file
View file

0
libmysqld/resource.h Executable file → Normal file
View file

View file

@ -1445,7 +1445,7 @@ qq
*a *a*a *
explain select * from t1 where v='a';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref v,v_2 v 13 const 10 Using where
1 SIMPLE t1 ref v,v_2 # 13 const # Using where
select v,count(*) from t1 group by v limit 10;
v count(*)
a 1

View file

@ -1609,14 +1609,14 @@ t2 CREATE TABLE `t2` (
drop table t2, t1;
show status like "binlog_cache_use";
Variable_name Value
Binlog_cache_use 24
Binlog_cache_use 150
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 0
create table t1 (a int) engine=innodb;
show status like "binlog_cache_use";
Variable_name Value
Binlog_cache_use 25
Binlog_cache_use 151
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
@ -1625,7 +1625,7 @@ delete from t1;
commit;
show status like "binlog_cache_use";
Variable_name Value
Binlog_cache_use 26
Binlog_cache_use 152
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1

View file

@ -12,7 +12,7 @@ master-bin.000001 96 Query 1 # use `test`; BEGIN
master-bin.000001 158 Query 1 # use `test`; insert into t1 values(1)
master-bin.000001 239 Query 1 # use `test`; insert into t2 select * from t1
master-bin.000001 327 Xid 1 # xid=7
master-bin.000001 350 Query 1 # use `test`; COMMIT
master-bin.000001 354 Query 1 # use `test`; COMMIT
delete from t1;
delete from t2;
reset master;
@ -49,7 +49,7 @@ master-bin.000001 318 Query 1 # use `test`; insert into t1 values(4)
master-bin.000001 399 Query 1 # use `test`; insert into t2 select * from t1
master-bin.000001 487 Query 1 # use `test`; rollback to savepoint my_savepoint
master-bin.000001 578 Xid 1 # xid=24
master-bin.000001 601 Query 1 # use `test`; COMMIT
master-bin.000001 605 Query 1 # use `test`; COMMIT
delete from t1;
delete from t2;
reset master;
@ -77,7 +77,7 @@ master-bin.000001 399 Query 1 # use `test`; insert into t2 select * from t1
master-bin.000001 487 Query 1 # use `test`; rollback to savepoint my_savepoint
master-bin.000001 578 Query 1 # use `test`; insert into t1 values(7)
master-bin.000001 659 Xid 1 # xid=36
master-bin.000001 682 Query 1 # use `test`; COMMIT
master-bin.000001 686 Query 1 # use `test`; COMMIT
delete from t1;
delete from t2;
reset master;
@ -96,6 +96,7 @@ master-bin.000001 96 Query 1 # use `test`; BEGIN
master-bin.000001 158 Query 1 # use `test`; insert into t1 values(8)
master-bin.000001 239 Query 1 # use `test`; insert into t2 select * from t1
master-bin.000001 327 Query 1 # use `test`; ROLLBACK
master-bin.000001 392 Query 1 # use `test`; DO RELEASE_LOCK("a")
delete from t1;
delete from t2;
reset master;
@ -103,8 +104,11 @@ insert into t1 values(9);
insert into t2 select * from t1;
show binlog events from 96;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 96 Query 1 # use `test`; insert into t1 values(9)
master-bin.000001 177 Query 1 # use `test`; insert into t2 select * from t1
master-bin.000001 96 Query 1 # use `test`; BEGIN
master-bin.000001 158 Query 1 # use `test`; insert into t1 values(9)
master-bin.000001 239 Xid 1 # xid=59
master-bin.000001 266 Query 1 # use `test`; COMMIT
master-bin.000001 329 Query 1 # use `test`; insert into t2 select * from t1
delete from t1;
delete from t2;
reset master;
@ -113,18 +117,24 @@ begin;
insert into t2 select * from t1;
show binlog events from 96;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 96 Query 1 # use `test`; insert into t1 values(10)
master-bin.000001 178 Query 1 # use `test`; insert into t2 select * from t1
master-bin.000001 96 Query 1 # use `test`; BEGIN
master-bin.000001 158 Query 1 # use `test`; insert into t1 values(10)
master-bin.000001 240 Xid 1 # xid=65
master-bin.000001 267 Query 1 # use `test`; COMMIT
master-bin.000001 330 Query 1 # use `test`; insert into t2 select * from t1
insert into t1 values(11);
commit;
show binlog events from 96;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 96 Query 1 # use `test`; insert into t1 values(10)
master-bin.000001 178 Query 1 # use `test`; insert into t2 select * from t1
master-bin.000001 266 Query 1 # use `test`; BEGIN
master-bin.000001 328 Query 1 # use `test`; insert into t1 values(11)
master-bin.000001 410 Xid 1 # xid=67
master-bin.000001 433 Query 1 # use `test`; COMMIT
master-bin.000001 96 Query 1 # use `test`; BEGIN
master-bin.000001 158 Query 1 # use `test`; insert into t1 values(10)
master-bin.000001 240 Xid 1 # xid=65
master-bin.000001 267 Query 1 # use `test`; COMMIT
master-bin.000001 330 Query 1 # use `test`; insert into t2 select * from t1
master-bin.000001 418 Query 1 # use `test`; BEGIN
master-bin.000001 480 Query 1 # use `test`; insert into t1 values(11)
master-bin.000001 562 Xid 1 # xid=67
master-bin.000001 589 Query 1 # use `test`; COMMIT
alter table t2 engine=INNODB;
delete from t1;
delete from t2;
@ -139,7 +149,7 @@ master-bin.000001 96 Query 1 # use `test`; BEGIN
master-bin.000001 158 Query 1 # use `test`; insert into t1 values(12)
master-bin.000001 240 Query 1 # use `test`; insert into t2 select * from t1
master-bin.000001 328 Xid 1 # xid=77
master-bin.000001 351 Query 1 # use `test`; COMMIT
master-bin.000001 355 Query 1 # use `test`; COMMIT
delete from t1;
delete from t2;
reset master;
@ -164,7 +174,7 @@ Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 96 Query 1 # use `test`; BEGIN
master-bin.000001 158 Query 1 # use `test`; insert into t1 values(14)
master-bin.000001 240 Xid 1 # xid=93
master-bin.000001 263 Query 1 # use `test`; COMMIT
master-bin.000001 267 Query 1 # use `test`; COMMIT
delete from t1;
delete from t2;
reset master;
@ -186,7 +196,7 @@ master-bin.000001 96 Query 1 # use `test`; BEGIN
master-bin.000001 158 Query 1 # use `test`; insert into t1 values(16)
master-bin.000001 240 Query 1 # use `test`; insert into t1 values(18)
master-bin.000001 322 Xid 1 # xid=104
master-bin.000001 345 Query 1 # use `test`; COMMIT
master-bin.000001 349 Query 1 # use `test`; COMMIT
delete from t1;
delete from t2;
alter table t2 type=MyISAM;

View file

@ -18,5 +18,5 @@ max(a)
8000
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 687231 # # master-bin.000001 Yes Yes 0 0 687231 # None 0 No #
# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 687235 # # master-bin.000001 Yes Yes 0 0 687235 # None 0 No #
drop table t1;

View file

@ -238,15 +238,13 @@ static int berkeley_commit(THD *thd, bool all)
DBUG_ENTER("berkeley_commit");
DBUG_PRINT("trans",("ending transaction %s", all ? "all" : "stmt"));
berkeley_trx_data *trx=(berkeley_trx_data *)thd->ha_data[berkeley_hton.slot];
int error=txn_commit(all ? trx->all : trx->stmt,0);
DB_TXN **txn= all ? &trx->all : &trx->stmt;
int error=txn_commit(*txn,0);
*txn=0;
#ifndef DBUG_OFF
if (error)
DBUG_PRINT("error",("error: %d",error));
#endif
if (all)
trx->all=0;
else
trx->stmt=0;
DBUG_RETURN(error);
}
@ -255,11 +253,9 @@ static int berkeley_rollback(THD *thd, bool all)
DBUG_ENTER("berkeley_rollback");
DBUG_PRINT("trans",("aborting transaction %s", all ? "all" : "stmt"));
berkeley_trx_data *trx=(berkeley_trx_data *)thd->ha_data[berkeley_hton.slot];
int error=txn_abort(all ? trx->all : trx->stmt);
if (all)
trx->all=0;
else
trx->stmt=0;
DB_TXN **txn= all ? &trx->all : &trx->stmt;
int error=txn_abort(*txn);
*txn=0;
DBUG_RETURN(error);
}
@ -1904,7 +1900,7 @@ int ha_berkeley::external_lock(THD *thd, int lock_type)
if (trx->stmt)
{
/*
F_UNLOCK is done without a transaction commit / rollback.
F_UNLCK is done without a transaction commit / rollback.
This happens if the thread didn't update any rows
We must in this case commit the work to keep the row locks
*/
@ -1929,6 +1925,7 @@ int ha_berkeley::start_stmt(THD *thd)
int error=0;
DBUG_ENTER("ha_berkeley::start_stmt");
berkeley_trx_data *trx=(berkeley_trx_data *)thd->ha_data[berkeley_hton.slot];
DBUG_ASSERT(trx);
/*
note that trx->stmt may have been already initialized as start_stmt()
is called for *each table* not for each storage engine,
@ -2277,6 +2274,7 @@ int ha_berkeley::analyze(THD* thd, HA_CHECK_OPT* check_opt)
DB_BTREE_STAT *stat=0;
DB_TXN_STAT *txn_stat_ptr= 0;
berkeley_trx_data *trx=(berkeley_trx_data *)thd->ha_data[berkeley_hton.slot];
DBUG_ASSERT(trx);
/*
Original bdb documentation says:
@ -2291,10 +2289,10 @@ int ha_berkeley::analyze(THD* thd, HA_CHECK_OPT* check_opt)
txn_stat_ptr && txn_stat_ptr->st_nactive>=2)
{
DB_TXN_ACTIVE *atxn_stmt= 0, *atxn_all= 0;
u_int32_t all_id= trx->all->id(trx->all);
u_int32_t stmt_id= trx->stmt->id(trx->stmt);
DB_TXN_ACTIVE *cur= txn_stat_ptr->st_txnarray;
DB_TXN_ACTIVE *end= cur + txn_stat_ptr->st_nactive;
for (; cur!=end && (!atxn_stmt || !atxn_all); cur++)
@ -2302,7 +2300,7 @@ int ha_berkeley::analyze(THD* thd, HA_CHECK_OPT* check_opt)
if (cur->txnid==all_id) atxn_all= cur;
if (cur->txnid==stmt_id) atxn_stmt= cur;
}
if (atxn_stmt && atxn_all &&
log_compare(&atxn_stmt->lsn,&atxn_all->lsn))
{

View file

@ -698,7 +698,7 @@ ha_innobase::update_thd(
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
trx_t* trx;
trx = check_trx_exists(thd);
if (prebuilt->trx != trx) {
@ -711,11 +711,23 @@ ha_innobase::update_thd(
return(0);
}
static void register_trans(THD *thd)
/*************************************************************************
Registers the InnoDB transaction in MySQL, to receive commit/rollback
events. This function must be called every time InnoDB starts a
transaction internally. */
static
void
register_trans(
/*============*/
THD* thd) /* in: thd to use the handle */
{
trans_register_ha(thd, FALSE, &innobase_hton);
if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
trans_register_ha(thd, TRUE, &innobase_hton);
/* register the start of the statement */
trans_register_ha(thd, FALSE, &innobase_hton);
if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
/* no autocommit mode, register for a transaction */
trans_register_ha(thd, TRUE, &innobase_hton);
}
}
/* BACKGROUND INFO: HOW THE MYSQL QUERY CACHE WORKS WITH INNODB
@ -1459,12 +1471,12 @@ innobase_report_binlog_offset_and_commit(
ut_a(trx != NULL);
trx->mysql_log_file_name = log_file_name;
trx->mysql_log_file_name = log_file_name;
trx->mysql_log_offset = (ib_longlong)end_offset;
trx->flush_log_later = TRUE;
innobase_commit(thd, trx_handle);
innobase_commit(thd, trx_handle);
trx->flush_log_later = FALSE;
@ -1474,18 +1486,18 @@ innobase_report_binlog_offset_and_commit(
/***********************************************************************
This function stores the binlog offset and flushes logs. */
void
void
innobase_store_binlog_offset_and_flush_log(
/*=======================================*/
char *binlog_name, /* in: binlog name */
longlong offset) /* in: binlog offset */
longlong offset) /* in: binlog offset */
{
mtr_t mtr;
assert(binlog_name != NULL);
/* Start a mini-transaction */
mtr_start_noninline(&mtr);
mtr_start_noninline(&mtr);
/* Update the latest MySQL binlog name and offset info
in trx sys header */
@ -1497,7 +1509,7 @@ innobase_store_binlog_offset_and_flush_log(
/* Commits the mini-transaction */
mtr_commit(&mtr);
/* Syncronous flush of the log buffer to disk */
log_buffer_flush_to_disk();
}
@ -1520,14 +1532,14 @@ innobase_commit_complete(
if (trx && trx->active_trans) {
trx->active_trans = 0;
trx->active_trans = 0;
if (srv_flush_log_at_trx_commit == 0) {
if (srv_flush_log_at_trx_commit == 0) {
return(0);
}
return(0);
}
trx_commit_complete_for_mysql(trx);
trx_commit_complete_for_mysql(trx);
}
return(0);

View file

@ -59,8 +59,15 @@ static int NEAR_F delete_file(const char *name,const char *ext,int extflag);
static SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES;
/* list of all available storage engines (of their handlertons) */
handlerton *handlertons[MAX_HA]={0};
ulong total_ha, total_ha_2pc, savepoint_alloc_size;
/* number of entries in handlertons[] */
ulong total_ha;
/* number of storage engines (from handlertons[]) that support 2pc */
ulong total_ha_2pc;
/* size of savepoint storage area (see ha_init) */
ulong savepoint_alloc_size;
struct show_table_type_st sys_table_types[]=
{
@ -120,7 +127,7 @@ enum db_type ha_resolve_by_name(const char *name, uint namelen)
if (thd && !my_strcasecmp(&my_charset_latin1, name, "DEFAULT")) {
return (enum db_type) thd->variables.table_type;
}
show_table_type_st *types;
for (types= sys_table_types; types->type; types++)
{
@ -138,7 +145,7 @@ const char *ha_get_storage_engine(enum db_type db_type)
if (db_type == types->db_type)
return types->type;
}
return "none";
}
@ -439,6 +446,7 @@ int ha_commit_trans(THD *thd, bool all)
THD_TRANS *trans= all ? &thd->transaction.all : &thd->transaction.stmt;
bool is_real_trans= all || thd->transaction.all.nht == 0;
handlerton **ht= trans->ht;
my_xid xid= thd->transaction.xid.get_my_xid();
DBUG_ENTER("ha_commit_trans");
#ifdef USING_TRANSACTIONS
if (trans->nht)
@ -455,9 +463,8 @@ int ha_commit_trans(THD *thd, bool all)
}
statistic_increment(thd->status_var.ha_prepare_count,&LOCK_status);
}
if (error || (is_real_trans &&
(error= !(cookie= tc_log->log(thd,
thd->transaction.xid.quick_get_my_xid())))))
if (error || (is_real_trans && xid &&
(error= !(cookie= tc_log->log(thd, xid)))))
{
ha_rollback_trans(thd, all);
return 1;
@ -465,7 +472,7 @@ int ha_commit_trans(THD *thd, bool all)
}
error=ha_commit_one_phase(thd, all) ? cookie ? 2 : 1 : 0;
if (cookie)
tc_log->unlog(cookie, thd->transaction.xid.quick_get_my_xid());
tc_log->unlog(cookie, xid);
}
#endif /* USING_TRANSACTIONS */
DBUG_RETURN(error);
@ -486,7 +493,7 @@ int ha_commit_one_phase(THD *thd, bool all)
{
if ((error= wait_if_global_read_lock(thd, 0, 0)))
{
my_error(ER_SERVER_SHUTDOWN, MYF(0)); // we're killed
my_error(ER_ERROR_DURING_COMMIT, MYF(0), error);
error= 1;
}
else

View file

@ -195,7 +195,7 @@ enum row_type { ROW_TYPE_NOT_USED=-1, ROW_TYPE_DEFAULT, ROW_TYPE_FIXED,
#define HA_CREATE_USED_COMMENT (1L << 16)
#define HA_CREATE_USED_PASSWORD (1L << 17)
typedef ulong my_xid;
typedef ulonglong my_xid;
#define MYSQL_XID_PREFIX "MySQLXid"
#define MYSQL_XID_PREFIX_LEN 8 // must be a multiple of 8
#define MYSQL_XID_OFFSET (MYSQL_XID_PREFIX_LEN+sizeof(server_id))
@ -215,11 +215,11 @@ struct xid_t {
bool eq(long g, long b, const char *d)
{ return g == gtrid_length && b == bqual_length && !memcmp(d, data, g+b); }
void set(LEX_STRING *l) { set(l->length, 0, l->str); }
void set(ulong l)
void set(ulonglong l)
{
set(MYSQL_XID_PREFIX_LEN, 0, MYSQL_XID_PREFIX);
*(ulong*)(data+MYSQL_XID_PREFIX_LEN)=server_id;
*(ulong*)(data+MYSQL_XID_OFFSET)=l;
*(my_xid*)(data+MYSQL_XID_OFFSET)=l;
gtrid_length=MYSQL_XID_GTRID_LEN;
}
void set(long g, long b, const char *d)
@ -233,7 +233,7 @@ struct xid_t {
void null() { formatID= -1; }
my_xid quick_get_my_xid()
{
return *(ulong*)(data+MYSQL_XID_OFFSET);
return *(my_xid*)(data+MYSQL_XID_OFFSET);
}
my_xid get_my_xid()
{
@ -319,8 +319,11 @@ typedef struct
typedef struct st_thd_trans
{
/* number of entries in the ht[] */
uint nht;
/* true is not all entries in the ht[] support 2pc */
bool no_2pc;
/* storage engines that registered themselves for this transaction */
handlerton *ht[MAX_HA];
} THD_TRANS;

View file

@ -2096,7 +2096,7 @@ void item_user_lock_release(User_level_lock *ull)
tmp.copy(command, strlen(command), tmp.charset());
tmp.append(ull->key,ull->key_length);
tmp.append("\")", 2);
Query_log_event qev(current_thd, tmp.ptr(), tmp.length(),1, FALSE);
Query_log_event qev(current_thd, tmp.ptr(), tmp.length(), 0, FALSE);
qev.error_code=0; // this query is always safe to run on slave
mysql_bin_log.write(&qev);
}

View file

@ -75,6 +75,7 @@ handlerton *binlog_init()
static int binlog_close_connection(THD *thd)
{
IO_CACHE *trans_log= (IO_CACHE*)thd->ha_data[binlog_hton.slot];
DBUG_ASSERT(mysql_bin_log.is_open() && !my_b_tell(trans_log));
close_cached_file(trans_log);
my_free((gptr)trans_log, MYF(0));
return 0;
@ -109,7 +110,7 @@ static int binlog_commit(THD *thd, bool all)
IO_CACHE *trans_log= (IO_CACHE*)thd->ha_data[binlog_hton.slot];
DBUG_ENTER("binlog_commit");
DBUG_ASSERT(mysql_bin_log.is_open() &&
(all || !(thd->options & OPTION_NOT_AUTOCOMMIT)));
(all || !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))));
if (!my_b_tell(trans_log))
{
@ -1247,7 +1248,7 @@ void MYSQL_LOG::new_file(bool need_lock)
{
pthread_mutex_lock(&LOCK_log);
pthread_mutex_lock(&LOCK_index);
}
}
safe_mutex_assert_owner(&LOCK_log);
safe_mutex_assert_owner(&LOCK_index);
@ -1567,10 +1568,14 @@ bool MYSQL_LOG::write(Log_event* event_info)
goto err;
}
trans_log->end_of_file= max_binlog_cache_size;
trans_register_ha(thd, TRUE, &binlog_hton);
trans_register_ha(thd,
thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN),
&binlog_hton);
}
else if (!my_b_tell(trans_log))
trans_register_ha(thd, TRUE, &binlog_hton);
trans_register_ha(thd,
thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN),
&binlog_hton);
file= trans_log;
}
else if (trans_log && my_b_tell(trans_log))
@ -2057,8 +2062,7 @@ void MYSQL_LOG::close(uint exiting)
{
my_off_t offset= BIN_LOG_HEADER_SIZE + FLAGS_OFFSET;
char flags=LOG_EVENT_BINLOG_CLOSED_F;
my_pwrite(log_file.file, &flags, 1,
BIN_LOG_HEADER_SIZE + FLAGS_OFFSET, MYF(0));
my_pwrite(log_file.file, &flags, 1, offset, MYF(0));
}
if (my_close(log_file.file,MYF(0)) < 0 && ! write_error)
@ -2382,26 +2386,33 @@ void sql_print_information(const char *format, ...)
(usable size of the first page is smaller because of log header)
there's PAGE control structure for each page
each page (or rather PAGE control structure) can be in one of three
states - active, in_sync, pool.
there could be only one page in active or in_sync states,
states - active, syncing, pool.
there could be only one page in active or syncing states,
but many in pool - pool is fifo queue.
usual lifecycle of a page is pool->active->in_sync->pool
usual lifecycle of a page is pool->active->syncing->pool
"active" page - is a page where new xid's are logged.
the page stays active as long as in_sync slot is taken.
"in_sync" page is being synced to disk. no new xid can be added to it.
the page stays active as long as syncing slot is taken.
"syncing" page is being synced to disk. no new xid can be added to it.
when the sync is done the page is moved to a pool and an active page
becomes "in_sync".
becomes "syncing".
when a xid is added to an active page, the thread of this xid waits for
a page's condition until the page is synced. when in_sync slot becomes vacant
one of these waiters is awaken to take care of syncing. it syncs the page
and signals all waiters that the page is synced.
the result of such an architecture is a natural "commit grouping" -
If commits are coming faster than the system can sync, they do not
stall. Instead, all commit that came since the last sync are
logged to the same page, and they all are synced with the next -
one - sync. Thus, thought individual commits are delayed, throughput
is not decreasing.
when a xid is added to an active page, the thread of this xid waits
for a page's condition until the page is synced. when syncing slot
becomes vacant one of these waiters is awaken to take care of syncing.
it syncs the page and signals all waiters that the page is synced.
PAGE::waiters is used to count these waiters, and a page may never
become active again until waiters==0 (that is all waiters from the
previous sync have noticed the sync was completed)
note, that the page becomes "dirty" and has to be synced only when
a new xid is added into it. Removing a xid from a page does not make it
note, that the page becomes "dirty" and has to be synced only when a
new xid is added into it. Removing a xid from a page does not make it
dirty - we don't sync removals to disk.
*/
#define TC_LOG_HEADER_SIZE (sizeof(tc_log_magic)+1)
@ -2433,35 +2444,38 @@ int TC_LOG_MMAP::open(const char *opt_name)
#endif
fn_format(logname,opt_name,mysql_data_home,"",MY_UNPACK_FILENAME);
fd=my_open(logname, O_RDWR, MYF(0)); // TODO use O_CREAT and check len==0 ?
fd= my_open(logname, O_RDWR, MYF(0));
if (fd == -1)
{
if (my_errno != ENOENT)
goto err;
if (using_heuristic_recover())
return 1;
fd=my_open(logname, O_RDWR|O_CREAT, MYF(MY_WME));
fd= my_create(logname, O_RDWR, 0, MYF(MY_WME));
if (fd == -1)
goto err;
inited=1;
file_length=opt_tc_log_size;
file_length= opt_tc_log_size;
if (my_chsize(fd, file_length, 0, MYF(MY_WME)))
goto err;
}
else
{
inited=1;
crashed=TRUE;
inited= 1;
crashed= TRUE;
sql_print_information("Recovering after a crash");
if (tc_heuristic_recover)
{
sql_print_error("Cannot perform automatic crash recovery when "
"--tc-heuristic-recover is used");
goto err;
}
file_length = my_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME+MY_FAE));
file_length= my_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME+MY_FAE));
if (file_length == MY_FILEPOS_ERROR || file_length % tc_log_page_size)
goto err;
}
data=(uchar *)my_mmap(0, file_length, PROT_READ|PROT_WRITE,
data= (uchar *)my_mmap(0, file_length, PROT_READ|PROT_WRITE,
MAP_NOSYNC|MAP_SHARED, fd, 0);
if (data == MAP_FAILED)
{
@ -2486,18 +2500,15 @@ int TC_LOG_MMAP::open(const char *opt_name)
pg->end=(my_xid *)(pg->start + tc_log_page_size);
pg->size=pg->free=tc_log_page_size/sizeof(my_xid);
}
pages[0].start=(my_xid *)(data+TC_LOG_HEADER_SIZE);
pages[0].size=pages[0].free=
(tc_log_page_size-TC_LOG_HEADER_SIZE)/sizeof(my_xid);
pages[0].start=pages[0].end-pages[0].size;
pages[npages-1].next=0;
inited=4;
if (crashed)
{
sql_print_error("Recovering after a crash");
if (recover())
if (crashed && recover())
goto err;
}
memcpy(data, tc_log_magic, sizeof(tc_log_magic));
data[sizeof(tc_log_magic)]= total_ha_2pc;
my_msync(fd, data, tc_log_page_size, MS_SYNC);
@ -2511,7 +2522,7 @@ int TC_LOG_MMAP::open(const char *opt_name)
inited=6;
in_sync= 0;
syncing= 0;
active=pages;
pool=pages+1;
pool_last=pages+npages-1;
@ -2524,6 +2535,8 @@ err:
}
/*
there is no active page, let's got one from the pool
two strategies here:
1. take the first from the pool
2. if there're waiters - take the one with the most free space
@ -2536,13 +2549,16 @@ void TC_LOG_MMAP::get_active_from_pool()
PAGE **p, **best_p=0;
int best_free;
if (syncing)
pthread_mutex_lock(&LOCK_pool);
do
{
best_p= p= &pool;
if ((*p)->waiters == 0)
break;
if ((*p)->waiters == 0) // can the first page be used ?
break; // yes - take it.
best_free=0;
best_free=0; // no - trying second strategy
for (p=&(*p)->next; *p; p=&(*p)->next)
{
if ((*p)->waiters == 0 && (*p)->free > best_free)
@ -2555,16 +2571,19 @@ void TC_LOG_MMAP::get_active_from_pool()
while ((*best_p == 0 || best_free == 0) && overflow());
active=*best_p;
if (active->free == active->size)
if (active->free == active->size) // we've chosen an empty page
{
tc_log_cur_pages_used++;
set_if_bigger(tc_log_max_pages_used, tc_log_cur_pages_used);
}
if ((*best_p)->next)
if ((*best_p)->next) // unlink the page from the pool
*best_p=(*best_p)->next;
else
pool_last=*best_p;
if (syncing)
pthread_mutex_unlock(&LOCK_pool);
}
int TC_LOG_MMAP::overflow()
@ -2576,14 +2595,22 @@ int TC_LOG_MMAP::overflow()
*/
tc_log_page_waits++;
pthread_cond_wait(&COND_pool, &LOCK_pool);
return 1; // returns always 1
return 1; // always return 1
}
/*
all access to active page is serialized but it's not a problem, as we're
assuming that fsync() will be a bottleneck anyway.
That is, parallelizing writes to log pages we'll decrease number of threads
waiting for a page, but then all these threads will be waiting for fsync()
all access to active page is serialized but it's not a problem, as
we're assuming that fsync() will be a main bottleneck.
That is, parallelizing writes to log pages we'll decrease number of
threads waiting for a page, but then all these threads will be waiting
for a fsync() anyway
RETURN
0 - error
otherwise - "cookie", a number that will be passed as an argument
to unlog() call. tc_log can define it any way it wants,
and use for whatever purposes. TC_LOG_MMAP sets it
to the position in memory where xid was logged to.
*/
int TC_LOG_MMAP::log(THD *thd, my_xid xid)
@ -2594,42 +2621,50 @@ int TC_LOG_MMAP::log(THD *thd, my_xid xid)
pthread_mutex_lock(&LOCK_active);
/*
if active page is full - just wait...
frankly speaking, active->free here accessed outside of mutex
protection, but it's safe, because it only means we may miss an
unlog() for the active page, and we're not waiting for it here -
unlog() does not signal COND_active.
*/
while (unlikely(active && active->free == 0))
pthread_cond_wait(&COND_active, &LOCK_active);
/* no active page ? take one from the pool */
if (active == 0)
{
lock_queue(&LOCK_pool);
get_active_from_pool();
unlock_queue(&LOCK_pool);
}
p=active;
pthread_mutex_lock(&p->lock);
/* searching for an empty slot */
while (*p->ptr)
{
p->ptr++;
DBUG_ASSERT(p->ptr < p->end); // because p->free > 0
}
cookie= (ulong)((uchar *)p->ptr - data); // Can never be zero
/* found! store xid there and mark the page dirty */
cookie= (ulong)((uchar *)p->ptr - data); // can never be zero
*p->ptr++= xid;
p->free--;
p->state= DIRTY;
/* to sync or not to sync - this is the question */
pthread_mutex_unlock(&LOCK_active);
pthread_mutex_lock(&LOCK_sync);
pthread_mutex_unlock(&p->lock);
if (in_sync)
if (syncing)
{ // somebody's syncing. let's wait
pthread_mutex_unlock(&LOCK_active);
p->waiters++;
do
{
/*
note - it must be while(), not do ... while() here
as p->state may be not DIRTY when we come here
*/
while (p->state == DIRTY && syncing)
pthread_cond_wait(&p->cond, &LOCK_sync);
} while (p->state == DIRTY && in_sync);
p->waiters--;
err= p->state == ERROR;
if (p->state != DIRTY) // page was synced
@ -2640,9 +2675,10 @@ int TC_LOG_MMAP::log(THD *thd, my_xid xid)
goto done; // we're done
}
} // page was not synced! do it now
in_sync=p; // place is vacant - take it
DBUG_ASSERT(active == p);
active=0;
DBUG_ASSERT(active == p && syncing == 0);
pthread_mutex_lock(&LOCK_active);
syncing=p; // place is vacant - take it
active=0; // page is not active anymore
pthread_cond_broadcast(&COND_active); // in case somebody's waiting
pthread_mutex_unlock(&LOCK_active);
pthread_mutex_unlock(&LOCK_sync);
@ -2656,30 +2692,36 @@ int TC_LOG_MMAP::sync()
{
int err;
DBUG_ASSERT(in_sync != active);
DBUG_ASSERT(syncing != active);
/*
sit down and relax - this can take a while...
note - no locks are held at this point
*/
err= my_msync(fd, in_sync->start, 1, MS_SYNC);
err= my_msync(fd, syncing->start, 1, MS_SYNC);
/* page is synced. let's move it to the pool */
pthread_mutex_lock(&LOCK_pool);
pool_last->next=in_sync;
pool_last=in_sync;
in_sync->next=0;
in_sync->state= err ? ERROR : POOL;
pthread_cond_broadcast(&in_sync->cond); // signal "sync done"
pool_last->next=syncing;
pool_last=syncing;
syncing->next=0;
syncing->state= err ? ERROR : POOL;
pthread_cond_broadcast(&syncing->cond); // signal "sync done"
pthread_cond_signal(&COND_pool); // in case somebody's waiting
pthread_mutex_unlock(&LOCK_pool);
/* marking 'syncing' slot free */
pthread_mutex_lock(&LOCK_sync);
in_sync=0;
syncing=0;
pthread_cond_signal(&active->cond); // wake up a new syncer
pthread_mutex_unlock(&LOCK_sync);
return err;
}
/*
erase xid from the page, update page free space counters/pointers.
cookie points directly to the memory where xid was logged
*/
void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid)
{
PAGE *p=pages+(cookie/tc_log_page_size);
@ -2693,10 +2735,10 @@ void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid)
p->free++;
DBUG_ASSERT(p->free <= p->size);
set_if_smaller(p->ptr, x);
if (p->free == p->size)
if (p->free == p->size) // the page is completely empty
statistic_decrement(tc_log_cur_pages_used, &LOCK_status);
if (p->waiters == 0) // the page is in pool and ready to rock
pthread_cond_signal(&COND_pool); // ping ... in case somebody's waiting
pthread_cond_signal(&COND_pool); // ping ... for overflow()
pthread_mutex_unlock(&p->lock);
}
@ -2747,8 +2789,10 @@ int TC_LOG_MMAP::recover()
*/
if (data[sizeof(tc_log_magic)] != total_ha_2pc)
{
sql_print_error("For recovery to work all storage engines and binary log "
"must have exactly the same settings as before the crash!");
sql_print_error("Recovery failed! You must have enabled "
"exactly %d storage engines that support "
"two-phase commit protocol",
data[sizeof(tc_log_magic)]);
goto err1;
}
@ -2793,6 +2837,7 @@ int TC_LOG::using_heuristic_recover()
}
/****** transaction coordinator log for 2pc - binlog() based solution ******/
#define TC_LOG_BINLOG MYSQL_LOG
/*
TODO keep in-memory list of prepared transactions
@ -2801,9 +2846,10 @@ int TC_LOG::using_heuristic_recover()
but let's check the behaviour of tc_log_page_waits first!
*/
int MYSQL_LOG::open(const char *opt_name)
int TC_LOG_BINLOG::open(const char *opt_name)
{
LOG_INFO log_info, new_log_info;
int error;
DBUG_ASSERT(total_ha_2pc > 1);
@ -2821,8 +2867,11 @@ int MYSQL_LOG::open(const char *opt_name)
let's keep it happy.
*/
if (find_log_pos(&new_log_info, NullS, 1))
if ((error= find_log_pos(&new_log_info, NullS, 1)))
{
sql_print_error("find_log_pos() failed (error: %d)", error);
goto err; // er ? where's the current entry ?
}
if (strcmp(log_file_name, new_log_info.log_file_name))
{
@ -2830,9 +2879,8 @@ int MYSQL_LOG::open(const char *opt_name)
char last_event_type=UNKNOWN_EVENT;
IO_CACHE log;
File file;
int error;
Log_event *ev;
Format_description_log_event fdle(4);
Log_event *ev=0;
Format_description_log_event fdle(BINLOG_VERSION);
if (! fdle.is_valid())
goto err;
@ -2842,8 +2890,11 @@ int MYSQL_LOG::open(const char *opt_name)
log_info.index_file_offset=new_log_info.index_file_offset;
log_info.index_file_start_offset=new_log_info.index_file_offset;
strcpy(log_info.log_file_name, new_log_info.log_file_name);
if (find_next_log(&new_log_info, 1))
goto err; // er ? where's the current entry ?
if ((error= find_next_log(&new_log_info, 1)))
{
sql_print_error("find_log_pos() failed (error: %d)", error);
goto err; // er ? where's the current entry ?
}
} while (strcmp(log_file_name, new_log_info.log_file_name));
if ((file= open_binlog(&log, log_info.log_file_name, &errmsg)) < 0)
@ -2853,11 +2904,14 @@ int MYSQL_LOG::open(const char *opt_name)
}
if (((ev= Log_event::read_log_event(&log, 0, &fdle))) &&
(ev->get_type_code() == FORMAT_DESCRIPTION_EVENT) &&
(ev->flags & LOG_EVENT_BINLOG_CLOSED_F))
error=0;
else
error= recover(&log, (Format_description_log_event *)ev);
(ev->get_type_code() == FORMAT_DESCRIPTION_EVENT))
{
if (ev->flags & LOG_EVENT_BINLOG_CLOSED_F)
error=0;
else
error= recover(&log, (Format_description_log_event *)ev);
}
// else nothing to do (probably MySQL 4.x binlog)
delete ev;
end_io_cache(&log);
@ -2873,15 +2927,22 @@ err:
return 1;
}
void MYSQL_LOG::close()
/* this is called on shutdown, after ha_panic */
void TC_LOG_BINLOG::close()
{
DBUG_ASSERT(prepared_xids==0);
pthread_mutex_destroy(&LOCK_prep_xids);
pthread_cond_destroy (&COND_prep_xids);
}
/* TODO group commit */
int MYSQL_LOG::log(THD *thd, my_xid xid)
/*
TODO group commit
RETURN
0 - error
1 - success
*/
int TC_LOG_BINLOG::log(THD *thd, my_xid xid)
{
Xid_log_event xle(thd, xid);
if (xle.write((IO_CACHE*)thd->ha_data[binlog_hton.slot]))
@ -2890,13 +2951,13 @@ int MYSQL_LOG::log(THD *thd, my_xid xid)
return !binlog_commit(thd,1); // invert return value
}
void MYSQL_LOG::unlog(ulong cookie, my_xid xid)
void TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
{
if (thread_safe_dec_and_test(prepared_xids, &LOCK_prep_xids))
pthread_cond_signal(&COND_prep_xids);
}
int MYSQL_LOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
{
Log_event *ev;
HASH xids;

View file

@ -288,8 +288,6 @@ Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans)
server_id= thd->server_id;
when= thd->start_time;
cache_stmt= using_trans;
cache_stmt= (using_trans &&
(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)));
}
@ -316,12 +314,12 @@ Log_event::Log_event()
*/
Log_event::Log_event(const char* buf,
const Format_description_log_event* description_event)
const Format_description_log_event* description_event)
:temp_buf(0), cache_stmt(0)
{
#ifndef MYSQL_CLIENT
thd = 0;
#endif
#endif
when = uint4korr(buf);
server_id = uint4korr(buf + SERVER_ID_OFFSET);
if (description_event->binlog_version==1)
@ -2982,11 +2980,19 @@ void Xid_log_event::pack_info(Protocol *protocol)
{
char buf[64], *pos;
pos= strmov(buf, "xid=");
pos= int10_to_str(xid, pos, 10);
pos= longlong10_to_str(xid, pos, 10);
protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
}
#endif
/*
NOTE it's ok not to use int8store here,
as long as xid_t::set(ulonglong) and
xid_t::get_my_xid doesn't do it either
we don't care about actual values of xids as long as
identical numbers compare identically
*/
Xid_log_event::Xid_log_event(const char* buf,
const Format_description_log_event* description_event)
:Log_event(buf, description_event)
@ -3006,14 +3012,15 @@ bool Xid_log_event::write(IO_CACHE* file)
#ifdef MYSQL_CLIENT
void Xid_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info)
{
char buf[512];
if (!short_form)
{
char buf[64];
longlong10_to_str(xid, buf, 10);
print_header(file);
fprintf(file, "\tXid\n");
fprintf(file, "\tXid = %s\n", buf);
fflush(file);
}
fprintf(file, "/* == %lu == */\n", xid);
fflush(file);
}
#endif /* MYSQL_CLIENT */

View file

@ -305,7 +305,10 @@ struct sql_ex_info
/*
This flag only makes sense for Format_description_log_event.
It is set not when the event is written, but when a binlog file
is closed.
is closed. It serves as a reliable indicator that binlog was
closed correctly. (Stop_log_event is not enough, there's always
a small chance that mysqld crashes in the middle of insert
and end of the binlog would look like a Stop_log_event)
*/
#define LOG_EVENT_BINLOG_CLOSED_F 0x1
@ -355,20 +358,26 @@ enum Log_event_type
{
/*
Every time you update this enum (when you add a type), you have to
update the code of Format_description_log_event::Format_description_log_event().
Make sure you always insert new types ***BEFORE*** ENUM_END_EVENT.
fix Format_description_log_event::Format_description_log_event().
*/
UNKNOWN_EVENT= 0, START_EVENT_V3, QUERY_EVENT, STOP_EVENT, ROTATE_EVENT,
INTVAR_EVENT, LOAD_EVENT, SLAVE_EVENT, CREATE_FILE_EVENT,
APPEND_BLOCK_EVENT, EXEC_LOAD_EVENT, DELETE_FILE_EVENT,
/*
NEW_LOAD_EVENT is like LOAD_EVENT except that it has a longer sql_ex,
allowing multibyte TERMINATED BY etc; both types share the same class
(Load_log_event)
NEW_LOAD_EVENT is like LOAD_EVENT except that it has a longer
sql_ex, allowing multibyte TERMINATED BY etc; both types share the
same class (Load_log_event)
*/
NEW_LOAD_EVENT, XID_EVENT,
NEW_LOAD_EVENT,
RAND_EVENT, USER_VAR_EVENT,
FORMAT_DESCRIPTION_EVENT,
XID_EVENT,
/*
add new events here - right above this comment!
existing events should never change their numbers
*/
ENUM_END_EVENT /* end marker */
};

View file

@ -1247,26 +1247,11 @@ SQL_CRYPT *get_crypt_for_frm(void);
/* query_id */
typedef ulong query_id_t;
typedef ulonglong query_id_t;
extern query_id_t query_id;
/*
increment query_id and return it.
but be sure it's never a 0
(2^32 at 1000 q/s rate will means an overflow every ~50 days.
*/
inline query_id_t next_query_id()
{
if (sizeof(query_id_t) <= 5) // assuming the compiler optimizes dead code away
{
query_id_t old_query_id=query_id;
if (unlikely(++query_id == 0))
query_id=1;
return old_query_id;
}
else
return query_id++;
}
/* increment query_id and return it. */
inline query_id_t next_query_id() { return query_id++; }
/* Some inline functions for more speed */

View file

@ -2162,8 +2162,8 @@ static void check_data_home(const char *path)
/*
All global error messages are sent here where the first one is stored for
the client
All global error messages are sent here where the first one is stored
for the client
*/
@ -2199,7 +2199,7 @@ extern "C" int my_message_sql(uint error, const char *str, myf MyFlags)
(thd->lex->current_select ?
thd->lex->current_select->no_error : 0),
(int) thd->is_fatal_error));
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str);
}
else
@ -5601,7 +5601,7 @@ static void mysql_init_variables(void)
opt_log= opt_update_log= opt_bin_log= opt_slow_log= 0;
opt_disable_networking= opt_skip_show_db=0;
opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname= 0;
opt_tc_log_file= "mysqld-tc.log"; // no hostname in tc_log file name !
opt_tc_log_file= "tc.log"; // no hostname in tc_log file name !
opt_secure_auth= 0;
opt_bootstrap= opt_myisam_log= 0;
mqh_used= 0;

View file

@ -5237,10 +5237,10 @@ ER_XAER_NOTA XAE04
ER_XAER_INVAL XAE05
eng "XAER_INVAL: Invalid arguments (or unsupported command)"
ER_XAER_RMFAIL XAE07
eng "XAER_RMFAIL: The command cannot be executed in this state"
eng "XAER_RMFAIL: The command cannot be executed in the %.64s state"
ER_XAER_OUTSIDE XAE09
eng "XAER_OUTSIDE: Some work is done outside global transaction"
ER_XAER_RMERR XAE03
eng "XAER_RMERR: fatal error occurred in the transaction branch - check your data for consistency"
eng "XAER_RMERR: Fatal error occurred in the transaction branch - check your data for consistency"
ER_XA_RBROLLBACK XA100
eng "XA_RBROLLBACK: Transaction branch was rolled back"

View file

@ -105,7 +105,13 @@ class TC_LOG_MMAP: public TC_LOG
File fd;
uint file_length, npages, inited;
uchar *data;
struct st_page *pages, *in_sync, *active, *pool, *pool_last;
struct st_page *pages, *syncing, *active, *pool, *pool_last;
/*
note that, e.g. LOCK_active is only used to protect
'active' pointer, to protect the content of the active page
one has to use active->lock.
Same for LOCK_pool and LOCK_sync
*/
pthread_mutex_t LOCK_active, LOCK_pool, LOCK_sync;
pthread_cond_t COND_pool, COND_active;
@ -121,17 +127,6 @@ class TC_LOG_MMAP: public TC_LOG
void get_active_from_pool();
int sync();
int overflow();
void compact_active();
void lock_queue(pthread_mutex_t *lock)
{
if (in_sync)
pthread_mutex_lock(lock);
}
void unlock_queue(pthread_mutex_t *lock)
{
if (in_sync)
pthread_mutex_unlock(lock);
}
};
extern TC_LOG *tc_log;
@ -881,6 +876,7 @@ struct st_savepoint {
};
enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED};
extern const char *xa_state_names[];
/*
A registry for item tree transformations performed during
@ -1775,7 +1771,7 @@ class multi_delete :public select_result_interceptor
ha_rows deleted, found;
uint num_of_tables;
int error;
bool do_delete, transactional_tables, log_delayed, normal_tables;
bool do_delete, transactional_tables, normal_tables;
public:
multi_delete(THD *thd, TABLE_LIST *dt, uint num_of_tables);
~multi_delete();
@ -1802,7 +1798,7 @@ class multi_update :public select_result_interceptor
uint table_count;
Copy_field *copy_field;
enum enum_duplicates handle_duplicates;
bool do_update, trans_safe, transactional_tables, log_delayed;
bool do_update, trans_safe, transactional_tables;
public:
multi_update(THD *thd_arg, TABLE_LIST *ut, TABLE_LIST *leaves_list,

View file

@ -36,8 +36,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
TABLE *table;
SQL_SELECT *select=0;
READ_RECORD info;
bool using_limit=limit != HA_POS_ERROR;
bool transactional_table, log_delayed, safe_update, const_cond;
bool using_limit=limit != HA_POS_ERROR;
bool transactional_table, safe_update, const_cond;
ha_rows deleted;
SELECT_LEX *select_lex= &thd->lex->select_lex;
DBUG_ENTER("mysql_delete");
@ -233,7 +233,6 @@ cleanup:
delete select;
transactional_table= table->file->has_transactions();
log_delayed= (transactional_table || table->tmp_table);
/*
We write to the binary log even if we deleted no row, because maybe the
user is using this command to ensure that a table is clean on master *and
@ -249,11 +248,11 @@ cleanup:
if (error <= 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
log_delayed, FALSE);
transactional_table, FALSE);
if (mysql_bin_log.write(&qinfo) && transactional_table)
error=1;
}
if (!log_delayed)
if (!transactional_table)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
if (transactional_table)
@ -398,7 +397,7 @@ multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt,
uint num_of_tables_arg)
: delete_tables(dt), thd(thd_arg), deleted(0), found(0),
num_of_tables(num_of_tables_arg), error(0),
do_delete(0), transactional_tables(0), log_delayed(0), normal_tables(0)
do_delete(0), transactional_tables(0), normal_tables(0)
{
tempfiles = (Unique **) sql_calloc(sizeof(Unique *) * (num_of_tables-1));
}
@ -445,9 +444,7 @@ multi_delete::initialize_tables(JOIN *join)
tbl->no_cache= 1;
tbl->used_keys.clear_all();
if (tbl->file->has_transactions())
log_delayed= transactional_tables= 1;
else if (tbl->tmp_table != NO_TMP_TABLE)
log_delayed= 1;
transactional_tables= 1;
else
normal_tables= 1;
}
@ -670,14 +667,14 @@ bool multi_delete::send_eof()
if (error <= 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
log_delayed, FALSE);
transactional_tables, FALSE);
if (mysql_bin_log.write(&qinfo) && !normal_tables)
local_error=1; // Log write failed: roll back the SQL statement
}
if (!log_delayed)
if (!transactional_tables)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
/* Commit or rollback the current SQL statement */
/* Commit or rollback the current SQL statement */
if (transactional_tables)
if (ha_autocommit_or_rollback(thd,local_error > 0))
local_error=1;
@ -768,7 +765,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
*fn_ext(path)=0; // Remove the .frm extension
error= ha_create_table(path,&create_info,1);
query_cache_invalidate3(thd, table_list, 0);
query_cache_invalidate3(thd, table_list, 0);
end:
if (!dont_send_ok)
@ -779,7 +776,7 @@ end:
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
thd->tmp_table, FALSE);
0, FALSE);
mysql_bin_log.write(&qinfo);
}
send_ok(thd); // This should return record count

View file

@ -168,7 +168,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
runs without --log-update or --log-bin).
*/
bool log_on= (thd->options & OPTION_BIN_LOG) || (!(thd->master_access & SUPER_ACL));
bool transactional_table, log_delayed;
bool transactional_table;
bool ignore_err= (thd->lex->duplicates == DUP_IGNORE);
uint value_count;
ulong counter = 1;
@ -447,7 +447,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
transactional_table= table->file->has_transactions();
log_delayed= (transactional_table || table->tmp_table);
if ((info.copied || info.deleted || info.updated) &&
(error <= 0 || !transactional_table))
{
@ -456,11 +455,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
if (error <= 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
log_delayed, FALSE);
transactional_table, FALSE);
if (mysql_bin_log.write(&qinfo) && transactional_table)
error=1;
}
if (!log_delayed)
if (!transactional_table)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
if (transactional_table)

View file

@ -105,7 +105,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
char *tdb= thd->db ? thd->db : db; // Result is never null
ulong skip_lines= ex->skip_lines;
int res;
bool transactional_table, log_delayed;
bool transactional_table;
DBUG_ENTER("mysql_load");
#ifdef EMBEDDED_LIBRARY
@ -133,7 +133,6 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
}
table= table_list->table;
transactional_table= table->file->has_transactions();
log_delayed= (transactional_table || table->tmp_table);
if (!fields.elements)
{
@ -261,7 +260,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
lf_info.handle_dup = handle_duplicates;
lf_info.wrote_create_file = 0;
lf_info.last_pos_in_file = HA_POS_ERROR;
lf_info.log_delayed= log_delayed;
lf_info.log_delayed= transactional_table;
read_info.set_io_cache_arg((void*) &lf_info);
}
#endif /*!EMBEDDED_LIBRARY*/
@ -363,7 +362,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
/* If the file was not empty, wrote_create_file is true */
if (lf_info.wrote_create_file)
{
Delete_file_log_event d(thd, db, log_delayed);
Delete_file_log_event d(thd, db, transactional_table);
mysql_bin_log.write(&d);
}
}
@ -375,7 +374,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
(ulong) (info.records - info.copied), (ulong) thd->cuted_fields);
send_ok(thd,info.copied+info.deleted,0L,name);
if (!log_delayed)
if (!transactional_table)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
#ifndef EMBEDDED_LIBRARY
if (mysql_bin_log.is_open())
@ -385,16 +384,16 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
block will be logged only after Execute_load_log_event (which is wrong),
when read_info is destroyed.
*/
read_info.end_io_cache();
read_info.end_io_cache();
if (lf_info.wrote_create_file)
{
Execute_load_log_event e(thd, db, log_delayed);
Execute_load_log_event e(thd, db, transactional_table);
mysql_bin_log.write(&e);
}
}
#endif /*!EMBEDDED_LIBRARY*/
if (transactional_table)
error=ha_autocommit_or_rollback(thd,error);
error=ha_autocommit_or_rollback(thd,error);
err:
if (thd->lock)
@ -402,7 +401,7 @@ err:
mysql_unlock_tables(thd, thd->lock);
thd->lock=0;
}
thd->abort_on_warning= 0;
thd->abort_on_warning= 0;
DBUG_RETURN(error);
}
@ -732,12 +731,11 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
my_free((gptr) buffer,MYF(0)); /* purecov: inspected */
error=1;
}
else
else
{
/*
init_io_cache() will not initialize read_function member
if the cache is READ_NET. The reason is explained in
mysys/mf_iocache.c. So we work around the problem with a
if the cache is READ_NET. So we work around the problem with a
manual assignment
*/
need_end_io_cache = 1;

View file

@ -83,6 +83,10 @@ const char *command_name[]={
"Error" // Last command number
};
const char *xa_state_names[]={
"NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
};
static char empty_c_string[1]= {0}; // Used for not defined 'db'
#ifdef __WIN__
@ -524,6 +528,12 @@ void free_max_user_conn(void)
sql_command is actually set to SQLCOM_END sometimes
so we need the +1 to include it in the array.
numbers are:
0 - read-only query
!= 0 - query that may change a table
2 - query that returns meaningful ROW_COUNT() -
a number of modified rows
*/
char uc_update_queries[SQLCOM_END+1];
@ -559,7 +569,7 @@ void init_update_queries(void)
bool is_update_query(enum enum_sql_command command)
{
DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
return uc_update_queries[command] > 0;
return uc_update_queries[command];
}
/*
@ -2153,7 +2163,7 @@ mysql_execute_command(THD *thd)
*/
if (opt_readonly &&
!(thd->slave_thread || (thd->master_access & SUPER_ACL)) &&
(uc_update_queries[lex->sql_command] > 0))
uc_update_queries[lex->sql_command])
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
DBUG_RETURN(-1);
@ -4056,7 +4066,6 @@ create_error:
break;
}
case SQLCOM_XA_START:
res= FALSE;
if (thd->transaction.xa_state == XA_IDLE && thd->lex->xa_opt == XA_RESUME)
{
if (! thd->transaction.xid.eq(&thd->lex->ident))
@ -4066,7 +4075,7 @@ create_error:
}
thd->transaction.xa_state=XA_ACTIVE;
send_ok(thd);
res=0;
res=TRUE;
break;
}
if (thd->lex->ident.length > MAXGTRIDSIZE || thd->lex->xa_opt != XA_NONE)
@ -4076,7 +4085,8 @@ create_error:
}
if (thd->transaction.xa_state != XA_NOTR)
{
my_error(ER_XAER_RMFAIL, MYF(0));
my_error(ER_XAER_RMFAIL, MYF(0),
xa_state_names[thd->transaction.xa_state]);
break;
}
if (thd->active_transaction() || thd->locked_tables)
@ -4091,11 +4101,10 @@ create_error:
OPTION_BEGIN);
thd->server_status|= SERVER_STATUS_IN_TRANS;
send_ok(thd);
res=0;
res=TRUE;
break;
case SQLCOM_XA_END:
/* fake it */
res= FALSE;
if (thd->lex->xa_opt != XA_NONE)
{ // SUSPEND and FOR MIGRATE are not supported yet. TODO
my_error(ER_XAER_INVAL, MYF(0));
@ -4103,7 +4112,8 @@ create_error:
}
if (thd->transaction.xa_state != XA_ACTIVE)
{
my_error(ER_XAER_RMFAIL, MYF(0));
my_error(ER_XAER_RMFAIL, MYF(0),
xa_state_names[thd->transaction.xa_state]);
break;
}
if (!thd->transaction.xid.eq(&thd->lex->ident))
@ -4113,13 +4123,13 @@ create_error:
}
thd->transaction.xa_state=XA_IDLE;
send_ok(thd);
res=0;
res=TRUE;
break;
case SQLCOM_XA_PREPARE:
res= FALSE;
if (thd->transaction.xa_state != XA_IDLE)
{
my_error(ER_XAER_RMFAIL, MYF(0));
my_error(ER_XAER_RMFAIL, MYF(0),
xa_state_names[thd->transaction.xa_state]);
break;
}
if (!thd->transaction.xid.eq(&thd->lex->ident))
@ -4133,7 +4143,7 @@ create_error:
thd->transaction.xa_state=XA_NOTR;
break;
}
res=0;
res=TRUE;
thd->transaction.xa_state=XA_PREPARED;
send_ok(thd);
break;
@ -4146,29 +4156,30 @@ create_error:
}
if (thd->transaction.xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE)
{
if (res=ha_commit(thd))
{
my_error(res==1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
res= FALSE;
}
int r;
if ((r= ha_commit(thd)))
my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
else
{
send_ok(thd);
res= TRUE;
}
}
else
if (thd->transaction.xa_state == XA_PREPARED && thd->lex->xa_opt == XA_NONE)
{
if (ha_commit_one_phase(thd, 1))
{
my_error(ER_XAER_RMERR, MYF(0));
res= FALSE;
}
else
{
send_ok(thd);
res= TRUE;
}
}
else
{
res= FALSE;
my_error(ER_XAER_RMFAIL, MYF(0));
my_error(ER_XAER_RMFAIL, MYF(0),
xa_state_names[thd->transaction.xa_state]);
break;
}
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
@ -4185,23 +4196,23 @@ create_error:
if (thd->transaction.xa_state != XA_IDLE &&
thd->transaction.xa_state != XA_PREPARED)
{
res= FALSE;
my_error(ER_XAER_RMFAIL, MYF(0));
my_error(ER_XAER_RMFAIL, MYF(0),
xa_state_names[thd->transaction.xa_state]);
break;
}
if (ha_rollback(thd))
{
my_error(ER_XAER_RMERR, MYF(0));
res= FALSE;
}
else
{
send_ok(thd);
res= TRUE;
}
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
thd->transaction.xa_state=XA_NOTR;
break;
case SQLCOM_XA_RECOVER:
res= mysql_xa_recover(thd);
res= !mysql_xa_recover(thd);
break;
default:
DBUG_ASSERT(0); /* Impossible */

View file

@ -14,7 +14,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* drop and alter of tables */
#include "mysql_priv.h"
@ -274,9 +273,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
{
if (!error)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
tmp_table_deleted && !some_tables_deleted,
FALSE);
Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
mysql_bin_log.write(&qinfo);
}
}
@ -1286,7 +1283,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
create_info Create information (like MAX_ROWS)
fields List of fields to create
keys List of keys to create
tmp_table Set to 1 if this is an internal temporary table
internal_tmp_table Set to 1 if this is an internal temporary table
(From ALTER TABLE)
DESCRIPTION
@ -1305,7 +1302,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
bool mysql_create_table(THD *thd,const char *db, const char *table_name,
HA_CREATE_INFO *create_info,
List<create_field> &fields,
List<Key> &keys,bool tmp_table,
List<Key> &keys,bool internal_tmp_table,
uint select_field_count)
{
char path[FN_REFLEN];
@ -1374,7 +1371,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
}
if (mysql_prepare_table(thd, create_info, fields,
keys, tmp_table, db_options, file,
keys, internal_tmp_table, db_options, file,
key_info_buffer, &key_count,
select_field_count))
DBUG_RETURN(TRUE);
@ -1408,7 +1405,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
if (wait_if_global_read_lock(thd, 0, 1))
DBUG_RETURN(error);
VOID(pthread_mutex_lock(&LOCK_open));
if (!tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
{
if (!access(path,F_OK))
{
@ -1475,13 +1472,10 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
}
thd->tmp_table_used= 1;
}
if (!tmp_table && mysql_bin_log.is_open())
if (!internal_tmp_table && mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
test(create_info->options &
HA_LEX_CREATE_TMP_TABLE),
FALSE);
Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
mysql_bin_log.write(&qinfo);
}
error= FALSE;
@ -2459,10 +2453,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
if (mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
test(create_info->options &
HA_LEX_CREATE_TMP_TABLE),
FALSE);
Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
mysql_bin_log.write(&qinfo);
}
res= FALSE;
@ -2572,7 +2563,7 @@ mysql_discard_or_import_tablespace(THD *thd,
goto err;
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
mysql_bin_log.write(&qinfo);
}
err:
@ -2961,7 +2952,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
mysql_bin_log.write(&qinfo);
}
if (do_send_ok)
@ -3377,7 +3368,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
mysql_bin_log.write(&qinfo);
}
goto end_temporary;
@ -3511,7 +3502,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
mysql_bin_log.write(&qinfo);
}
VOID(pthread_cond_broadcast(&COND_refresh));

View file

@ -118,7 +118,7 @@ int mysql_update(THD *thd,
{
bool using_limit= limit != HA_POS_ERROR;
bool safe_update= thd->options & OPTION_SAFE_UPDATES;
bool used_key_is_modified, transactional_table, log_delayed;
bool used_key_is_modified, transactional_table;
bool ignore_err= (thd->lex->duplicates == DUP_IGNORE);
int res;
int error=0;
@ -474,7 +474,6 @@ int mysql_update(THD *thd,
query_cache_invalidate3(thd, table_list, 1);
}
log_delayed= (transactional_table || table->tmp_table);
if ((updated || (error < 0)) && (error <= 0 || !transactional_table))
{
if (mysql_bin_log.is_open())
@ -482,11 +481,11 @@ int mysql_update(THD *thd,
if (error <= 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
log_delayed, FALSE);
transactional_table, FALSE);
if (mysql_bin_log.write(&qinfo) && transactional_table)
error=1; // Rollback update
}
if (!log_delayed)
if (!transactional_table)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
if (transactional_table)
@ -1001,7 +1000,6 @@ multi_update::initialize_tables(JOIN *join)
DBUG_RETURN(1);
main_table=join->join_tab->table;
trans_safe= transactional_tables= main_table->file->has_transactions();
log_delayed= trans_safe || main_table->tmp_table != NO_TMP_TABLE;
table_to_update= 0;
/* Create a temporary table for keys to all tables, except main table */
@ -1339,17 +1337,13 @@ int multi_update::do_updates(bool from_send_error)
goto err;
}
updated++;
if (table->tmp_table != NO_TMP_TABLE)
log_delayed= 1;
}
}
if (updated != org_updated)
{
if (table->tmp_table != NO_TMP_TABLE)
log_delayed= 1; // Tmp tables forces delay log
if (table->file->has_transactions())
log_delayed= transactional_tables= 1;
transactional_tables= 1;
else
trans_safe= 0; // Can't do safe rollback
}
@ -1370,10 +1364,8 @@ err:
if (updated != org_updated)
{
if (table->tmp_table != NO_TMP_TABLE)
log_delayed= 1;
if (table->file->has_transactions())
log_delayed= transactional_tables= 1;
transactional_tables= 1;
else
trans_safe= 0;
}
@ -1415,11 +1407,11 @@ bool multi_update::send_eof()
if (local_error <= 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
log_delayed, FALSE);
transactional_tables, FALSE);
if (mysql_bin_log.write(&qinfo) && trans_safe)
local_error= 1; // Rollback update
}
if (!log_delayed)
if (!transactional_tables)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}