diff -r 8fadb9f22d1c innobase/buf/buf0flu.c --- a/innobase/buf/buf0flu.c Thu Oct 09 17:29:20 2008 -0700 +++ b/innobase/buf/buf0flu.c Fri Oct 17 02:50:16 2008 -0700 @@ -341,7 +341,7 @@ /* Now flush the doublewrite buffer data to disk */ - fil_flush(TRX_SYS_SPACE); + fil_flush(TRX_SYS_SPACE, FLUSH_FROM_DIRTY_BUFFER); /* We know that the writes have been flushed to disk now and in recovery we will find them in the doublewrite buffer @@ -381,7 +381,7 @@ /* Now we flush the data to disk (for example, with fsync) */ - fil_flush_file_spaces(FIL_TABLESPACE); + fil_flush_file_spaces(FIL_TABLESPACE, FLUSH_FROM_DIRTY_BUFFER); /* We can now reuse the doublewrite memory buffer: */ @@ -501,7 +501,8 @@ } #else /* Force the log to the disk before writing the modified block */ - log_write_up_to(block->newest_modification, LOG_WAIT_ALL_GROUPS, TRUE); + log_write_up_to(block->newest_modification, LOG_WAIT_ALL_GROUPS, TRUE, + LOG_WRITE_FROM_DIRTY_BUFFER); #endif buf_flush_init_for_writing(block->frame, block->newest_modification, block->space, block->offset); diff -r 8fadb9f22d1c innobase/fil/fil0fil.c --- a/innobase/fil/fil0fil.c Thu Oct 09 17:29:20 2008 -0700 +++ b/innobase/fil/fil0fil.c Fri Oct 17 02:50:16 2008 -0700 @@ -245,6 +245,7 @@ request */ UT_LIST_BASE_NODE_T(fil_space_t) space_list; /* list of all file spaces */ + ulint flush_types[FLUSH_FROM_NUMBER];/* calls to fil_flush by caller */ }; /* The tablespace memory cache. This variable is NULL before the module is @@ -849,7 +850,7 @@ /* Flush tablespaces so that we can close modified files in the LRU list */ - fil_flush_file_spaces(FIL_TABLESPACE); + fil_flush_file_spaces(FIL_TABLESPACE, FLUSH_FROM_OTHER); count++; @@ -1309,7 +1310,10 @@ UT_LIST_INIT(system->unflushed_spaces); UT_LIST_INIT(system->space_list); - + { + int x; + for (x = 0; x < FLUSH_FROM_NUMBER; ++x) system->flush_types[x] = 0; + } return(system); } @@ -1437,6 +1441,23 @@ } mutex_exit(&(system->mutex)); +} + +/******************************************************************** +Prints internal counters */ + +void +fil_print(FILE *file) +{ + fprintf(file, + "fsync callers: %lu buffer pool, %lu other, %lu checkpoint, " + "%lu log aio, %lu log sync, %lu archive\n", + fil_system->flush_types[FLUSH_FROM_DIRTY_BUFFER], + fil_system->flush_types[FLUSH_FROM_OTHER], + fil_system->flush_types[FLUSH_FROM_CHECKPOINT], + fil_system->flush_types[FLUSH_FROM_LOG_IO_COMPLETE], + fil_system->flush_types[FLUSH_FROM_LOG_WRITE_UP_TO], + fil_system->flush_types[FLUSH_FROM_ARCHIVE]); } /******************************************************************** @@ -2256,7 +2277,7 @@ os_thread_sleep(20000); - fil_flush(id); + fil_flush(id, FLUSH_FROM_OTHER); goto retry; @@ -3574,7 +3595,7 @@ size_after_extend, *actual_size); */ mutex_exit(&(system->mutex)); - fil_flush(space_id); + fil_flush(space_id, FLUSH_FROM_OTHER); return(success); } @@ -4166,8 +4187,9 @@ void fil_flush( /*======*/ - ulint space_id) /* in: file space id (this can be a group of + ulint space_id, /* in: file space id (this can be a group of log files or a tablespace of the database) */ + flush_from_type flush_type)/* in: identifies the caller */ { fil_system_t* system = fil_system; fil_space_t* space; @@ -4176,7 +4198,7 @@ ib_longlong old_mod_counter; mutex_enter(&(system->mutex)); - + system->flush_types[flush_type]++; HASH_SEARCH(hash, system->spaces, space_id, space, space->id == space_id); if (!space || space->is_being_deleted) { @@ -4281,7 +4303,8 @@ void fil_flush_file_spaces( /*==================*/ - ulint purpose) /* in: FIL_TABLESPACE, FIL_LOG */ + ulint purpose, /* in: FIL_TABLESPACE, FIL_LOG */ + flush_from_type flush_type)/* in: identifies the caller */ { fil_system_t* system = fil_system; fil_space_t* space; @@ -4322,7 +4345,7 @@ a non-existing space id. */ for (i = 0; i < n_space_ids; i++) { - fil_flush(space_ids[i]); + fil_flush(space_ids[i], flush_type); } mem_free(space_ids); diff -r 8fadb9f22d1c innobase/include/fil0fil.h --- a/innobase/include/fil0fil.h Thu Oct 09 17:29:20 2008 -0700 +++ b/innobase/include/fil0fil.h Fri Oct 17 02:50:16 2008 -0700 @@ -197,6 +197,13 @@ fil_init( /*=====*/ ulint max_n_open); /* in: max number of open files */ +/******************************************************************** + * Prints internal counters. */ + +void +fil_print( + /*=====*/ + FILE* file); /* in: output stream */ /*********************************************************************** Opens all log files and system tablespace data files. They stay open until the database server shutdown. This should be called at a server startup after the @@ -621,14 +628,26 @@ ulint segment); /* in: the number of the segment in the aio array to wait for */ /************************************************************************** +Identifies the caller of fil_flush. */ +typedef enum { + FLUSH_FROM_DIRTY_BUFFER, + FLUSH_FROM_OTHER, + FLUSH_FROM_CHECKPOINT, + FLUSH_FROM_LOG_IO_COMPLETE, + FLUSH_FROM_LOG_WRITE_UP_TO, + FLUSH_FROM_ARCHIVE, + FLUSH_FROM_NUMBER +} flush_from_type; +/************************************************************************** Flushes to disk possible writes cached by the OS. If the space does not exist or is being dropped, does not do anything. */ void fil_flush( /*======*/ - ulint space_id); /* in: file space id (this can be a group of + ulint space_id, /* in: file space id (this can be a group of log files or a tablespace of the database) */ + flush_from_type flush_type);/* in: identifies the caller */ /************************************************************************** Flushes to disk writes in file spaces of the given type possibly cached by the OS. */ @@ -636,7 +655,8 @@ void fil_flush_file_spaces( /*==================*/ - ulint purpose); /* in: FIL_TABLESPACE, FIL_LOG */ + ulint purpose, /* in: FIL_TABLESPACE, FIL_LOG */ + flush_from_type flush_type);/* in: identifies the caller */ /********************************************************************** Checks the consistency of the tablespace cache. */ diff -r 8fadb9f22d1c innobase/include/log0log.h --- a/innobase/include/log0log.h Thu Oct 09 17:29:20 2008 -0700 +++ b/innobase/include/log0log.h Fri Oct 17 02:50:16 2008 -0700 @@ -146,6 +146,22 @@ log_io_complete( /*============*/ log_group_t* group); /* in: log group */ + +/********************************************************** +Describes the caller of log_write_up_to. */ + +typedef enum { + LOG_WRITE_FROM_DIRTY_BUFFER, + LOG_WRITE_FROM_BACKGROUND_SYNC, + LOG_WRITE_FROM_BACKGROUND_ASYNC, + LOG_WRITE_FROM_INTERNAL, + LOG_WRITE_FROM_CHECKPOINT_SYNC, + LOG_WRITE_FROM_CHECKPOINT_ASYNC, + LOG_WRITE_FROM_LOG_ARCHIVE, + LOG_WRITE_FROM_COMMIT_SYNC, + LOG_WRITE_FROM_COMMIT_ASYNC, + LOG_WRITE_FROM_NUMBER +} log_sync_type; /********************************************************** This function is called, e.g., when a transaction wants to commit. It checks that the log has been written to the log file up to the last log entry written @@ -159,14 +175,21 @@ be written, ut_dulint_max if not specified */ ulint wait, /* in: LOG_NO_WAIT, LOG_WAIT_ONE_GROUP, or LOG_WAIT_ALL_GROUPS */ - ibool flush_to_disk); - /* in: TRUE if we want the written log also to be - flushed to disk */ + ibool flush_to_disk, + /* in: TRUE if we want the written log also to be flushed to disk */ + log_sync_type caller);/* in: identifies the caller */ /******************************************************************** Does a syncronous flush of the log buffer to disk. */ void log_buffer_flush_to_disk(void); +/*==========================*/ +/******************************************************************** +Flushes the log buffer. Forces it to disk depending on the value of +the configuration parameter innodb_flush_log_at_trx_commit. */ + +void +log_buffer_flush_maybe_sync(void); /*==========================*/ /******************************************************************** Advances the smallest lsn for which there are unflushed dirty blocks in the @@ -744,6 +767,12 @@ AND flushed to disk */ ulint n_pending_writes;/* number of currently pending flushes or writes */ + ulint log_sync_callers[LOG_WRITE_FROM_NUMBER]; + /* counts calls to log_write_up_to */ + ulint log_sync_syncers[LOG_WRITE_FROM_NUMBER]; + /* counts calls to log_write_up_to when log file is sync'd */ + ulint n_syncs; /* number of fsyncs done for log file */ + ulint n_checkpoints; /* number of calls to log_checkpoint */ /* NOTE on the 'flush' in names of the fields below: starting from 4.0.14, we separate the write of the log file and the actual fsync() or other method to flush it to disk. The names below shhould really diff -r 8fadb9f22d1c innobase/include/trx0sys.h --- a/innobase/include/trx0sys.h Thu Oct 09 17:29:20 2008 -0700 +++ b/innobase/include/trx0sys.h Fri Oct 17 02:50:16 2008 -0700 @@ -24,11 +24,13 @@ #include "fsp0fsp.h" #include "read0types.h" -/* In a MySQL replication slave, in crash recovery we store the master log -file name and position here. We have successfully got the updates to InnoDB +/* In a MySQL replication slave, in crash recovery we have to store the relay +log file name and position here. We have successfully got the updates to InnoDB up to this position. If .._pos is -1, it means no crash recovery was needed, -or there was no master log position info inside InnoDB. */ +or there was no relay-log position info inside InnoDB. */ +extern char trx_sys_mysql_relay_log_name[]; +extern ib_longlong trx_sys_mysql_relay_log_pos; extern char trx_sys_mysql_master_log_name[]; extern ib_longlong trx_sys_mysql_master_log_pos; @@ -271,6 +273,23 @@ ulint field, /* in: offset of the MySQL log info field in the trx sys header */ mtr_t* mtr); /* in: mtr */ + +/********************************************************************* +In a MySQL replication slave updates the latest relay log and master +log position up to which replication has proceeded. */ +void +trx_sys_update_mysql_relay_offset( +/*===============================*/ + const char* relaylog_name, /* in: relay-log file name */ + ib_longlong relaylog_pos, /* in: position in relay-log file */ + const char* masterlog_name, /* in: relay-log file name */ + ib_longlong masterlog_pos, /* in: position in relay-log file */ + ulint field, /* in: offset of the MySQL log info field in + the trx sys header */ + mtr_t* mtr, /* in: mtr */ + ibool lock_kernel_mutex); /* in: lock kernel_mutex when TRUE */ + + /********************************************************************* Prints to stderr the MySQL binlog offset info in the trx system header if the magic number shows it valid. */ @@ -289,12 +308,14 @@ byte* page); /* in: buffer containing the trx system header page, i.e., page number TRX_SYS_PAGE_NO in the tablespace */ #endif /* UNIV_HOTBACKUP */ + /********************************************************************* -Prints to stderr the MySQL master log offset info in the trx system header if -the magic number shows it valid. */ +Prints to stderr the MySQL relay-log/master-log offset info in the trx system +header if the magic number shows it valid. */ void -trx_sys_print_mysql_master_log_pos(void); +trx_sys_print_mysql_relay_log_pos(ibool print_msg); + /*====================================*/ /* The automatically created system rollback segment has this id */ @@ -335,7 +356,55 @@ /* The offset of the MySQL replication info in the trx system header; this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */ -#define TRX_SYS_MYSQL_MASTER_LOG_INFO (UNIV_PAGE_SIZE - 2000) +#define TRX_SYS_MYSQL_RELAY_LOG_INFO (UNIV_PAGE_SIZE - 2000) + +#define TRX_SYS_MYSQL_RELAY_INFO (UNIV_PAGE_SIZE - 2000) + +/* We change the layout of writing relay-log information a little: + * offset 0: magic number + * offset 4: 0xfffffffe magic number indicating the format that + * contains both relay-log and master-log information + * (we need the four bytes to indicate the difference to the + * old innodb relay-log only format because we want to + * keep the first magic number unchanged). + * offset 8: relay-log position high 4 byte + * offset 12: relay-log position low 4 byte + * offset 16: master-log position high 4 byte + * offset 20: master-log position low 4 byte + * offset 24: relay-log filename + * offset 274: master-log filename + * Each filename's length is limited to 250 bytes, which should be more than + * enough for most applications. We will fail during MySQL replication if + * the filename is too long so that users can adjust. + */ +#define TRX_SYS_MYSQL_RELAYLOG_MAGIC_N_FLD 0 +#define TRX_SYS_MYSQL_RELAYMASTER_MAGIC_NUM 0xfffffffe +#define TRX_SYS_MYSQL_RELAYMASTER_MAGIC_OFF 4 /* the magic number indicating + both relay-log and master-log + information */ +#define TRX_SYS_MYSQL_RELAYLOG_POS_HIGH 8 /* high 4 bytes of the offset + within relay-log file */ +#define TRX_SYS_MYSQL_RELAYLOG_POS_LOW 12 /* low 4 bytes of the offset + within relay-log file */ +#define TRX_SYS_MYSQL_MASTERLOG_POS_HIGH 16 /* high 4 bytes of the offset + within master-log file */ +#define TRX_SYS_MYSQL_MASTERLOG_POS_LOW 20 /* low 4 bytes of the offset + within relay-log file */ +#define TRX_SYS_MYSQL_RELAYLOG_NAME_OFF 24 /* relay-log filename */ +#define TRX_SYS_MYSQL_MASTERLOG_NAME_OFF 274 /* master-log filename */ + +#define TRX_SYS_MYSQL_RELAY_NAME_LEN 250 +/* All relay-log related information should end at offset 520 */ + + +#define TRX_SYS_MYSQL_LOG_NAME_LEN 512 + +#define TRX_SYS_MYSQL_LOG_OFFSET_HIGH 4 /* high 4 bytes of the offset + within that file */ +#define TRX_SYS_MYSQL_LOG_OFFSET_LOW 8 /* low 4 bytes of the offset + within that file */ +#define TRX_SYS_MYSQL_LOG_NAME 12 /* MySQL log file name */ + /* The offset of the MySQL binlog offset info in the trx system header */ #define TRX_SYS_MYSQL_LOG_INFO (UNIV_PAGE_SIZE - 1000) diff -r 8fadb9f22d1c innobase/include/trx0trx.h --- a/innobase/include/trx0trx.h Thu Oct 09 17:29:20 2008 -0700 +++ b/innobase/include/trx0trx.h Fri Oct 17 02:50:16 2008 -0700 @@ -184,7 +184,8 @@ void trx_commit_off_kernel( /*==================*/ - trx_t* trx); /* in: transaction */ + trx_t* trx, /* in: transaction */ + ibool for_commit); /* in: false when for a rollback */ /******************************************************************** Cleans up a transaction at database startup. The cleanup is needed if the transaction already got to the middle of a commit when the database @@ -668,6 +669,27 @@ /*------------------------------*/ char detailed_error[256]; /* detailed error message for last error, or empty. */ + const char* mysql_relay_log_file_name; + /* if the database server is a MySQL + replication slave, we have here the + relay-log name up to which + replication has processed; otherwise + this is a pointer to a null + character */ + ib_longlong mysql_relay_log_pos; + /* if the database server is a MySQL + replication slave, this is the + position in the relay-log up to which + replication has processed */ + + ibool always_enter_innodb; + /* thread always enter innodb without + considering ticket limit; this is only + used for replication sql thread. */ + + ibool clear_replication_status; + /* we need to clear the replication + status stored in transaction log */ }; #define TRX_MAX_N_THREADS 32 /* maximum number of concurrent diff -r 8fadb9f22d1c innobase/log/log0log.c --- a/innobase/log/log0log.c Thu Oct 09 17:29:20 2008 -0700 +++ b/innobase/log/log0log.c Fri Oct 17 02:50:16 2008 -0700 @@ -782,6 +782,15 @@ log_sys->written_to_all_lsn = log_sys->lsn; log_sys->n_pending_writes = 0; + { + int x; + for (x = 0; x < LOG_WRITE_FROM_NUMBER; ++x) { + log_sys->log_sync_callers[x] = 0; + log_sys->log_sync_syncers[x] = 0; + } + } + log_sys->n_syncs = 0; + log_sys->n_checkpoints = 0; log_sys->no_flush_event = os_event_create(NULL); @@ -1066,7 +1075,7 @@ if (srv_unix_file_flush_method != SRV_UNIX_O_DSYNC && srv_unix_file_flush_method != SRV_UNIX_NOSYNC) { - fil_flush(group->space_id); + fil_flush(group->space_id, FLUSH_FROM_LOG_IO_COMPLETE); } #ifdef UNIV_DEBUG @@ -1088,7 +1097,7 @@ && srv_unix_file_flush_method != SRV_UNIX_NOSYNC && srv_flush_log_at_trx_commit != 2) { - fil_flush(group->space_id); + fil_flush(group->space_id, FLUSH_FROM_LOG_IO_COMPLETE); } mutex_enter(&(log_sys->mutex)); @@ -1303,9 +1312,10 @@ be written, ut_dulint_max if not specified */ ulint wait, /* in: LOG_NO_WAIT, LOG_WAIT_ONE_GROUP, or LOG_WAIT_ALL_GROUPS */ - ibool flush_to_disk) + ibool flush_to_disk, /* in: TRUE if we want the written log also to be flushed to disk */ + log_sync_type caller) /* in: identifies caller */ { log_group_t* group; ulint start_offset; @@ -1315,6 +1325,7 @@ ulint loop_count; ulint unlock; + log_sys->log_sync_callers[caller]++; if (recv_no_ibuf_operations) { /* Recovery is running and no operations on the log files are allowed yet (the variable name .._no_ibuf_.. is misleading) */ @@ -1465,13 +1476,17 @@ so we have also flushed to disk what we have written */ log_sys->flushed_to_disk_lsn = log_sys->write_lsn; + log_sys->n_syncs++; + log_sys->log_sync_syncers[caller]++; } else if (flush_to_disk) { group = UT_LIST_GET_FIRST(log_sys->log_groups); - fil_flush(group->space_id); + fil_flush(group->space_id, FLUSH_FROM_LOG_WRITE_UP_TO); log_sys->flushed_to_disk_lsn = log_sys->write_lsn; + log_sys->n_syncs++; + log_sys->log_sync_syncers[caller]++; } mutex_enter(&(log_sys->mutex)); @@ -1520,9 +1535,33 @@ mutex_exit(&(log_sys->mutex)); - log_write_up_to(lsn, LOG_WAIT_ALL_GROUPS, TRUE); + log_write_up_to(lsn, LOG_WAIT_ALL_GROUPS, TRUE, + LOG_WRITE_FROM_BACKGROUND_SYNC); } +/******************************************************************** +Flush the log buffer. Force it to disk depending on the value of +innodb_flush_log_at_trx_commit. */ + +void +log_buffer_flush_maybe_sync(void) +/*==========================*/ +{ + dulint lsn; + + mutex_enter(&(log_sys->mutex)); + + lsn = log_sys->lsn; + + mutex_exit(&(log_sys->mutex)); + + /* Force log buffer to disk when innodb_flush_log_at_trx_commit = 1. */ + log_write_up_to(lsn, LOG_WAIT_ALL_GROUPS, + srv_flush_log_at_trx_commit == 1 ? TRUE : FALSE, + srv_flush_log_at_trx_commit == 1 ? + LOG_WRITE_FROM_BACKGROUND_SYNC : + LOG_WRITE_FROM_BACKGROUND_ASYNC); +} /******************************************************************** Tries to establish a big enough margin of free space in the log buffer, such that a new log entry can be catenated without an immediate need for a flush. */ @@ -1551,7 +1590,7 @@ mutex_exit(&(log->mutex)); if (do_flush) { - log_write_up_to(lsn, LOG_NO_WAIT, FALSE); + log_write_up_to(lsn, LOG_NO_WAIT, FALSE, LOG_WRITE_FROM_INTERNAL); } } @@ -1921,11 +1960,11 @@ } if (srv_unix_file_flush_method != SRV_UNIX_NOSYNC) { - fil_flush_file_spaces(FIL_TABLESPACE); + fil_flush_file_spaces(FIL_TABLESPACE, FLUSH_FROM_CHECKPOINT); } mutex_enter(&(log_sys->mutex)); - + log_sys->n_checkpoints++; oldest_lsn = log_buf_pool_get_oldest_modification(); mutex_exit(&(log_sys->mutex)); @@ -1938,7 +1977,8 @@ write-ahead-logging algorithm ensures that the log has been flushed up to oldest_lsn. */ - log_write_up_to(oldest_lsn, LOG_WAIT_ALL_GROUPS, TRUE); + log_write_up_to(oldest_lsn, LOG_WAIT_ALL_GROUPS, TRUE, + LOG_WRITE_FROM_CHECKPOINT_SYNC); mutex_enter(&(log_sys->mutex)); @@ -2566,7 +2606,7 @@ mutex_exit(&(log_sys->mutex)); - fil_flush(group->archive_space_id); + fil_flush(group->archive_space_id, FLUSH_FROM_ARCHIVE); mutex_enter(&(log_sys->mutex)); @@ -2647,7 +2687,8 @@ mutex_exit(&(log_sys->mutex)); - log_write_up_to(limit_lsn, LOG_WAIT_ALL_GROUPS, TRUE); + log_write_up_to(limit_lsn, LOG_WAIT_ALL_GROUPS, TRUE, + LOG_WRITE_FROM_LOG_ARCHIVE); calc_new_limit = FALSE; @@ -3171,8 +3212,8 @@ } mutex_exit(&kernel_mutex); - fil_flush_file_spaces(FIL_TABLESPACE); - fil_flush_file_spaces(FIL_LOG); + fil_flush_file_spaces(FIL_TABLESPACE, FLUSH_FROM_OTHER); + fil_flush_file_spaces(FIL_LOG, FLUSH_FROM_OTHER); /* The call fil_write_flushed_lsn_to_data_files() will pass the buffer pool: therefore it is essential that the buffer pool has been @@ -3219,7 +3260,7 @@ fil_write_flushed_lsn_to_data_files(lsn, arch_log_no); - fil_flush_file_spaces(FIL_TABLESPACE); + fil_flush_file_spaces(FIL_TABLESPACE, FLUSH_FROM_OTHER); fil_close_all_files(); @@ -3332,15 +3373,45 @@ time_elapsed = 0.001 + difftime(current_time, log_sys->last_printout_time); fprintf(file, - "%lu pending log writes, %lu pending chkp writes\n" - "%lu log i/o's done, %.2f log i/o's/second\n", - (ulong) log_sys->n_pending_writes, - (ulong) log_sys->n_pending_checkpoint_writes, - (ulong) log_sys->n_log_ios, - ((log_sys->n_log_ios - log_sys->n_log_ios_old) / time_elapsed)); + "%lu pending log writes, %lu pending chkp writes\n" + "%lu log i/o's done, %.2f log i/o's/second, %lu syncs, %lu checkpoints\n", + (ulong) log_sys->n_pending_writes, + (ulong) log_sys->n_pending_checkpoint_writes, + (ulong) log_sys->n_log_ios, + (log_sys->n_log_ios - log_sys->n_log_ios_old) / time_elapsed, + log_sys->n_syncs, + log_sys->n_checkpoints); log_sys->n_log_ios_old = log_sys->n_log_ios; log_sys->last_printout_time = current_time; + + fprintf(file, + "log sync callers: %lu buffer pool, background %lu sync and %lu async, " + "%lu internal, checkpoint %lu sync and %lu async, %lu archive, " + "commit %lu sync and %lu async\n", + log_sys->log_sync_callers[LOG_WRITE_FROM_DIRTY_BUFFER], + log_sys->log_sync_callers[LOG_WRITE_FROM_BACKGROUND_SYNC], + log_sys->log_sync_callers[LOG_WRITE_FROM_BACKGROUND_ASYNC], + log_sys->log_sync_callers[LOG_WRITE_FROM_INTERNAL], + log_sys->log_sync_callers[LOG_WRITE_FROM_CHECKPOINT_SYNC], + log_sys->log_sync_callers[LOG_WRITE_FROM_CHECKPOINT_ASYNC], + log_sys->log_sync_callers[LOG_WRITE_FROM_LOG_ARCHIVE], + log_sys->log_sync_callers[LOG_WRITE_FROM_COMMIT_SYNC], + log_sys->log_sync_callers[LOG_WRITE_FROM_COMMIT_ASYNC]); + + fprintf(file, + "log sync syncers: %lu buffer pool, background %lu sync and %lu async, " + "%lu internal, checkpoint %lu sync and %lu async, %lu archive, " + "commit %lu sync and %lu async\n", + log_sys->log_sync_syncers[LOG_WRITE_FROM_DIRTY_BUFFER], + log_sys->log_sync_syncers[LOG_WRITE_FROM_BACKGROUND_SYNC], + log_sys->log_sync_syncers[LOG_WRITE_FROM_BACKGROUND_ASYNC], + log_sys->log_sync_syncers[LOG_WRITE_FROM_INTERNAL], + log_sys->log_sync_syncers[LOG_WRITE_FROM_CHECKPOINT_SYNC], + log_sys->log_sync_syncers[LOG_WRITE_FROM_CHECKPOINT_ASYNC], + log_sys->log_sync_syncers[LOG_WRITE_FROM_LOG_ARCHIVE], + log_sys->log_sync_syncers[LOG_WRITE_FROM_COMMIT_SYNC], + log_sys->log_sync_syncers[LOG_WRITE_FROM_COMMIT_ASYNC]); mutex_exit(&(log_sys->mutex)); } diff -r 8fadb9f22d1c innobase/log/log0recv.c --- a/innobase/log/log0recv.c Thu Oct 09 17:29:20 2008 -0700 +++ b/innobase/log/log0recv.c Fri Oct 17 02:50:16 2008 -0700 @@ -2923,6 +2923,8 @@ return(DB_SUCCESS); } +extern my_bool rpl_transaction_enabled; + /************************************************************ Completes recovery from a checkpoint. */ @@ -2947,8 +2949,17 @@ } #endif /* UNIV_DEBUG */ + if (rpl_transaction_enabled || recv_needed_recovery) { + + trx_sys_print_mysql_relay_log_pos(TRUE); + if (recv_needed_recovery) { + fprintf(stderr, + " InnoDB: recv_recovery_from_checkpoint_finish()" + " - recovery is needed.\n"); + } + } + if (recv_needed_recovery) { - trx_sys_print_mysql_master_log_pos(); trx_sys_print_mysql_binlog_offset(); } diff -r 8fadb9f22d1c innobase/trx/trx0roll.c --- a/innobase/trx/trx0roll.c Thu Oct 09 17:29:20 2008 -0700 +++ b/innobase/trx/trx0roll.c Fri Oct 17 02:50:16 2008 -0700 @@ -1262,7 +1262,7 @@ } #endif /* UNIV_DEBUG */ - trx_commit_off_kernel(trx); + trx_commit_off_kernel(trx, FALSE); /* Remove all TRX_SIG_TOTAL_ROLLBACK signals from the signal queue and send reply messages to them */ diff -r 8fadb9f22d1c innobase/trx/trx0sys.c --- a/innobase/trx/trx0sys.c Thu Oct 09 17:29:20 2008 -0700 +++ b/innobase/trx/trx0sys.c Fri Oct 17 02:50:16 2008 -0700 @@ -37,12 +37,15 @@ ibool trx_sys_multiple_tablespace_format = FALSE; -/* In a MySQL replication slave, in crash recovery we store the master log -file name and position here. We have successfully got the updates to InnoDB + +/* In a MySQL replication slave, in crash recovery we have to store the relay +log file name and position here. We have successfully got the updates to InnoDB up to this position. If .._pos is -1, it means no crash recovery was needed, -or there was no master log position info inside InnoDB. */ +or there was no relay-log position info inside InnoDB. */ -char trx_sys_mysql_master_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN]; +char trx_sys_mysql_relay_log_name[TRX_SYS_MYSQL_RELAY_NAME_LEN]; +char trx_sys_mysql_master_log_name[TRX_SYS_MYSQL_RELAY_NAME_LEN]; +ib_longlong trx_sys_mysql_relay_log_pos = -1; ib_longlong trx_sys_mysql_master_log_pos = -1; /* If this MySQL server uses binary logging, after InnoDB has been inited @@ -511,7 +514,7 @@ page += UNIV_PAGE_SIZE; } - fil_flush_file_spaces(FIL_TABLESPACE); + fil_flush_file_spaces(FIL_TABLESPACE, FLUSH_FROM_OTHER); leave_func: ut_free(unaligned_read_buf); @@ -630,6 +633,93 @@ } /********************************************************************* +In a MySQL replication slave updates the latest relay log and master +log position up to which replication has proceeded. */ + +void +trx_sys_update_mysql_relay_offset( +/*===============================*/ + const char* relaylog_name, /* in: relay-log file name */ + ib_longlong relaylog_pos, /* in: position in relay-log file */ + const char* masterlog_name, /* in: relay-log file name */ + ib_longlong masterlog_pos, /* in: position in relay-log file */ + ulint field, /* in: offset of the MySQL log info field in + the trx sys header */ + mtr_t* mtr, /* in: mtr */ + ibool lock_kernel_mutex) /* in: lock mutex when TRUE */ +{ + trx_sysf_t* sys_header; + + if (ut_strlen(relaylog_name) >= TRX_SYS_MYSQL_RELAY_NAME_LEN || + ut_strlen(masterlog_name) >= TRX_SYS_MYSQL_RELAY_NAME_LEN) { + /* Each filename's length is limited to 250 bytes, which should be more + * than enough for most applications. We will fail during MySQL replication + * if the filename is too long so that users can adjust. + */ + fprintf(stderr, + " InnoDB: trx_sys_update_mysql_relay_offset() filename is too long " + "- relay(%s), master(%s)", relaylog_name, masterlog_name); + return; + } + + if (lock_kernel_mutex) + mutex_enter(&kernel_mutex); + + sys_header = trx_sysf_get(mtr); + if (mach_read_from_4(sys_header + field + TRX_SYS_MYSQL_RELAYLOG_MAGIC_N_FLD) + != TRX_SYS_MYSQL_LOG_MAGIC_N) { + mlog_write_ulint(sys_header + field + TRX_SYS_MYSQL_RELAYLOG_MAGIC_N_FLD, + TRX_SYS_MYSQL_LOG_MAGIC_N, MLOG_4BYTES, mtr); + } + + if (mach_read_from_4(sys_header + field + TRX_SYS_MYSQL_RELAYMASTER_MAGIC_OFF) + != TRX_SYS_MYSQL_RELAYMASTER_MAGIC_NUM) { + mlog_write_ulint(sys_header + field + TRX_SYS_MYSQL_RELAYMASTER_MAGIC_OFF, + TRX_SYS_MYSQL_RELAYMASTER_MAGIC_NUM, MLOG_4BYTES, mtr); + } + + /* write relay-log related information */ + if (0 != strcmp((char*) (sys_header + field + + TRX_SYS_MYSQL_RELAYLOG_NAME_OFF), relaylog_name)) { + mlog_write_string(sys_header + field + TRX_SYS_MYSQL_RELAYLOG_NAME_OFF, + (byte*) relaylog_name, 1 + ut_strlen(relaylog_name), + mtr); + } + if (mach_read_from_4(sys_header + field + + TRX_SYS_MYSQL_RELAYLOG_POS_HIGH) > 0 + || (relaylog_pos >> 32) > 0) { + mlog_write_ulint(sys_header + field + + TRX_SYS_MYSQL_RELAYLOG_POS_HIGH, + (ulint)(relaylog_pos >> 32), + MLOG_4BYTES, mtr); + } + mlog_write_ulint(sys_header + field + TRX_SYS_MYSQL_RELAYLOG_POS_LOW, + (ulint)(relaylog_pos & 0xFFFFFFFFUL), MLOG_4BYTES, mtr); + + /* write master-log related information */ + if (0 != strcmp((char*) (sys_header + field + + TRX_SYS_MYSQL_MASTERLOG_NAME_OFF), + masterlog_name)) { + mlog_write_string(sys_header + field + TRX_SYS_MYSQL_MASTERLOG_NAME_OFF, + (byte*) masterlog_name, 1 + ut_strlen(masterlog_name), + mtr); + } + if (mach_read_from_4(sys_header + field + + TRX_SYS_MYSQL_MASTERLOG_POS_HIGH) > 0 + || (masterlog_pos >> 32) > 0) { + mlog_write_ulint(sys_header + field + + TRX_SYS_MYSQL_MASTERLOG_POS_HIGH, + (ulint)(masterlog_pos >> 32), + MLOG_4BYTES, mtr); + } + mlog_write_ulint(sys_header + field + TRX_SYS_MYSQL_MASTERLOG_POS_LOW, + (ulint)(masterlog_pos & 0xFFFFFFFFUL), MLOG_4BYTES, mtr); + + if (lock_kernel_mutex) + mutex_exit(&kernel_mutex); +} + +/********************************************************************* Prints to stderr the MySQL binlog info in the system header if the magic number shows it valid. */ @@ -703,55 +793,80 @@ } /********************************************************************* -Prints to stderr the MySQL master log offset info in the trx system header if -the magic number shows it valid. */ +Prints to stderr the MySQL relay-log/master-log offset info in the trx system +header if the magic number shows it valid. */ void -trx_sys_print_mysql_master_log_pos(void) +trx_sys_print_mysql_relay_log_pos(ibool print_msg) /*====================================*/ { - trx_sysf_t* sys_header; - mtr_t mtr; - - mtr_start(&mtr); + trx_sysf_t* sys_header; + mtr_t mtr; - sys_header = trx_sysf_get(&mtr); + mtr_start(&mtr); - if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO - + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD) - != TRX_SYS_MYSQL_LOG_MAGIC_N) { + fprintf(stderr, "trx_sys_print_mysql_relay_log_pos \n"); - mtr_commit(&mtr); + sys_header = trx_sysf_get(&mtr); + ulint magic_num = mach_read_from_4(sys_header + TRX_SYS_MYSQL_RELAY_INFO + + TRX_SYS_MYSQL_RELAYLOG_MAGIC_N_FLD); + if (magic_num != TRX_SYS_MYSQL_LOG_MAGIC_N) { + mtr_commit(&mtr); + fprintf(stderr, + " InnoDB: Incorrect magic number(%d) for relay-log information\n", + magic_num); + return; + } - return; - } + magic_num = mach_read_from_4(sys_header + TRX_SYS_MYSQL_RELAY_INFO + + TRX_SYS_MYSQL_RELAYMASTER_MAGIC_OFF); + if (magic_num != TRX_SYS_MYSQL_RELAYMASTER_MAGIC_NUM) { + mtr_commit(&mtr); + fprintf(stderr, + " InnoDB: Old magic number(%d) for relay-log information\n", + magic_num); + return; + } - fprintf(stderr, -"InnoDB: In a MySQL replication slave the last master binlog file\n" -"InnoDB: position %lu %lu, file name %s\n", - (ulong) mach_read_from_4(sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO - + TRX_SYS_MYSQL_LOG_OFFSET_HIGH), - (ulong) mach_read_from_4(sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO - + TRX_SYS_MYSQL_LOG_OFFSET_LOW), - sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO - + TRX_SYS_MYSQL_LOG_NAME); - /* Copy the master log position info to global variables we can - use in ha_innobase.cc to initialize glob_mi to right values */ + /* We need the relay-log related information in ha_innobase.cc to initialize + * glob_mi to right values. + */ - ut_memcpy(trx_sys_mysql_master_log_name, - sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO - + TRX_SYS_MYSQL_LOG_NAME, - TRX_SYS_MYSQL_LOG_NAME_LEN); + /* Copy the relay-log log position info to global variables */ + ut_memcpy(trx_sys_mysql_relay_log_name, + sys_header + TRX_SYS_MYSQL_RELAY_INFO + + TRX_SYS_MYSQL_RELAYLOG_NAME_OFF, + TRX_SYS_MYSQL_RELAY_NAME_LEN); + trx_sys_mysql_relay_log_pos = + (((ib_longlong)mach_read_from_4( + sys_header + TRX_SYS_MYSQL_RELAY_INFO + + TRX_SYS_MYSQL_RELAYLOG_POS_HIGH)) << 32) + + ((ib_longlong)mach_read_from_4(sys_header + TRX_SYS_MYSQL_RELAY_INFO + + TRX_SYS_MYSQL_RELAYLOG_POS_LOW)); - trx_sys_mysql_master_log_pos = - (((ib_longlong)mach_read_from_4( - sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO - + TRX_SYS_MYSQL_LOG_OFFSET_HIGH)) - << 32) - + (ib_longlong) - mach_read_from_4(sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO - + TRX_SYS_MYSQL_LOG_OFFSET_LOW); - mtr_commit(&mtr); + /* Copy the master-log log position info to global variables */ + ut_memcpy(trx_sys_mysql_master_log_name, + sys_header + TRX_SYS_MYSQL_RELAY_INFO + + TRX_SYS_MYSQL_MASTERLOG_NAME_OFF, + TRX_SYS_MYSQL_RELAY_NAME_LEN); + trx_sys_mysql_master_log_pos = + (((ib_longlong)mach_read_from_4( + sys_header + TRX_SYS_MYSQL_RELAY_INFO + + TRX_SYS_MYSQL_MASTERLOG_POS_HIGH)) << 32) + + ((ib_longlong)mach_read_from_4(sys_header + TRX_SYS_MYSQL_RELAY_INFO + + TRX_SYS_MYSQL_MASTERLOG_POS_LOW)); + + mtr_commit(&mtr); + + if (print_msg) { + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: In a MySQL replication slave the last relay-log file\n" +" InnoDB: relay-log - filename %s, position (%lld)\n" +" InnoDB: master-log - filename %s, position (%lld)\n", + trx_sys_mysql_relay_log_name, trx_sys_mysql_relay_log_pos, + trx_sys_mysql_master_log_name, trx_sys_mysql_master_log_pos); + } } /******************************************************************** @@ -836,6 +951,58 @@ mtr); ut_a(slot_no == TRX_SYS_SYSTEM_RSEG_ID); ut_a(page_no != FIL_NULL); + + /* Initialize old-style master offset. This feature is deprecated. */ + mlog_write_ulint(sys_header + TRX_SYS_MYSQL_LOG_INFO + + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD, + TRX_SYS_MYSQL_LOG_MAGIC_N, + MLOG_4BYTES, mtr); + + mlog_write_string(sys_header + TRX_SYS_MYSQL_LOG_INFO + + TRX_SYS_MYSQL_LOG_NAME, + "", 1 + ut_strlen(""), mtr); + + mlog_write_ulint(sys_header + TRX_SYS_MYSQL_LOG_INFO + + TRX_SYS_MYSQL_LOG_OFFSET_HIGH, + 0, MLOG_4BYTES, mtr); + + mlog_write_ulint(sys_header + TRX_SYS_MYSQL_LOG_INFO + + TRX_SYS_MYSQL_LOG_OFFSET_LOW, + 0, MLOG_4BYTES, mtr); + + /* Initialize new-style master and relay offsets updated by the + * replication SQL slave thread. */ + mlog_write_ulint(sys_header + TRX_SYS_MYSQL_RELAY_INFO + + TRX_SYS_MYSQL_RELAYLOG_MAGIC_N_FLD, + TRX_SYS_MYSQL_LOG_MAGIC_N, MLOG_4BYTES, mtr); + + mlog_write_ulint(sys_header + TRX_SYS_MYSQL_RELAY_INFO + + TRX_SYS_MYSQL_RELAYMASTER_MAGIC_OFF, + TRX_SYS_MYSQL_RELAYMASTER_MAGIC_NUM, MLOG_4BYTES, mtr); + + mlog_write_string(sys_header + TRX_SYS_MYSQL_RELAY_INFO + + TRX_SYS_MYSQL_RELAYLOG_NAME_OFF, + (byte*) "", 1 + ut_strlen(""), mtr); + + mlog_write_ulint(sys_header + TRX_SYS_MYSQL_RELAY_INFO + + TRX_SYS_MYSQL_RELAYLOG_POS_HIGH, + 0, MLOG_4BYTES, mtr); + + mlog_write_ulint(sys_header + TRX_SYS_MYSQL_RELAY_INFO + + TRX_SYS_MYSQL_RELAYLOG_POS_LOW, + 0, MLOG_4BYTES, mtr); + + mlog_write_string(sys_header + TRX_SYS_MYSQL_RELAY_INFO + + TRX_SYS_MYSQL_MASTERLOG_NAME_OFF, + (byte*) "", 1 + ut_strlen(""), mtr); + + mlog_write_ulint(sys_header + TRX_SYS_MYSQL_RELAY_INFO + + TRX_SYS_MYSQL_MASTERLOG_POS_HIGH, + 0, MLOG_4BYTES, mtr); + + mlog_write_ulint(sys_header + TRX_SYS_MYSQL_RELAY_INFO + + TRX_SYS_MYSQL_MASTERLOG_POS_LOW, + 0, MLOG_4BYTES, mtr); mutex_exit(&kernel_mutex); } diff -r 8fadb9f22d1c innobase/trx/trx0trx.c --- a/innobase/trx/trx0trx.c Thu Oct 09 17:29:20 2008 -0700 +++ b/innobase/trx/trx0trx.c Fri Oct 17 02:50:16 2008 -0700 @@ -140,6 +140,8 @@ trx->mysql_log_offset = 0; trx->mysql_master_log_file_name = ""; trx->mysql_master_log_pos = 0; + trx->mysql_relay_log_file_name = ""; + trx->mysql_relay_log_pos = 0; trx->repl_wait_binlog_name = NULL; trx->repl_wait_binlog_pos = 0; @@ -196,6 +198,9 @@ trx->xid.formatID = -1; trx_reset_new_rec_lock_info(trx); + + trx->always_enter_innodb = FALSE; + trx->clear_replication_status = FALSE; return(trx); } @@ -354,7 +359,7 @@ trx->global_read_view = NULL; ut_a(trx->read_view == NULL); - + mem_free(trx); } @@ -727,7 +732,8 @@ void trx_commit_off_kernel( /*==================*/ - trx_t* trx) /* in: transaction */ + trx_t* trx, /* in: transaction */ + ibool for_commit) /* in: for rollback when FALSE */ { page_t* update_hdr_page; dulint lsn; @@ -803,14 +809,22 @@ trx->mysql_log_file_name = NULL; } - if (trx->mysql_master_log_file_name[0] != '\0') { - /* This database server is a MySQL replication slave */ - trx_sys_update_mysql_binlog_offset( - trx->mysql_master_log_file_name, - trx->mysql_master_log_pos, - TRX_SYS_MYSQL_MASTER_LOG_INFO, &mtr); + if (for_commit) { + if (trx->clear_replication_status) { + /* Clear the replication status. */ + trx_sys_update_mysql_relay_offset( + "", -1, "", -1, TRX_SYS_MYSQL_RELAY_INFO, &mtr, FALSE); + } else if (trx->mysql_relay_log_file_name[0] != '\0') { + /* This database server is a MySQL replication slave */ + trx_sys_update_mysql_relay_offset( + trx->mysql_relay_log_file_name, + trx->mysql_relay_log_pos, + trx->mysql_master_log_file_name, + trx->mysql_master_log_pos, + TRX_SYS_MYSQL_RELAY_INFO, &mtr, FALSE); + } } - + /* The following call commits the mini-transaction, making the whole transaction committed in the file-based world, at this log sequence number. The transaction becomes 'durable' when @@ -916,19 +930,21 @@ if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) { /* Write the log but do not flush it to disk */ - log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, - FALSE); + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE, + LOG_WRITE_FROM_COMMIT_ASYNC); } else { /* Write the log to the log files AND flush them to disk */ - log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE); + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE, + LOG_WRITE_FROM_COMMIT_SYNC); } } else if (srv_flush_log_at_trx_commit == 2) { /* Write the log but do not flush it to disk */ - log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE); + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE, + LOG_WRITE_FROM_COMMIT_ASYNC); } else { ut_error; } @@ -1029,7 +1045,7 @@ trx->que_state = TRX_QUE_COMMITTING; - trx_commit_off_kernel(trx); + trx_commit_off_kernel(trx, TRUE); ut_ad(UT_LIST_GET_LEN(trx->wait_thrs) == 0); @@ -1624,7 +1640,7 @@ mutex_enter(&kernel_mutex); - trx_commit_off_kernel(trx); + trx_commit_off_kernel(trx, TRUE); mutex_exit(&kernel_mutex); @@ -1657,18 +1673,21 @@ if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) { /* Write the log but do not flush it to disk */ - log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE); + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE, + LOG_WRITE_FROM_COMMIT_ASYNC); } else { /* Write the log to the log files AND flush them to disk */ - log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE); + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE, + LOG_WRITE_FROM_COMMIT_SYNC); } } else if (srv_flush_log_at_trx_commit == 2) { /* Write the log but do not flush it to disk */ - log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE); + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE, + LOG_WRITE_FROM_COMMIT_ASYNC); } else { ut_error; } @@ -1904,19 +1923,21 @@ if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) { /* Write the log but do not flush it to disk */ - log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, - FALSE); + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE, + LOG_WRITE_FROM_COMMIT_ASYNC); } else { /* Write the log to the log files AND flush them to disk */ - log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE); + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE, + LOG_WRITE_FROM_COMMIT_SYNC); } } else if (srv_flush_log_at_trx_commit == 2) { /* Write the log but do not flush it to disk */ - log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE); + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE, + LOG_WRITE_FROM_COMMIT_ASYNC); } else { ut_error; } diff -r 8fadb9f22d1c mysql-test/mysql-test-run.pl --- a/mysql-test/mysql-test-run.pl Thu Oct 09 17:29:20 2008 -0700 +++ b/mysql-test/mysql-test-run.pl Fri Oct 17 02:50:16 2008 -0700 @@ -280,6 +280,7 @@ our $opt_wait_for_slave; our $opt_warnings; +our $opt_slave_innodb= 0; our $opt_udiff; @@ -624,6 +625,7 @@ 'testcase-timeout=i' => \$opt_testcase_timeout, 'suite-timeout=i' => \$opt_suite_timeout, 'warnings|log-warnings' => \$opt_warnings, + 'slave-innodb' => \$opt_slave_innodb, 'help|h' => \$opt_usage, ) or usage("Can't read options"); @@ -970,6 +972,14 @@ { $ENV{'BIG_TEST'}= 1; } + + # -------------------------------------------------------------------------- + # Big test flags + # -------------------------------------------------------------------------- + if ( $opt_big_test ) + { + $ENV{'BIG_TEST'}= 1; + } # -------------------------------------------------------------------------- # Gcov flag @@ -2297,6 +2307,8 @@ if ( ! $glob_win32 ) { symlink("$glob_mysql_test_dir/std_data", "$opt_vardir/std_data_ln"); + my @a = ("chmod", "-R", "o+r", "$glob_mysql_test_dir/std_data"); + system(@a) == 0 or die "system @ failed: $?" } else { @@ -3824,7 +3836,8 @@ unless $mysqld->{'type'} eq 'slave'; mtr_add_arg($args, "%s--init-rpl-role=slave", $prefix); - if (! ( $opt_skip_slave_binlog || $skip_binlog )) + + if (! $opt_skip_slave_binlog) { mtr_add_arg($args, "%s--log-bin=%s/log/slave%s-bin", $prefix, $opt_vardir, $sidx); # FIXME use own dir for binlogs @@ -3839,7 +3852,15 @@ mtr_add_arg($args, "%s--report-port=%d", $prefix, $mysqld->{'port'}); mtr_add_arg($args, "%s--report-user=root", $prefix); - mtr_add_arg($args, "%s--skip-innodb", $prefix); + if ( ! $opt_slave_innodb ) + { + mtr_add_arg($args, "%s--skip-innodb", $prefix); + } + else + { + mtr_add_arg($args, "%s--default-table-type=innodb", $prefix); + mtr_add_arg($args, "%s--transaction-isolation=READ-COMMITTED", $prefix); + } mtr_add_arg($args, "%s--skip-slave-start", $prefix); # Directory where slaves find the dumps generated by "load data" diff -r 8fadb9f22d1c mysql-test/r/rpl_innodb_clear_status.result --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mysql-test/r/rpl_innodb_clear_status.result Fri Oct 17 02:50:16 2008 -0700 @@ -0,0 +1,37 @@ +create database mysqltest; +delete from mysql.user where user like 'mysqltest\_%'; +delete from mysql.db where user like 'mysqltest\_%'; +delete from mysql.tables_priv where user like 'mysqltest\_%'; +delete from mysql.columns_priv where user like 'mysqltest\_%'; +flush privileges; +grant all on mysqltest.t1 to mysqltest_1@localhost; +flush user_resources; +show variables like "innodb_clear_replication_status"; +Variable_name Value +innodb_clear_replication_status OFF +SET innodb_clear_replication_status = 1; +Warnings: +Error 1227 Access denied; you need the SUPER privilege for this operation +show variables like "innodb_clear_replication_status"; +Variable_name Value +innodb_clear_replication_status OFF +drop table if exists t1; +show variables like "innodb_clear_replication_status"; +Variable_name Value +innodb_clear_replication_status OFF +SET innodb_clear_replication_status = 1; +show variables like "innodb_clear_replication_status"; +Variable_name Value +innodb_clear_replication_status ON +create table t1 (a int) Engine = InnoDB; +SET innodb_clear_replication_status = 0; +show variables like "innodb_clear_replication_status"; +Variable_name Value +innodb_clear_replication_status OFF +drop table t1; +delete from mysql.user where user like 'mysqltest\_%'; +delete from mysql.db where user like 'mysqltest\_%'; +delete from mysql.tables_priv where user like 'mysqltest\_%'; +delete from mysql.columns_priv where user like 'mysqltest\_%'; +flush privileges; +drop database mysqltest; diff -r 8fadb9f22d1c mysql-test/rpl_transaction_test/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mysql-test/rpl_transaction_test/README Fri Oct 17 02:50:16 2008 -0700 @@ -0,0 +1,15 @@ +The tests under this directory is to support the transaction support for replication. +We have to store those tests in a different place because some test results are different +when transaction support is enabled. + +How to run those tests: + . copy all test files to their corresponding directories + . ./mysql-test-run.pl --mysqld="--rpl_transaction_enabled=1" --slave-innodb --do-test=rpl + + +rpl_transaction_001 need manual verification: + . ./mysql-test-run.pl --mysqld="--rpl_transaction_enabled=1" --slave-innodb rpl_transaction_001 + . slave-relay-bin.000006: should be the only relay-log left + . the first event after start event in slave-relay-bin.000006 should be + - server id -1 end_log_pos 236 Rotate to master-bin.000001 pos: 11735 + - the position "pos: 11735" must be correct diff -r 8fadb9f22d1c mysql-test/rpl_transaction_test/r/rpl000002.result --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mysql-test/rpl_transaction_test/r/rpl000002.result Fri Oct 17 02:50:16 2008 -0700 @@ -0,0 +1,46 @@ +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; +create table t1 (n int auto_increment primary key); +set insert_id = 2000; +insert into t1 values (NULL),(NULL),(NULL); +select * from t1; +n +2000 +2001 +2002 +show slave hosts; +Server_id Host Port Rpl_recovery_rank Master_id +2 127.0.0.1 9999 2 1 +drop table t1; +stop slave; +create table t2(id int auto_increment primary key, created datetime); +set timestamp=12345; +insert into t2 set created=now(); +select * from t2; +id created +1 1970-01-01 06:25:45 +create table t3 like t2; +create temporary table t4 like t2; +create table t5 select * from t4; +start slave; +select * from t2; +id created +1 1970-01-01 06:25:45 +show create table t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `id` int(11) NOT NULL auto_increment, + `created` datetime default NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +show create table t5; +Table Create Table +t5 CREATE TABLE `t5` ( + `id` int(11) NOT NULL default '0', + `created` datetime default NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +drop table t2,t3,t5; diff -r 8fadb9f22d1c mysql-test/rpl_transaction_test/r/rpl_create_database.result --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mysql-test/rpl_transaction_test/r/rpl_create_database.result Fri Oct 17 02:50:16 2008 -0700 @@ -0,0 +1,87 @@ +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 mysqltest_prometheus; +DROP DATABASE IF EXISTS mysqltest_sisyfos; +DROP DATABASE IF EXISTS mysqltest_bob; +DROP DATABASE IF EXISTS mysqltest_bob; +CREATE DATABASE mysqltest_prometheus; +CREATE DATABASE mysqltest_sisyfos; +CREATE DATABASE mysqltest_bob; +USE mysqltest_sisyfos; +CREATE TABLE t1 (b int); +INSERT INTO t1 VALUES(1); +USE mysqltest_bob; +CREATE TABLE t2 (b int); +INSERT INTO t2 VALUES(2); +ALTER DATABASE mysqltest_sisyfos CHARACTER SET latin1; +USE mysqltest_sisyfos; +ALTER DATABASE mysqltest_bob CHARACTER SET latin1; +SHOW DATABASES; +Database +information_schema +mysql +mysqltest_bob +mysqltest_prometheus +mysqltest_sisyfos +test +SHOW DATABASES; +Database +information_schema +mysql +mysqltest_prometheus +mysqltest_sisyfos +test +DROP DATABASE IF EXISTS mysqltest_sisyfos; +USE mysqltest_prometheus; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); +CREATE DATABASE mysqltest_sisyfos; +USE mysqltest_sisyfos; +CREATE TABLE t2 (a INT); +SHOW BINLOG EVENTS; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Format_desc 1 # Server ver: VERSION, Binlog ver: 4 +master-bin.000001 # Query 1 # DROP DATABASE IF EXISTS mysqltest_prometheus +master-bin.000001 # Query 1 # DROP DATABASE IF EXISTS mysqltest_sisyfos +master-bin.000001 # Query 1 # CREATE DATABASE mysqltest_prometheus +master-bin.000001 # Query 1 # CREATE DATABASE mysqltest_sisyfos +master-bin.000001 # Query 1 # use `mysqltest_sisyfos`; CREATE TABLE t1 (b int) +master-bin.000001 # Query 1 # use `mysqltest_sisyfos`; INSERT INTO t1 VALUES(1) +master-bin.000001 # Query 1 # ALTER DATABASE mysqltest_sisyfos CHARACTER SET latin1 +master-bin.000001 # Query 1 # DROP DATABASE IF EXISTS mysqltest_sisyfos +master-bin.000001 # Query 1 # use `mysqltest_prometheus`; CREATE TABLE t1 (a INT) +master-bin.000001 # Query 1 # use `mysqltest_prometheus`; INSERT INTO t1 VALUES (1) +master-bin.000001 # Query 1 # CREATE DATABASE mysqltest_sisyfos +master-bin.000001 # Query 1 # use `mysqltest_sisyfos`; CREATE TABLE t2 (a INT) +SHOW DATABASES; +Database +information_schema +mysql +mysqltest_bob +mysqltest_prometheus +mysqltest_sisyfos +test +SHOW DATABASES; +Database +information_schema +mysql +mysqltest_prometheus +mysqltest_sisyfos +test +SHOW CREATE TABLE mysqltest_prometheus.t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) default NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +SHOW CREATE TABLE mysqltest_sisyfos.t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(11) default NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP DATABASE IF EXISTS mysqltest_prometheus; +DROP DATABASE IF EXISTS mysqltest_sisyfos; +DROP DATABASE IF EXISTS mysqltest_bob; diff -r 8fadb9f22d1c mysql-test/rpl_transaction_test/r/rpl_ddl.result --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mysql-test/rpl_transaction_test/r/rpl_ddl.result Fri Oct 17 02:50:16 2008 -0700 @@ -0,0 +1,1693 @@ +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; +SET AUTOCOMMIT = 1; +DROP DATABASE IF EXISTS mysqltest1; +DROP DATABASE IF EXISTS mysqltest2; +DROP DATABASE IF EXISTS mysqltest3; +CREATE DATABASE mysqltest1; +CREATE DATABASE mysqltest2; +CREATE TABLE mysqltest1.t1 (f1 BIGINT) ENGINE= "InnoDB"; +INSERT INTO mysqltest1.t1 SET f1= 0; +CREATE TABLE mysqltest1.t2 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t3 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t4 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t5 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t6 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE INDEX my_idx6 ON mysqltest1.t6(f1); +CREATE TABLE mysqltest1.t7 (f1 BIGINT) ENGINE= "InnoDB"; +INSERT INTO mysqltest1.t7 SET f1= 0; +CREATE TABLE mysqltest1.t8 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t9 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t10 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t11 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t12 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t13 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t14 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t15 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t16 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t17 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t18 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t19 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TEMPORARY TABLE mysqltest1.t23 (f1 BIGINT); +SET AUTOCOMMIT = 0; +use mysqltest1; + +-------- switch to slave -------- +SET AUTOCOMMIT = 0; +use mysqltest1; + +-------- switch to master ------- + +######## COMMIT ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 0 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +0 + +-------- switch to master ------- +COMMIT; +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- + +######## ROLLBACK ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 1 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +2 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +TEST-INFO: MASTER: The INSERT is not committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +TEST-INFO: SLAVE: The INSERT is not committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- + +######## SET AUTOCOMMIT=1 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 1 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +2 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +-------- switch to master ------- +SET AUTOCOMMIT=1; +SELECT MAX(f1) FROM t1; +MAX(f1) +2 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +2 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +2 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +2 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SET AUTOCOMMIT=0; + +######## START TRANSACTION ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 2 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +3 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +2 + +-------- switch to master ------- +START TRANSACTION; +SELECT MAX(f1) FROM t1; +MAX(f1) +3 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +3 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +3 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +3 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- + +######## BEGIN ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 3 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +4 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +3 + +-------- switch to master ------- +BEGIN; +SELECT MAX(f1) FROM t1; +MAX(f1) +4 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +4 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +4 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +4 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- + +######## DROP TABLE mysqltest1.t2 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 4 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +5 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +4 + +-------- switch to master ------- +DROP TABLE mysqltest1.t2; +SELECT MAX(f1) FROM t1; +MAX(f1) +5 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +5 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +5 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +5 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW TABLES LIKE 't2'; +Tables_in_mysqltest1 (t2) + +-------- switch to slave -------- +SHOW TABLES LIKE 't2'; +Tables_in_mysqltest1 (t2) + +-------- switch to master ------- + +######## DROP TEMPORARY TABLE mysqltest1.t23 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 5 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +6 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +5 + +-------- switch to master ------- +DROP TEMPORARY TABLE mysqltest1.t23; +SELECT MAX(f1) FROM t1; +MAX(f1) +6 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +5 + +-------- switch to master ------- +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +SELECT MAX(f1) FROM t1; +MAX(f1) +5 + +TEST-INFO: MASTER: The INSERT is not committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +5 + +TEST-INFO: SLAVE: The INSERT is not committed (Failed) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW TABLES LIKE 't23'; +Tables_in_mysqltest1 (t23) + +-------- switch to slave -------- +SHOW TABLES LIKE 't23'; +Tables_in_mysqltest1 (t23) + +-------- switch to master ------- + +######## RENAME TABLE mysqltest1.t3 to mysqltest1.t20 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 5 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +6 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +5 + +-------- switch to master ------- +RENAME TABLE mysqltest1.t3 to mysqltest1.t20; +SELECT MAX(f1) FROM t1; +MAX(f1) +6 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +6 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +6 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +6 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW TABLES LIKE 't20'; +Tables_in_mysqltest1 (t20) +t20 + +-------- switch to slave -------- +SHOW TABLES LIKE 't20'; +Tables_in_mysqltest1 (t20) +t20 + +-------- switch to master ------- + +######## ALTER TABLE mysqltest1.t4 ADD column f2 BIGINT ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 6 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +7 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +6 + +-------- switch to master ------- +ALTER TABLE mysqltest1.t4 ADD column f2 BIGINT; +SELECT MAX(f1) FROM t1; +MAX(f1) +7 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +7 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +7 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +7 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +describe mysqltest1.t4; +Field Type Null Key Default Extra +f1 bigint(20) YES NULL +f2 bigint(20) YES NULL + +-------- switch to slave -------- +describe mysqltest1.t4; +Field Type Null Key Default Extra +f1 bigint(20) YES NULL +f2 bigint(20) YES NULL + +-------- switch to master ------- + +######## CREATE TABLE mysqltest1.t21 (f1 BIGINT) ENGINE= "InnoDB" ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 7 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +8 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +7 + +-------- switch to master ------- +CREATE TABLE mysqltest1.t21 (f1 BIGINT) ENGINE= "InnoDB"; +SELECT MAX(f1) FROM t1; +MAX(f1) +8 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +8 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +8 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +8 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- + +######## CREATE TEMPORARY TABLE mysqltest1.t22 (f1 BIGINT) ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 8 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +9 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +8 + +-------- switch to master ------- +CREATE TEMPORARY TABLE mysqltest1.t22 (f1 BIGINT); +SELECT MAX(f1) FROM t1; +MAX(f1) +9 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +8 + +-------- switch to master ------- +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +SELECT MAX(f1) FROM t1; +MAX(f1) +8 + +TEST-INFO: MASTER: The INSERT is not committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +8 + +TEST-INFO: SLAVE: The INSERT is not committed (Failed) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- + +######## TRUNCATE TABLE mysqltest1.t7 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 8 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +9 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +8 + +-------- switch to master ------- +TRUNCATE TABLE mysqltest1.t7; +SELECT MAX(f1) FROM t1; +MAX(f1) +9 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +9 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +9 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +9 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SELECT * FROM mysqltest1.t7; +f1 + +-------- switch to slave -------- +SELECT * FROM mysqltest1.t7; +f1 + +-------- switch to master ------- + +######## LOCK TABLES mysqltest1.t1 WRITE, mysqltest1.t8 READ ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 9 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +9 + +-------- switch to master ------- +LOCK TABLES mysqltest1.t1 WRITE, mysqltest1.t8 READ; +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +UNLOCK TABLES; + +######## UNLOCK TABLES ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 10 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +11 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +-------- switch to master ------- +UNLOCK TABLES; +SELECT MAX(f1) FROM t1; +MAX(f1) +11 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +TEST-INFO: MASTER: The INSERT is not committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +TEST-INFO: SLAVE: The INSERT is not committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +LOCK TABLES mysqltest1.t1 READ; + +######## UNLOCK TABLES ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 10 + 1; +ERROR HY000: Table 't1' was locked with a READ lock and can't be updated +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +-------- switch to master ------- +UNLOCK TABLES; +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +TEST-INFO: MASTER: The INSERT is not committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +TEST-INFO: SLAVE: The INSERT is not committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +LOCK TABLES mysqltest1.t1 WRITE, mysqltest1.t8 READ; + +######## UNLOCK TABLES ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 10 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +11 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +-------- switch to master ------- +UNLOCK TABLES; +SELECT MAX(f1) FROM t1; +MAX(f1) +11 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +11 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +11 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +11 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- + +######## DROP INDEX my_idx6 ON mysqltest1.t6 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 11 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +12 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +11 + +-------- switch to master ------- +DROP INDEX my_idx6 ON mysqltest1.t6; +SELECT MAX(f1) FROM t1; +MAX(f1) +12 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +12 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +12 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +12 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW INDEX FROM mysqltest1.t6; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment + +-------- switch to slave -------- +SHOW INDEX FROM mysqltest1.t6; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment + +-------- switch to master ------- + +######## CREATE INDEX my_idx5 ON mysqltest1.t5(f1) ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 12 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +13 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +12 + +-------- switch to master ------- +CREATE INDEX my_idx5 ON mysqltest1.t5(f1); +SELECT MAX(f1) FROM t1; +MAX(f1) +13 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +13 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +13 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +13 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW INDEX FROM mysqltest1.t5; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t5 1 my_idx5 1 f1 A 0 NULL NULL YES BTREE + +-------- switch to slave -------- +SHOW INDEX FROM mysqltest1.t5; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t5 1 my_idx5 1 f1 A 0 NULL NULL YES BTREE + +-------- switch to master ------- + +######## DROP DATABASE mysqltest2 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 13 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +14 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +13 + +-------- switch to master ------- +DROP DATABASE mysqltest2; +SELECT MAX(f1) FROM t1; +MAX(f1) +14 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +14 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +14 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +14 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW DATABASES LIKE "mysqltest2"; +Database (mysqltest2) + +-------- switch to slave -------- +SHOW DATABASES LIKE "mysqltest2"; +Database (mysqltest2) + +-------- switch to master ------- + +######## CREATE DATABASE mysqltest3 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 14 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +15 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +14 + +-------- switch to master ------- +CREATE DATABASE mysqltest3; +SELECT MAX(f1) FROM t1; +MAX(f1) +15 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +15 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +15 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +15 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW DATABASES LIKE "mysqltest3"; +Database (mysqltest3) +mysqltest3 + +-------- switch to slave -------- +SHOW DATABASES LIKE "mysqltest3"; +Database (mysqltest3) +mysqltest3 + +-------- switch to master ------- + +######## CREATE PROCEDURE p1() READS SQL DATA SELECT "this is p1" ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 15 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +16 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +15 + +-------- switch to master ------- +CREATE PROCEDURE p1() READS SQL DATA SELECT "this is p1"; +SELECT MAX(f1) FROM t1; +MAX(f1) +16 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +16 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +16 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +16 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW PROCEDURE STATUS LIKE 'p1'; +Db mysqltest1 +Name p1 +Type PROCEDURE +Definer root@localhost +Modified # +Created # +Security_type DEFINER +Comment + -------- switch to slave ------- +SHOW PROCEDURE STATUS LIKE 'p1'; +Db mysqltest1 +Name p1 +Type PROCEDURE +Definer root@localhost +Modified # +Created # +Security_type DEFINER +Comment + +######## ALTER PROCEDURE p1 COMMENT "I have been altered" ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 16 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +17 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +16 + +-------- switch to master ------- +ALTER PROCEDURE p1 COMMENT "I have been altered"; +SELECT MAX(f1) FROM t1; +MAX(f1) +17 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +17 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +17 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +17 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW PROCEDURE STATUS LIKE 'p1'; +Db mysqltest1 +Name p1 +Type PROCEDURE +Definer root@localhost +Modified # +Created # +Security_type DEFINER +Comment I have been altered + -------- switch to slave ------- +SHOW PROCEDURE STATUS LIKE 'p1'; +Db mysqltest1 +Name p1 +Type PROCEDURE +Definer root@localhost +Modified # +Created # +Security_type DEFINER +Comment I have been altered + +######## DROP PROCEDURE p1 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 17 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +18 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +17 + +-------- switch to master ------- +DROP PROCEDURE p1; +SELECT MAX(f1) FROM t1; +MAX(f1) +18 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +18 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +18 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +18 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW PROCEDURE STATUS LIKE 'p1'; + -------- switch to slave ------- +SHOW PROCEDURE STATUS LIKE 'p1'; + +######## CREATE OR REPLACE VIEW v1 as select * from t1 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 18 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +19 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +18 + +-------- switch to master ------- +CREATE OR REPLACE VIEW v1 as select * from t1; +SELECT MAX(f1) FROM t1; +MAX(f1) +19 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +19 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +19 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +19 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f1` AS `f1` from `t1` + +-------- switch to slave ------- +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f1` AS `f1` from `t1` + +######## ALTER VIEW v1 AS select f1 from t1 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 19 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +20 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +19 + +-------- switch to master ------- +ALTER VIEW v1 AS select f1 from t1; +SELECT MAX(f1) FROM t1; +MAX(f1) +20 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +20 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +20 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +20 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f1` AS `f1` from `t1` + +-------- switch to slave ------- +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f1` AS `f1` from `t1` + +######## DROP VIEW IF EXISTS v1 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 20 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +21 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +20 + +-------- switch to master ------- +DROP VIEW IF EXISTS v1; +SELECT MAX(f1) FROM t1; +MAX(f1) +21 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +21 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +21 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +21 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW CREATE VIEW v1; +ERROR 42S02: Table 'mysqltest1.v1' doesn't exist + +-------- switch to slave ------- +SHOW CREATE VIEW v1; +ERROR 42S02: Table 'mysqltest1.v1' doesn't exist + +######## CREATE TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 21 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +22 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +21 + +-------- switch to master ------- +CREATE TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1; +SELECT MAX(f1) FROM t1; +MAX(f1) +22 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +22 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +22 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +22 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode Definer +trg1 INSERT t1 SET @a:=1 BEFORE NULL root@localhost + +-------- switch to slave ------- +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode Definer +trg1 INSERT t1 SET @a:=1 BEFORE NULL root@localhost + +######## DROP TRIGGER trg1 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 22 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +23 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +22 + +-------- switch to master ------- +DROP TRIGGER trg1; +SELECT MAX(f1) FROM t1; +MAX(f1) +23 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +23 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +23 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +23 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode Definer + +-------- switch to slave ------- +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode Definer + +######## CREATE USER user1@localhost ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 23 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +24 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +23 + +-------- switch to master ------- +CREATE USER user1@localhost; +SELECT MAX(f1) FROM t1; +MAX(f1) +24 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +24 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +24 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +24 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SELECT user FROM mysql.user WHERE user = 'user1'; +user +user1 + +-------- switch to slave ------- +SELECT user FROM mysql.user WHERE user = 'user1'; +user +user1 + +######## RENAME USER user1@localhost TO rename1@localhost ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 24 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +25 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +24 + +-------- switch to master ------- +RENAME USER user1@localhost TO rename1@localhost; +SELECT MAX(f1) FROM t1; +MAX(f1) +25 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +25 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +25 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +25 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SELECT user FROM mysql.user WHERE user = 'rename1'; +user +rename1 + +-------- switch to slave ------- +SELECT user FROM mysql.user WHERE user = 'rename1'; +user +rename1 + +######## DROP USER rename1@localhost ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 25 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +26 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +25 + +-------- switch to master ------- +DROP USER rename1@localhost; +SELECT MAX(f1) FROM t1; +MAX(f1) +26 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +26 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +26 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +26 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SELECT user FROM mysql.user WHERE user = 'rename1'; +user + +-------- switch to slave ------- +SELECT user FROM mysql.user WHERE user = 'rename1'; +user +DROP DATABASE IF EXISTS mysqltest1; +DROP DATABASE IF EXISTS mysqltest2; +DROP DATABASE IF EXISTS mysqltest3; diff -r 8fadb9f22d1c mysql-test/rpl_transaction_test/r/rpl_loaddata.result --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mysql-test/rpl_transaction_test/r/rpl_loaddata.result Fri Oct 17 02:50:16 2008 -0700 @@ -0,0 +1,82 @@ +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; +reset master; +create table t1(a int not null auto_increment, b int, primary key(a) ); +load data infile '../std_data_ln/rpl_loaddata.dat' into table t1; +create temporary table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60)); +load data infile '../std_data_ln/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by '\n##\n' starting by '>' ignore 1 lines; +create table t3 (day date,id int(9),category enum('a','b','c'),name varchar(60)); +insert into t3 select * from t2; +select * from t1; +a b +1 10 +2 15 +select * from t3; +day id category name +2003-02-22 2461 b a a a @ %  ' " a +2003-03-22 2161 c asdf +2003-03-22 2416 a bbbbb +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +slave-bin.000001 1557 +drop table t1; +drop table t2; +drop table t3; +create table t1(a int, b int, unique(b)); +insert into t1 values(1,10); +load data infile '../std_data_ln/rpl_loaddata.dat' into table t1; +set global sql_slave_skip_counter=1; +start slave; +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_PORT 1 master-bin.000001 1789 # # master-bin.000001 Yes Yes 0 0 1789 # None 0 No # +set sql_log_bin=0; +delete from t1; +set sql_log_bin=1; +load data infile '../std_data_ln/rpl_loaddata.dat' into table t1; +stop slave; +change master to master_user='test'; +change master to master_user='root'; +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_PORT 1 master-bin.000001 1824 # # master-bin.000001 No No 0 0 1824 # None 0 No # +set global sql_slave_skip_counter=1; +start slave; +set sql_log_bin=0; +delete from t1; +set sql_log_bin=1; +load data infile '../std_data_ln/rpl_loaddata.dat' into table t1; +stop slave; +reset slave; +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_PORT 1 4 # # No No 0 0 0 # None 0 No # +reset master; +create table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60), +unique(day)) engine=MyISAM; +load data infile '../std_data_ln/rpl_loaddata2.dat' into table t2 fields +terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by +'\n##\n' starting by '>' ignore 1 lines; +ERROR 23000: Duplicate entry '2003-03-22' for key 1 +select * from t2; +day id category name +2003-02-22 2461 b a a a @ %  ' " a +2003-03-22 2161 c asdf +start slave; +select * from t2; +day id category name +2003-02-22 2461 b a a a @ %  ' " a +2003-03-22 2161 c asdf +alter table t2 drop key day; +delete from t2; +load data infile '../std_data_ln/rpl_loaddata2.dat' into table t2 fields +terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by +'\n##\n' starting by '>' ignore 1 lines; +ERROR 23000: Duplicate entry '2003-03-22' for key 1 +drop table t2; +drop table t2; +drop table t1; diff -r 8fadb9f22d1c mysql-test/rpl_transaction_test/r/rpl_log.result --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mysql-test/rpl_transaction_test/r/rpl_log.result Fri Oct 17 02:50:16 2008 -0700 @@ -0,0 +1,128 @@ +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; +stop slave; +reset master; +reset slave; +reset master; +create table t1(n int not null auto_increment primary key); +insert into t1 values (NULL); +drop table t1; +create table t1 (word char(20) not null); +load data infile '../std_data_ln/words.dat' into table t1 ignore 1 lines; +select count(*) from t1; +count(*) +69 +drop table t1; +show binlog events; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 4 Format_desc 1 98 Server ver: VERSION, Binlog ver: 4 +master-bin.000001 98 Query 1 219 use `test`; create table t1(n int not null auto_increment primary key) +master-bin.000001 219 Intvar 1 247 INSERT_ID=1 +master-bin.000001 247 Query 1 338 use `test`; insert into t1 values (NULL) +master-bin.000001 338 Query 1 414 use `test`; drop table t1 +master-bin.000001 414 Query 1 517 use `test`; create table t1 (word char(20) not null) +master-bin.000001 517 Begin_load_query 1 1121 ;file_id=1;block_len=581 +master-bin.000001 1121 Execute_load_query 1 1269 use `test`; load data infile '../std_data_ln/words.dat' into table t1 ignore 1 lines ;file_id=1 +master-bin.000001 1269 Query 1 1345 use `test`; drop table t1 +show binlog events from 98 limit 1; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 98 Query 1 219 use `test`; create table t1(n int not null auto_increment primary key) +show binlog events from 98 limit 2; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 98 Query 1 219 use `test`; create table t1(n int not null auto_increment primary key) +master-bin.000001 219 Intvar 1 247 INSERT_ID=1 +show binlog events from 98 limit 2,1; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 247 Query 1 338 use `test`; insert into t1 values (NULL) +flush logs; +create table t5 (a int); +drop table t5; +start slave; +flush logs; +stop slave; +create table t1 (n int); +insert into t1 values (1); +drop table t1; +show binlog events; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 4 Format_desc 1 98 Server ver: VERSION, Binlog ver: 4 +master-bin.000001 98 Query 1 219 use `test`; create table t1(n int not null auto_increment primary key) +master-bin.000001 219 Intvar 1 247 INSERT_ID=1 +master-bin.000001 247 Query 1 338 use `test`; insert into t1 values (NULL) +master-bin.000001 338 Query 1 414 use `test`; drop table t1 +master-bin.000001 414 Query 1 517 use `test`; create table t1 (word char(20) not null) +master-bin.000001 517 Begin_load_query 1 1121 ;file_id=1;block_len=581 +master-bin.000001 1121 Execute_load_query 1 1269 use `test`; load data infile '../std_data_ln/words.dat' into table t1 ignore 1 lines ;file_id=1 +master-bin.000001 1269 Query 1 1345 use `test`; drop table t1 +master-bin.000001 1345 Rotate 1 1389 master-bin.000002;pos=4 +show binlog events in 'master-bin.000002'; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000002 4 Format_desc 1 98 Server ver: VERSION, Binlog ver: 4 +master-bin.000002 98 Query 1 184 use `test`; create table t5 (a int) +master-bin.000002 184 Query 1 260 use `test`; drop table t5 +master-bin.000002 260 Query 1 346 use `test`; create table t1 (n int) +master-bin.000002 346 Query 1 434 use `test`; insert into t1 values (1) +master-bin.000002 434 Query 1 510 use `test`; drop table t1 +show binary logs; +Log_name File_size +master-bin.000001 1389 +master-bin.000002 510 +start slave; +show binary logs; +Log_name File_size +slave-bin.000001 1742 +slave-bin.000002 443 +show binlog events in 'slave-bin.000001' from 4; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 4 Format_desc 2 98 Server ver: VERSION, Binlog ver: 4 +slave-bin.000001 98 Query 1 219 use `test`; create table t1(n int not null auto_increment primary key) +slave-bin.000001 219 Query 1 287 use `test`; BEGIN +slave-bin.000001 287 Intvar 1 28 INSERT_ID=1 +slave-bin.000001 315 Query 1 119 use `test`; insert into t1 values (NULL) +slave-bin.000001 406 Xid 1 433 COMMIT /* xid=15 */ +slave-bin.000001 433 Query 1 509 use `test`; drop table t1 +slave-bin.000001 509 Query 1 612 use `test`; create table t1 (word char(20) not null) +slave-bin.000001 612 Query 1 680 use `test`; BEGIN +slave-bin.000001 680 Begin_load_query 1 604 ;file_id=1;block_len=581 +slave-bin.000001 1284 Execute_load_query 1 754 use `test`; load data INFILE '../tmp/SQL_LOAD-2-1-1.data' INTO table t1 ignore 1 lines ;file_id=1 +slave-bin.000001 1434 Xid 1 1461 COMMIT /* xid=18 */ +slave-bin.000001 1461 Query 1 1537 use `test`; drop table t1 +slave-bin.000001 1537 Query 1 1623 use `test`; create table t5 (a int) +slave-bin.000001 1623 Query 1 1699 use `test`; drop table t5 +slave-bin.000001 1699 Rotate 2 1742 slave-bin.000002;pos=4 +show binlog events in 'slave-bin.000002' from 4; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000002 4 Format_desc 2 98 Server ver: VERSION, Binlog ver: 4 +slave-bin.000002 98 Query 1 184 use `test`; create table t1 (n int) +slave-bin.000002 184 Query 1 252 use `test`; BEGIN +slave-bin.000002 252 Query 1 88 use `test`; insert into t1 values (1) +slave-bin.000002 340 Xid 1 367 COMMIT /* xid=27 */ +slave-bin.000002 367 Query 1 443 use `test`; drop table t1 +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_PORT 1 master-bin.000002 510 # # master-bin.000002 Yes Yes 0 0 510 # None 0 No # +show binlog events in 'slave-bin.000005' from 4; +ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Could not find target log +create table t1(a int auto_increment primary key, b int); +insert into t1 values (NULL, 1); +reset master; +set insert_id=5; +insert into t1 values (NULL, last_insert_id()), (NULL, last_insert_id()); +show binlog events; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 4 Format_desc 2 98 Server ver: VERSION, Binlog ver: 4 +slave-bin.000001 98 Query 2 166 use `test`; BEGIN +slave-bin.000001 166 Intvar 2 28 LAST_INSERT_ID=1 +slave-bin.000001 194 Intvar 2 56 INSERT_ID=5 +slave-bin.000001 222 Query 2 191 use `test`; insert into t1 values (NULL, last_insert_id()), (NULL, last_insert_id()) +slave-bin.000001 357 Xid 2 384 COMMIT /* xid=38 */ +select * from t1; +a b +1 1 +5 1 +6 1 +drop table t1; diff -r 8fadb9f22d1c mysql-test/rpl_transaction_test/r/rpl_sp.result --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mysql-test/rpl_transaction_test/r/rpl_sp.result Fri Oct 17 02:50:16 2008 -0700 @@ -0,0 +1,468 @@ +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 mysqltest1; +create database mysqltest1; +use mysqltest1; +create table t1 (a varchar(100)); +use mysqltest1; +create procedure foo() +begin +declare b int; +set b = 8; +insert into t1 values (b); +insert into t1 values (unix_timestamp()); +end| +select * from mysql.proc where name='foo' and db='mysqltest1'; +db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment +mysqltest1 foo PROCEDURE foo SQL CONTAINS_SQL NO DEFINER begin +declare b int; +set b = 8; +insert into t1 values (b); +insert into t1 values (unix_timestamp()); +end root@localhost # # +select * from mysql.proc where name='foo' and db='mysqltest1'; +db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment +mysqltest1 foo PROCEDURE foo SQL CONTAINS_SQL NO DEFINER begin +declare b int; +set b = 8; +insert into t1 values (b); +insert into t1 values (unix_timestamp()); +end root@localhost # # +set timestamp=1000000000; +call foo(); +select * from t1; +a +8 +1000000000 +select * from t1; +a +8 +1000000000 +delete from t1; +create procedure foo2() +select * from mysqltest1.t1; +call foo2(); +a +alter procedure foo2 contains sql; +drop table t1; +create table t1 (a int); +create table t2 like t1; +create procedure foo3() +deterministic +insert into t1 values (15); +grant CREATE ROUTINE, EXECUTE on mysqltest1.* to "zedjzlcsjhd"@127.0.0.1; +grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1; +grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1; +SELECT 1; +1 +1 +create procedure foo4() +deterministic +begin +insert into t2 values(3); +insert into t1 values (5); +end| +call foo4(); +Got one of the listed errors +call foo3(); +show warnings; +Level Code Message +call foo4(); +Got one of the listed errors +alter procedure foo4 sql security invoker; +call foo4(); +show warnings; +Level Code Message +select * from t1; +a +15 +5 +select * from t2; +a +3 +3 +3 +select * from t1; +a +15 +5 +select * from t2; +a +3 +3 +3 +delete from t2; +alter table t2 add unique (a); +drop procedure foo4; +create procedure foo4() +deterministic +begin +insert into t2 values(20),(20); +end| +call foo4(); +ERROR 23000: Duplicate entry '20' for key 1 +show warnings; +Level Code Message +Error 1062 Duplicate entry '20' for key 1 +select * from t2; +a +20 +select * from t2; +a +select * from mysql.proc where name="foo4" and db='mysqltest1'; +db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment +mysqltest1 foo4 PROCEDURE foo4 SQL CONTAINS_SQL YES DEFINER begin +insert into t2 values(20),(20); +end root@localhost # # +drop procedure foo4; +select * from mysql.proc where name="foo4" and db='mysqltest1'; +db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment +select * from mysql.proc where name="foo4" and db='mysqltest1'; +db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment +drop procedure foo; +drop procedure foo2; +drop procedure foo3; +create function fn1(x int) +returns int +begin +insert into t1 values (x); +return x+2; +end| +ERROR HY000: This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable) +create function fn1(x int) +returns int +deterministic +begin +insert into t1 values (x); +return x+2; +end| +delete from t1; +delete from t2; +select fn1(20); +fn1(20) +22 +insert into t2 values(fn1(21)); +select * from t1; +a +20 +21 +select * from t2; +a +23 +select * from t1; +a +20 +21 +select * from t2; +a +23 +drop function fn1; +create function fn1() +returns int +no sql +begin +return unix_timestamp(); +end| +alter function fn1 contains sql; +ERROR HY000: This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable) +delete from t1; +set timestamp=1000000000; +insert into t1 values(fn1()); +create function fn2() +returns int +no sql +begin +return unix_timestamp(); +end| +ERROR HY000: You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable) +set global log_bin_trust_routine_creators=1; +Warnings: +Warning 1287 'log_bin_trust_routine_creators' is deprecated; use 'log_bin_trust_function_creators' instead +set global log_bin_trust_function_creators=0; +set global log_bin_trust_function_creators=1; +set global log_bin_trust_function_creators=1; +create function fn2() +returns int +no sql +begin +return unix_timestamp(); +end| +create function fn3() +returns int +not deterministic +reads sql data +begin +return 0; +end| +select fn3(); +fn3() +0 +select * from mysql.proc where db='mysqltest1'; +db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment +mysqltest1 fn1 FUNCTION fn1 SQL NO_SQL NO DEFINER int(11) begin +return unix_timestamp(); +end root@localhost # # +mysqltest1 fn2 FUNCTION fn2 SQL NO_SQL NO DEFINER int(11) begin +return unix_timestamp(); +end zedjzlcsjhd@localhost # # +mysqltest1 fn3 FUNCTION fn3 SQL READS_SQL_DATA NO DEFINER int(11) begin +return 0; +end root@localhost # # +select * from t1; +a +1000000000 +use mysqltest1; +select * from t1; +a +1000000000 +select * from mysql.proc where db='mysqltest1'; +db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment +mysqltest1 fn1 FUNCTION fn1 SQL NO_SQL NO DEFINER int(11) begin +return unix_timestamp(); +end root@localhost # # +mysqltest1 fn2 FUNCTION fn2 SQL NO_SQL NO DEFINER int(11) begin +return unix_timestamp(); +end zedjzlcsjhd@localhost # # +mysqltest1 fn3 FUNCTION fn3 SQL READS_SQL_DATA NO DEFINER int(11) begin +return 0; +end root@localhost # # +delete from t2; +alter table t2 add unique (a); +drop function fn1; +create function fn1(x int) +returns int +begin +insert into t2 values(x),(x); +return 10; +end| +do fn1(100); +Warnings: +Error 1062 Duplicate entry '100' for key 1 +select fn1(20); +ERROR 23000: Duplicate entry '20' for key 1 +select * from t2; +a +20 +100 +select * from t2; +a +20 +100 +create trigger trg before insert on t1 for each row set new.a= 10; +ERROR 42000: Access denied; you need the SUPER privilege for this operation +delete from t1; +create trigger trg before insert on t1 for each row set new.a= 10; +insert into t1 values (1); +select * from t1; +a +10 +select * from t1; +a +10 +delete from t1; +drop trigger trg; +insert into t1 values (1); +select * from t1; +a +1 +show binlog events in 'master-bin.000001' from 98; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query 1 # drop database if exists mysqltest1 +master-bin.000001 # Query 1 # create database mysqltest1 +master-bin.000001 # Query 1 # use `mysqltest1`; create table t1 (a varchar(100)) +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` procedure foo() +begin +declare b int; +set b = 8; +insert into t1 values (b); +insert into t1 values (unix_timestamp()); +end +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values ( NAME_CONST('b',8)) +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (unix_timestamp()) +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` procedure foo2() +select * from mysqltest1.t1 +master-bin.000001 # Query 1 # use `mysqltest1`; alter procedure foo2 contains sql +master-bin.000001 # Query 1 # use `mysqltest1`; drop table t1 +master-bin.000001 # Query 1 # use `mysqltest1`; create table t1 (a int) +master-bin.000001 # Query 1 # use `mysqltest1`; create table t2 like t1 +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` procedure foo3() +deterministic +insert into t1 values (15) +master-bin.000001 # Query 1 # use `mysqltest1`; grant CREATE ROUTINE, EXECUTE on mysqltest1.* to "zedjzlcsjhd"@127.0.0.1 +master-bin.000001 # Query 1 # use `mysqltest1`; grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1 +master-bin.000001 # Query 1 # use `mysqltest1`; grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1 +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`zedjzlcsjhd`@`127.0.0.1` procedure foo4() +deterministic +begin +insert into t2 values(3); +insert into t1 values (5); +end +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3) +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (15) +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3) +master-bin.000001 # Query 1 # use `mysqltest1`; alter procedure foo4 sql security invoker +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3) +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (5) +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t2 +master-bin.000001 # Query 1 # use `mysqltest1`; alter table t2 add unique (a) +master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo4 +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` procedure foo4() +deterministic +begin +insert into t2 values(20),(20); +end +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(20),(20) +master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo4 +master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo +master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo2 +master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo3 +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function fn1(x int) +returns int +deterministic +begin +insert into t1 values (x); +return x+2; +end +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t2 +master-bin.000001 # Query 1 # use `mysqltest1`; SELECT `fn1`(20) +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(fn1(21)) +master-bin.000001 # Query 1 # use `mysqltest1`; drop function fn1 +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function fn1() +returns int +no sql +begin +return unix_timestamp(); +end +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values(fn1()) +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`zedjzlcsjhd`@`127.0.0.1` function fn2() +returns int +no sql +begin +return unix_timestamp(); +end +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function fn3() +returns int +not deterministic +reads sql data +begin +return 0; +end +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t2 +master-bin.000001 # Query 1 # use `mysqltest1`; alter table t2 add unique (a) +master-bin.000001 # Query 1 # use `mysqltest1`; drop function fn1 +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function fn1(x int) +returns int +begin +insert into t2 values(x),(x); +return 10; +end +master-bin.000001 # Query 1 # use `mysqltest1`; SELECT `fn1`(100) +master-bin.000001 # Query 1 # use `mysqltest1`; SELECT `fn1`(20) +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` trigger trg before insert on t1 for each row set new.a= 10 +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (1) +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 +master-bin.000001 # Query 1 # use `mysqltest1`; drop trigger trg +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (1) +select * from t1; +a +1 +create procedure foo() +not deterministic +reads sql data +select * from t1; +call foo(); +a +1 +drop procedure foo; +drop function fn1; +drop database mysqltest1; +drop user "zedjzlcsjhd"@127.0.0.1; +use test; +use test; +drop function if exists f1; +create function f1() returns int reads sql data +begin +declare var integer; +declare c cursor for select a from v1; +open c; +fetch c into var; +close c; +return var; +end| +create view v1 as select 1 as a; +create table t1 (a int); +insert into t1 (a) values (f1()); +select * from t1; +a +1 +drop view v1; +drop function f1; +select * from t1; +a +1 +DROP PROCEDURE IF EXISTS p1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1(col VARCHAR(10)); +CREATE PROCEDURE p1(arg VARCHAR(10)) +INSERT INTO t1 VALUES(arg); +CALL p1('test'); +SELECT * FROM t1; +col +test +SELECT * FROM t1; +col +test +DROP PROCEDURE p1; + +---> Test for BUG#20438 + +---> Preparing environment... +---> connection: master +DROP PROCEDURE IF EXISTS p1; +DROP FUNCTION IF EXISTS f1; + +---> Synchronizing slave with master... + +---> connection: master + +---> Creating procedure... +/*!50003 CREATE PROCEDURE p1() SET @a = 1 */; +/*!50003 CREATE FUNCTION f1() RETURNS INT RETURN 0 */; + +---> Checking on master... +SHOW CREATE PROCEDURE p1; +Procedure sql_mode Create Procedure +p1 CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`() +SET @a = 1 +SHOW CREATE FUNCTION f1; +Function sql_mode Create Function +f1 CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS int(11) +RETURN 0 + +---> Synchronizing slave with master... +---> connection: master + +---> Checking on slave... +SHOW CREATE PROCEDURE p1; +Procedure sql_mode Create Procedure +p1 CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`() +SET @a = 1 +SHOW CREATE FUNCTION f1; +Function sql_mode Create Function +f1 CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS int(11) +RETURN 0 + +---> connection: master + +---> Cleaning up... +DROP PROCEDURE p1; +DROP FUNCTION f1; +drop table t1; diff -r 8fadb9f22d1c mysql-test/rpl_transaction_test/r/rpl_transaction_001.result --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mysql-test/rpl_transaction_test/r/rpl_transaction_001.result Fri Oct 17 02:50:16 2008 -0700 @@ -0,0 +1,143 @@ +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 table if exists t1; +create table t1(n int primary key); +drop database if exists ignore_db; +create database ignore_db; +use test; +insert into t1 values (700); +use ignore_db; +create table ign1(n int primary key); +insert into ign1 values (70); +insert into ign1 values (69); +insert into ign1 values (68); +insert into ign1 values (67); +insert into ign1 values (66); +insert into ign1 values (65); +insert into ign1 values (64); +insert into ign1 values (63); +insert into ign1 values (62); +insert into ign1 values (61); +insert into ign1 values (60); +insert into ign1 values (59); +insert into ign1 values (58); +insert into ign1 values (57); +insert into ign1 values (56); +insert into ign1 values (55); +insert into ign1 values (54); +insert into ign1 values (53); +insert into ign1 values (52); +insert into ign1 values (51); +insert into ign1 values (50); +insert into ign1 values (49); +insert into ign1 values (48); +insert into ign1 values (47); +insert into ign1 values (46); +insert into ign1 values (45); +insert into ign1 values (44); +insert into ign1 values (43); +insert into ign1 values (42); +insert into ign1 values (41); +insert into ign1 values (40); +insert into ign1 values (39); +insert into ign1 values (38); +insert into ign1 values (37); +insert into ign1 values (36); +insert into ign1 values (35); +insert into ign1 values (34); +insert into ign1 values (33); +insert into ign1 values (32); +insert into ign1 values (31); +insert into ign1 values (30); +insert into ign1 values (29); +insert into ign1 values (28); +insert into ign1 values (27); +insert into ign1 values (26); +insert into ign1 values (25); +insert into ign1 values (24); +insert into ign1 values (23); +insert into ign1 values (22); +insert into ign1 values (21); +insert into ign1 values (20); +insert into ign1 values (19); +insert into ign1 values (18); +insert into ign1 values (17); +insert into ign1 values (16); +insert into ign1 values (15); +insert into ign1 values (14); +insert into ign1 values (13); +insert into ign1 values (12); +insert into ign1 values (11); +insert into ign1 values (10); +insert into ign1 values (9); +insert into ign1 values (8); +insert into ign1 values (7); +insert into ign1 values (6); +insert into ign1 values (5); +insert into ign1 values (4); +insert into ign1 values (3); +insert into ign1 values (2); +insert into ign1 values (1); +use test; +insert into t1 values (701); +insert into t1 values (50); +insert into t1 values (49); +insert into t1 values (48); +insert into t1 values (47); +insert into t1 values (46); +insert into t1 values (45); +insert into t1 values (44); +insert into t1 values (43); +insert into t1 values (42); +insert into t1 values (41); +insert into t1 values (40); +insert into t1 values (39); +insert into t1 values (38); +insert into t1 values (37); +insert into t1 values (36); +insert into t1 values (35); +insert into t1 values (34); +insert into t1 values (33); +insert into t1 values (32); +insert into t1 values (31); +insert into t1 values (30); +insert into t1 values (29); +insert into t1 values (28); +insert into t1 values (27); +insert into t1 values (26); +insert into t1 values (25); +insert into t1 values (24); +insert into t1 values (23); +insert into t1 values (22); +insert into t1 values (21); +insert into t1 values (20); +insert into t1 values (19); +insert into t1 values (18); +insert into t1 values (17); +insert into t1 values (16); +insert into t1 values (15); +insert into t1 values (14); +insert into t1 values (13); +insert into t1 values (12); +insert into t1 values (11); +insert into t1 values (10); +insert into t1 values (9); +insert into t1 values (8); +insert into t1 values (7); +insert into t1 values (6); +insert into t1 values (5); +insert into t1 values (4); +insert into t1 values (3); +insert into t1 values (2); +insert into t1 values (1); +select count(*) from t1; +count(*) +52 +select * from ign1; +ERROR 42S02: Table 'test.ign1' doesn't exist +drop table t1; +drop database ignore_db; diff -r 8fadb9f22d1c mysql-test/rpl_transaction_test/r/rpl_user_variables.result --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mysql-test/rpl_transaction_test/r/rpl_user_variables.result Fri Oct 17 02:50:16 2008 -0700 @@ -0,0 +1,131 @@ +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; +reset master; +create table t1(n char(30)); +set @i1:=12345678901234, @i2:=-12345678901234, @i3:=0, @i4:=-1; +set @s1:='This is a test', @r1:=12.5, @r2:=-12.5; +set @n1:=null; +set @s2:='', @s3:='abc\'def', @s4:= 'abc\\def', @s5:= 'abc''def'; +insert into t1 values (@i1), (@i2), (@i3), (@i4); +insert into t1 values (@r1), (@r2); +insert into t1 values (@s1), (@s2), (@s3), (@s4), (@s5); +insert into t1 values (@n1); +insert into t1 values (@n2); +insert into t1 values (@a:=0), (@a:=@a+1), (@a:=@a+1); +insert into t1 values (@a+(@b:=@a+1)); +set @q:='abc'; +insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2')); +set @a:=5; +insert into t1 values (@a),(@a); +insert into t1 values (@a),(@a),(@a*5); +select * from t1; +n +12345678901234 +-12345678901234 +0 +-1 +12.5 +-12.5 +This is a test + +abc'def +abc\def +abc'def +NULL +NULL +0 +1 +2 +5 +abc +abcn1 +abcn1n2 +5 +5 +NULL +NULL +NULL +select * from t1; +n +12345678901234 +-12345678901234 +0 +-1 +12.5 +-12.5 +This is a test + +abc'def +abc\def +abc'def +NULL +NULL +0 +1 +2 +5 +abc +abcn1 +abcn1n2 +5 +5 +NULL +NULL +NULL +show binlog events from 98; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Query 1 # use `test`; create table t1(n char(30)) +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # User var 2 # @`i1`=12345678901234 +slave-bin.000001 # User var 2 # @`i2`=-12345678901234 +slave-bin.000001 # User var 2 # @`i3`=0 +slave-bin.000001 # User var 2 # @`i4`=-1 +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@i1), (@i2), (@i3), (@i4) +slave-bin.000001 # Xid 1 # COMMIT /* xid=11 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # User var 2 # @`r1`=12.5 +slave-bin.000001 # User var 2 # @`r2`=-12.5 +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@r1), (@r2) +slave-bin.000001 # Xid 1 # COMMIT /* xid=12 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # User var 2 # @`s1`=_latin1 0x5468697320697320612074657374 COLLATE latin1_swedish_ci +slave-bin.000001 # User var 2 # @`s2`=_latin1 "" COLLATE latin1_swedish_ci +slave-bin.000001 # User var 2 # @`s3`=_latin1 0x61626327646566 COLLATE latin1_swedish_ci +slave-bin.000001 # User var 2 # @`s4`=_latin1 0x6162635C646566 COLLATE latin1_swedish_ci +slave-bin.000001 # User var 2 # @`s5`=_latin1 0x61626327646566 COLLATE latin1_swedish_ci +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@s1), (@s2), (@s3), (@s4), (@s5) +slave-bin.000001 # Xid 1 # COMMIT /* xid=13 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # User var 2 # @`n1`=NULL +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@n1) +slave-bin.000001 # Xid 1 # COMMIT /* xid=14 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # User var 2 # @`n2`=NULL +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@n2) +slave-bin.000001 # Xid 1 # COMMIT /* xid=15 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@a:=0), (@a:=@a+1), (@a:=@a+1) +slave-bin.000001 # Xid 1 # COMMIT /* xid=16 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # User var 2 # @`a`=2 +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@a+(@b:=@a+1)) +slave-bin.000001 # Xid 1 # COMMIT /* xid=17 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # User var 2 # @`q`=_latin1 0x616263 COLLATE latin1_swedish_ci +slave-bin.000001 # Query 1 # use `test`; insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2')) +slave-bin.000001 # Xid 1 # COMMIT /* xid=18 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # User var 2 # @`a`=5 +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@a),(@a) +slave-bin.000001 # Xid 1 # COMMIT /* xid=19 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # User var 2 # @`a`=NULL +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@a),(@a),(@a*5) +slave-bin.000001 # Xid 1 # COMMIT /* xid=20 */ +insert into t1 select * FROM (select @var1 union select @var2) AS t2; +drop table t1; +stop slave; diff -r 8fadb9f22d1c mysql-test/rpl_transaction_test/r/rpl_view.result --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mysql-test/rpl_transaction_test/r/rpl_view.result Fri Oct 17 02:50:16 2008 -0700 @@ -0,0 +1,117 @@ +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 table if exists t1,v1; +drop view if exists t1,v1; +reset master; +create table t1 (a int); +insert into t1 values (1); +create view v1 as select a from t1; +insert into v1 values (2); +select * from v1 order by a; +a +1 +2 +select * from v1 order by a; +a +1 +2 +update v1 set a=3 where a=1; +select * from v1 order by a; +a +2 +3 +select * from v1 order by a; +a +2 +3 +delete from v1 where a=2; +select * from v1 order by a; +a +3 +select * from v1 order by a; +a +3 +alter view v1 as select a as b from t1; +select * from v1 order by 1; +b +3 +drop view v1; +select * from v1 order by a; +ERROR 42S02: Table 'test.v1' doesn't exist +drop table t1; +show binlog events limit 1,100; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Query 1 # use `test`; create table t1 (a int) +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (1) +slave-bin.000001 # Xid 1 # COMMIT /* xid=13 */ +slave-bin.000001 # Query 1 # use `test`; CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select a from t1 +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # Query 1 # use `test`; insert into v1 values (2) +slave-bin.000001 # Xid 1 # COMMIT /* xid=15 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # Query 1 # use `test`; update v1 set a=3 where a=1 +slave-bin.000001 # Xid 1 # COMMIT /* xid=18 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # Query 1 # use `test`; delete from v1 where a=2 +slave-bin.000001 # Xid 1 # COMMIT /* xid=21 */ +slave-bin.000001 # Query 1 # use `test`; ALTER ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select a as b from t1 +slave-bin.000001 # Query 1 # use `test`; drop view v1 +slave-bin.000001 # Query 1 # use `test`; drop table t1 + +---> Test for BUG#20438 + +---> Preparing environment... +---> connection: master +DROP TABLE IF EXISTS t1; +DROP VIEW IF EXISTS v1; + +---> Synchronizing slave with master... + +---> connection: master + +---> Creating objects... +CREATE TABLE t1(c INT); +/*!50003 CREATE VIEW v1 AS SELECT * FROM t1 */; + +---> Inserting value... +INSERT INTO t1 VALUES(1); + +---> Checking on master... +SELECT * FROM t1; +c +1 + +---> Synchronizing slave with master... +---> connection: master + +---> Checking on slave... +SELECT * FROM t1; +c +1 + +---> connection: master + +---> Cleaning up... +DROP VIEW v1; +DROP TABLE t1; +create table t1(a int, b int); +insert into t1 values (1, 1), (1, 2), (1, 3); +create view v1(a, b) as select a, sum(b) from t1 group by a; +explain v1; +Field Type Null Key Default Extra +a int(11) YES NULL +b decimal(32,0) YES NULL +show create table v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,sum(`t1`.`b`) AS `b` from `t1` group by `t1`.`a` +select * from v1; +a b +1 6 +drop table t1; +drop view v1; +End of 5.0 tests diff -r 8fadb9f22d1c mysql-test/rpl_transaction_test/t/rpl_sp.test --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mysql-test/rpl_transaction_test/t/rpl_sp.test Fri Oct 17 02:50:16 2008 -0700 @@ -0,0 +1,522 @@ +# Test of replication of stored procedures (WL#2146 for MySQL 5.0) +# Modified by WL#2971. + +# Note that in the .opt files we still use the old variable name +# log-bin-trust-routine-creators so that this test checks that it's +# still accepted (this test also checks that the new name is +# accepted). The old name could be removed in 5.1 or 6.0. + +source include/master-slave.inc; + +# we need a db != test, where we don't have automatic grants +--disable_warnings +drop database if exists mysqltest1; +--enable_warnings +create database mysqltest1; +use mysqltest1; +create table t1 (a varchar(100)); +sync_slave_with_master; +use mysqltest1; + +# ********************** PART 1 : STORED PROCEDURES *************** + +# Does the same proc as on master get inserted into mysql.proc ? +# (same definer, same properties...) + +connection master; + +delimiter |; + +# Stored procedures don't have the limitations that functions have +# regarding binlogging: it's ok to create a procedure as not +# deterministic and updating data, while it's not ok to create such a +# function. We test this. + +create procedure foo() +begin + declare b int; + set b = 8; + insert into t1 values (b); + insert into t1 values (unix_timestamp()); +end| +delimiter ;| + +# we replace columns having times +# (even with fixed timestamp displayed time may changed based on TZ) +--replace_result localhost.localdomain localhost 127.0.0.1 localhost +--replace_column 13 # 14 # +select * from mysql.proc where name='foo' and db='mysqltest1'; +sync_slave_with_master; +# You will notice in the result that the definer does not match what +# it is on master, it is a known bug on which Alik is working +--replace_result localhost.localdomain localhost 127.0.0.1 localhost +--replace_column 13 # 14 # +select * from mysql.proc where name='foo' and db='mysqltest1'; + +connection master; +# see if timestamp used in SP on slave is same as on master +set timestamp=1000000000; +call foo(); +select * from t1; +sync_slave_with_master; +select * from t1; + +# Now a SP which is not updating tables + +connection master; +delete from t1; +create procedure foo2() + select * from mysqltest1.t1; +call foo2(); + +# check that this is allowed (it's not for functions): +alter procedure foo2 contains sql; + +# SP with definer's right + +drop table t1; +create table t1 (a int); +create table t2 like t1; + +create procedure foo3() + deterministic + insert into t1 values (15); + +# let's create a non-privileged user +grant CREATE ROUTINE, EXECUTE on mysqltest1.* to "zedjzlcsjhd"@127.0.0.1; +grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1; +grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1; + +# ToDo: BUG#14931: There is a race between the last grant binlogging, and +# the binlogging in the new connection made below, causing sporadic test +# failures due to switched statement order in binlog. To fix this we do +# SELECT 1 in the first connection before starting the second, ensuring +# that binlogging is done in the expected order. +# Please remove this SELECT 1 when BUG#14931 is fixed. +SELECT 1; + +connect (con1,127.0.0.1,zedjzlcsjhd,,mysqltest1,$MASTER_MYPORT,); +connection con1; + +# this routine will fail in the second INSERT because of privileges +delimiter |; +create procedure foo4() + deterministic + begin + insert into t2 values(3); + insert into t1 values (5); + end| + +delimiter ;| + +# I add ,0 so that it does not print the error in the test output, +# because this error is hostname-dependent +--error 1142,0 +call foo4(); # invoker has no INSERT grant on table t1 => failure + +connection master; +call foo3(); # success (definer == root) +show warnings; + +--error 1142,0 +call foo4(); # definer's rights => failure + +# we test replication of ALTER PROCEDURE +alter procedure foo4 sql security invoker; +call foo4(); # invoker's rights => success +show warnings; + +# Note that half-failed procedure calls are ok with binlogging; +# if we compare t2 on master and slave we see they are identical: + +select * from t1; +select * from t2; +sync_slave_with_master; +select * from t1; +select * from t2; + +# Let's check another failing-in-the-middle procedure +connection master; +delete from t2; +alter table t2 add unique (a); + +drop procedure foo4; +delimiter |; +create procedure foo4() + deterministic + begin + insert into t2 values(20),(20); + end| + +delimiter ;| + +--error 1062 +call foo4(); +show warnings; + +select * from t2; +sync_slave_with_master; +# check that this failed-in-the-middle replicated right: +select * from t2; + +# Test of DROP PROCEDURE + +--replace_result localhost.localdomain localhost 127.0.0.1 localhost +--replace_column 13 # 14 # +select * from mysql.proc where name="foo4" and db='mysqltest1'; +connection master; +drop procedure foo4; +select * from mysql.proc where name="foo4" and db='mysqltest1'; +sync_slave_with_master; +select * from mysql.proc where name="foo4" and db='mysqltest1'; + +# ********************** PART 2 : FUNCTIONS *************** + +connection master; +drop procedure foo; +drop procedure foo2; +drop procedure foo3; + +delimiter |; +# check that needs "deterministic" +--error 1418 +create function fn1(x int) + returns int +begin + insert into t1 values (x); + return x+2; +end| +create function fn1(x int) + returns int + deterministic +begin + insert into t1 values (x); + return x+2; +end| + +delimiter ;| +delete from t1; +delete from t2; +select fn1(20); +insert into t2 values(fn1(21)); +select * from t1; +select * from t2; +sync_slave_with_master; +select * from t1; +select * from t2; + +connection master; +delimiter |; + +drop function fn1; + +create function fn1() + returns int + no sql +begin + return unix_timestamp(); +end| + +delimiter ;| +# check that needs "deterministic" +--error 1418 +alter function fn1 contains sql; + +delete from t1; +set timestamp=1000000000; +insert into t1 values(fn1()); + +connection con1; + +delimiter |; +--error 1419 # only full-global-privs user can create a function +create function fn2() + returns int + no sql +begin + return unix_timestamp(); +end| +delimiter ;| +connection master; +# test old variable name: +set global log_bin_trust_routine_creators=1; +# now use new name: +set global log_bin_trust_function_creators=0; +set global log_bin_trust_function_creators=1; +# slave needs it too otherwise will not execute what master allowed: +connection slave; +set global log_bin_trust_function_creators=1; + +connection con1; + +delimiter |; +create function fn2() + returns int + no sql +begin + return unix_timestamp(); +end| +delimiter ;| + +connection master; + +# Now a function which is supposed to not update tables +# as it's "reads sql data", so should not give error even if +# non-deterministic. + +delimiter |; +create function fn3() + returns int + not deterministic + reads sql data +begin + return 0; +end| +delimiter ;| + +select fn3(); +--replace_result localhost.localdomain localhost 127.0.0.1 localhost +--replace_column 13 # 14 # +select * from mysql.proc where db='mysqltest1'; +select * from t1; + +sync_slave_with_master; +use mysqltest1; +select * from t1; +--replace_result localhost.localdomain localhost 127.0.0.1 localhost +--replace_column 13 # 14 # +select * from mysql.proc where db='mysqltest1'; + +# Let's check a failing-in-the-middle function +connection master; +delete from t2; +alter table t2 add unique (a); + +drop function fn1; + +delimiter |; +create function fn1(x int) + returns int +begin + insert into t2 values(x),(x); + return 10; +end| + +delimiter ;| + +do fn1(100); + +--error 1062 +select fn1(20); + +select * from t2; +sync_slave_with_master; + +# check that this failed-in-the-middle replicated right: +select * from t2; + +# ********************** PART 3 : TRIGGERS *************** + +connection con1; +--error 1227 +create trigger trg before insert on t1 for each row set new.a= 10; + +connection master; +delete from t1; +# TODO: when triggers can contain an update, test that this update +# does not go into binlog. +# I'm not setting user vars in the trigger, because replication of user vars +# would take care of propagating the user var's value to slave, so even if +# the trigger was not executed on slave it would not be discovered. +create trigger trg before insert on t1 for each row set new.a= 10; +insert into t1 values (1); +select * from t1; +sync_slave_with_master; +select * from t1; + +connection master; +delete from t1; +drop trigger trg; +insert into t1 values (1); +select * from t1; +--replace_column 2 # 5 # +show binlog events in 'master-bin.000001' from 98; +sync_slave_with_master; +select * from t1; + + +# +# Test for bug #13969 "Routines which are replicated from master can't be +# executed on slave". +# +connection master; +create procedure foo() + not deterministic + reads sql data + select * from t1; +sync_slave_with_master; +# This should not fail +call foo(); +connection master; +drop procedure foo; +sync_slave_with_master; + + +# Clean up +connection master; +drop function fn1; +drop database mysqltest1; +drop user "zedjzlcsjhd"@127.0.0.1; +use test; +sync_slave_with_master; +use test; + +# +# Bug#14077 "Failure to replicate a stored function with a cursor": +# verify that stored routines with cursors work on slave. +# +connection master; +--disable_warnings +drop function if exists f1; +--enable_warnings +delimiter |; +create function f1() returns int reads sql data +begin + declare var integer; + declare c cursor for select a from v1; + open c; + fetch c into var; + close c; + return var; +end| +delimiter ;| +create view v1 as select 1 as a; +create table t1 (a int); +insert into t1 (a) values (f1()); +select * from t1; +drop view v1; +drop function f1; +sync_slave_with_master; +connection slave; +select * from t1; + +# +# Bug#16621 "INSERTs in Stored Procedures causes data corruption in the Binary +# Log for 5.0.18" +# + +# Prepare environment. + +connection master; + +--disable_warnings +DROP PROCEDURE IF EXISTS p1; +DROP TABLE IF EXISTS t1; +--enable_warnings + +# Test case. + +CREATE TABLE t1(col VARCHAR(10)); + +CREATE PROCEDURE p1(arg VARCHAR(10)) + INSERT INTO t1 VALUES(arg); + +CALL p1('test'); + +SELECT * FROM t1; + +sync_slave_with_master; +connection slave; + +SELECT * FROM t1; + +# Cleanup. + +connection master; + +DROP PROCEDURE p1; + + +# +# BUG#20438: CREATE statements for views, stored routines and triggers can be +# not replicable. +# + +--echo +--echo ---> Test for BUG#20438 + +# Prepare environment. + +--echo +--echo ---> Preparing environment... +--echo ---> connection: master +--connection master + +--disable_warnings +DROP PROCEDURE IF EXISTS p1; +DROP FUNCTION IF EXISTS f1; +--enable_warnings + +--echo +--echo ---> Synchronizing slave with master... + +--save_master_pos +--connection slave +--sync_with_master + +--echo +--echo ---> connection: master +--connection master + +# Test. + +--echo +--echo ---> Creating procedure... + +/*!50003 CREATE PROCEDURE p1() SET @a = 1 */; + +/*!50003 CREATE FUNCTION f1() RETURNS INT RETURN 0 */; + +--echo +--echo ---> Checking on master... + +SHOW CREATE PROCEDURE p1; +SHOW CREATE FUNCTION f1; + +--echo +--echo ---> Synchronizing slave with master... + +--save_master_pos +--connection slave +--sync_with_master + +--echo ---> connection: master + +--echo +--echo ---> Checking on slave... + +SHOW CREATE PROCEDURE p1; +SHOW CREATE FUNCTION f1; + +# Cleanup. + +--echo +--echo ---> connection: master +--connection master + +--echo +--echo ---> Cleaning up... + +DROP PROCEDURE p1; +DROP FUNCTION f1; + +--save_master_pos +--connection slave +--sync_with_master +--connection master + + +# cleanup +connection master; +drop table t1; +sync_slave_with_master; diff -r 8fadb9f22d1c mysql-test/rpl_transaction_test/t/rpl_transaction_001-slave.opt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mysql-test/rpl_transaction_test/t/rpl_transaction_001-slave.opt Fri Oct 17 02:50:16 2008 -0700 @@ -0,0 +1,1 @@ +-O max_binlog_size=4096 --replicate-ignore-db=ignore_db diff -r 8fadb9f22d1c mysql-test/rpl_transaction_test/t/rpl_transaction_001.test --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mysql-test/rpl_transaction_test/t/rpl_transaction_001.test Fri Oct 17 02:50:16 2008 -0700 @@ -0,0 +1,47 @@ +source include/master-slave.inc; + +--disable_warnings +drop table if exists t1; +create table t1(n int primary key); +drop database if exists ignore_db; +create database ignore_db; +--enable_warnings + +use test; +insert into t1 values (700); + +use ignore_db; +create table ign1(n int primary key); +let $i=70; +while ($i) +{ + eval insert into ign1 values ($i); + dec $i; +} + +use test; +insert into t1 values (701); +let $i=50; +while ($i) +{ + eval insert into t1 values ($i); + dec $i; +} + + +save_master_pos; + +connection slave; +sync_with_master; + +select count(*) from t1; +--error 1146 +select * from ign1; + +connection master; +drop table t1; +drop database ignore_db; +save_master_pos; + +connection slave; +sync_with_master; diff -r 8fadb9f22d1c mysql-test/t/rpl_innodb_clear_status.test --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mysql-test/t/rpl_innodb_clear_status.test Fri Oct 17 02:50:16 2008 -0700 @@ -0,0 +1,48 @@ +--source include/have_innodb.inc +--source include/not_embedded.inc + +# Just be sure that nothing will bother us +create database mysqltest; +delete from mysql.user where user like 'mysqltest\_%'; +delete from mysql.db where user like 'mysqltest\_%'; +delete from mysql.tables_priv where user like 'mysqltest\_%'; +delete from mysql.columns_priv where user like 'mysqltest\_%'; +flush privileges; + +grant all on mysqltest.t1 to mysqltest_1@localhost; +# This ensures that counters are reset and makes test scheduling independent +flush user_resources; + +connect (con1,localhost,root,,); +connect (user1, localhost, mysqltest_1,,mysqltest); + +connection user1; +show variables like "innodb_clear_replication_status"; +SET innodb_clear_replication_status = 1; +show variables like "innodb_clear_replication_status"; + +connection con1; + +--disable_warnings +drop table if exists t1; +--enable_warnings + +show variables like "innodb_clear_replication_status"; +SET innodb_clear_replication_status = 1; +show variables like "innodb_clear_replication_status"; + +create table t1 (a int) Engine = InnoDB; +SET innodb_clear_replication_status = 0; +show variables like "innodb_clear_replication_status"; + +drop table t1; + +# Just be sure that nothing will bother us +delete from mysql.user where user like 'mysqltest\_%'; +delete from mysql.db where user like 'mysqltest\_%'; +delete from mysql.tables_priv where user like 'mysqltest\_%'; +delete from mysql.columns_priv where user like 'mysqltest\_%'; +flush privileges; + +disconnect user1; +drop database mysqltest; diff -r 8fadb9f22d1c sql/ha_innodb.cc --- a/sql/ha_innodb.cc Thu Oct 09 17:29:20 2008 -0700 +++ b/sql/ha_innodb.cc Fri Oct 17 02:50:16 2008 -0700 @@ -1514,31 +1514,57 @@ } /********************************************************************* -Commits a transaction in an InnoDB database. */ - -void -innobase_commit_low( -/*================*/ +Sets replication state for the current tx. */ + +static void +innobase_set_tx_replication_state( trx_t* trx) /* in: transaction handle */ { - if (trx->conc_state == TRX_NOT_STARTED) { - - return; - } - #ifdef HAVE_REPLICATION THD *thd=current_thd; if (thd && thd->slave_thread) { /* Update the replication position info inside InnoDB */ + + /* Unfortunately, we need all information here to recover + * replication slave execution status because events in + * BEGIN/COMMIT block do not carry the correct master-log + * position. + */ + trx->mysql_relay_log_file_name + = active_mi->rli.event_relay_log_name; + trx->mysql_relay_log_pos = ((ib_longlong) + active_mi->rli.future_event_relay_log_pos); trx->mysql_master_log_file_name = active_mi->rli.group_master_log_name; trx->mysql_master_log_pos = ((ib_longlong) active_mi->rli.future_group_master_log_pos); } + + /* In crash recovery scenarios we are here without a current_thd. + * Protect against getting a SIGSEGV. + */ + if (current_thd && + current_thd->variables.innodb_clear_replication_status) { + trx->clear_replication_status = TRUE; + } #endif /* HAVE_REPLICATION */ - +} + +/********************************************************************* +Commits a transaction in an InnoDB database. */ + +void +innobase_commit_low( +/*================*/ + trx_t* trx) /* in: transaction handle */ +{ + if (trx->conc_state == TRX_NOT_STARTED) { + + return; + } + innobase_set_tx_replication_state(trx); trx_commit_for_mysql(trx); } @@ -4900,8 +4926,12 @@ normalize_table_name(norm_name, name); + // Note, without this call, replications state will not be set during + // drop table and a slave will replay this tx on startup when it was the + // last one before shutdown. + innobase_set_tx_replication_state(trx); + /* Drop the table in InnoDB */ - error = row_drop_table_for_mysql(norm_name, trx, thd->lex->sql_command == SQLCOM_DROP_DB); @@ -4992,6 +5022,10 @@ srv_active_wake_master_thread(); + // Note, without this call, replications state will not be set and a slave + // will replay this tx on startup when it was the last one before shutdown. + innobase_set_tx_replication_state(trx); + innobase_commit_low(trx); trx_free_for_mysql(trx); @@ -5052,6 +5086,10 @@ normalize_table_name(norm_from, from); normalize_table_name(norm_to, to); + + // Note, without this call, replications state will not be set and a slave + // will replay this tx on startup when it was the last one before shutdown. + innobase_set_tx_replication_state(trx); /* Rename the table in InnoDB */ @@ -7350,4 +7388,77 @@ (cursor_view_t*) curview); } +char* +ha_innobase::get_mysql_relay_log_name() +{ + return(trx_sys_mysql_relay_log_name); +} + +ulonglong +ha_innobase::get_mysql_relay_log_pos() +{ + return(trx_sys_mysql_relay_log_pos); +} + +char* +ha_innobase::get_mysql_master_log_name() +{ + return(trx_sys_mysql_master_log_name); +} + +ulonglong +ha_innobase::get_mysql_master_log_pos() +{ + return(trx_sys_mysql_master_log_pos); +} + +void ha_innobase::print_mysql_relay_log_pos() { + trx_sys_print_mysql_relay_log_pos(FALSE); +} + +void ha_innobase::reset_mysql_relay_info() +{ + set_mysql_relay_info("", -1, "", -1); +} + +void ha_innobase::set_mysql_relay_info(const char *relay_log_name, + ulonglong relay_log_pos, + const char *master_log_name, + ulonglong master_log_pos) +{ + if (have_innodb != SHOW_OPTION_YES) + return; + + char buf1[22], buf2[22]; + sql_print_information("InnoDB replication info master log changed from " + "master '%s' position %s to '%s' position %s", + trx_sys_mysql_master_log_name, + llstr((longlong)trx_sys_mysql_master_log_pos, buf1), + master_log_name, + llstr((longlong)master_log_pos, buf2)); + sql_print_information("InnoDB replication info relay log changed from " + "'%s' position %s to '%s' position %s", + trx_sys_mysql_relay_log_name, + llstr((longlong)trx_sys_mysql_relay_log_pos, buf1), + relay_log_name, + llstr((longlong)relay_log_pos, buf2)); + + trx_sys_mysql_relay_log_pos = relay_log_pos; + trx_sys_mysql_master_log_pos = master_log_pos; + strmake(trx_sys_mysql_relay_log_name, + relay_log_name, strlen(relay_log_name)); + strmake(trx_sys_mysql_master_log_name, + master_log_name, strlen(master_log_name)); + + mtr_t mtr; + mtr_start_noninline(&mtr); + trx_sys_update_mysql_relay_offset(trx_sys_mysql_relay_log_name, + trx_sys_mysql_relay_log_pos, + trx_sys_mysql_master_log_name, + trx_sys_mysql_master_log_pos, + TRX_SYS_MYSQL_RELAY_INFO, &mtr, + TRUE); + mtr_commit(&mtr); +} + #endif /* HAVE_INNOBASE_DB */ diff -r 8fadb9f22d1c sql/ha_innodb.h --- a/sql/ha_innodb.h Thu Oct 09 17:29:20 2008 -0700 +++ b/sql/ha_innodb.h Fri Oct 17 02:50:16 2008 -0700 @@ -31,6 +31,7 @@ uint table_name_length,use_count; } INNOBASE_SHARE; +typedef struct trx_struct trx_t; my_bool innobase_query_caching_of_table_permitted(THD* thd, char* full_name, uint full_name_len, @@ -193,6 +194,29 @@ static ulonglong get_mysql_bin_log_pos(); bool primary_key_is_clustered() { return true; } int cmp_ref(const byte *ref1, const byte *ref2); + + // This is used to get replication slave's progress. + static char *get_mysql_relay_log_name(); + static ulonglong get_mysql_relay_log_pos(); + static char* get_mysql_master_log_name(); + static ulonglong get_mysql_master_log_pos(); + + /* Get the relay-log filename/position from transaction log. The + * function will read the current relay progress from InnoDB + * transaction log and update corresponding global variables. + * The above four functions will get the correct value after the + * call. + */ + static void print_mysql_relay_log_pos(); + + // Reset the relay-log info inside InnoDB + static void reset_mysql_relay_info(); + + static void set_mysql_relay_info(const char *relay_log_name, + ulonglong relay_log_pos, + const char *master_log_name, + ulonglong master_log_pos); + }; extern struct show_var_st innodb_status_variables[]; diff -r 8fadb9f22d1c sql/log.cc --- a/sql/log.cc Thu Oct 09 17:29:20 2008 -0700 +++ b/sql/log.cc Fri Oct 17 02:50:16 2008 -0700 @@ -32,6 +32,16 @@ #include "message.h" #endif +#ifdef HAVE_INNOBASE_DB +#include "ha_innodb.h" +#endif + + +/* The max InnoDB allowed replication binlog filename length: the value should + * be the same as TRX_SYS_MYSQL_RELAY_NAME_LEN. + */ +#define MAX_INNODB_BINLOG_FILENAME_LEN 250 + MYSQL_LOG mysql_log, mysql_slow_log, mysql_bin_log; ulong sync_binlog_counter= 0; @@ -46,6 +56,18 @@ static int binlog_commit(THD *thd, bool all); static int binlog_rollback(THD *thd, bool all); static int binlog_prepare(THD *thd, bool all); + +/* Queries with the correct log position in the event */ +struct QueryLogEvent { + const char *query_; + const int query_length_; +}; + +QueryLogEvent query_with_log[] = { + { "BEGIN", strlen("BEGIN") }, + { "COMMIT", strlen("COMMIT") } +}; + handlerton binlog_hton = { "binlog", @@ -681,6 +703,37 @@ goto err; bytes_written+= description_event_for_queue->data_written; } + + if (rpl_transaction_enabled) { + /* Check to make sure that filename is not longer than the limit inside + * InnoDB's transaction header. + */ + if (strlen(log_file_name) >= MAX_INNODB_BINLOG_FILENAME_LEN) { + sql_print_error("Too long binlog filename(%s) for InnoDB: %d bytes", + log_file_name, MAX_INNODB_BINLOG_FILENAME_LEN); + goto err; + } + + /* We need a special event in each relay-log file to make sure that each + * file always has the correct master-log information itself. + * So, we always write a Rotate_log_event with server_id as + * MASTER_INFO_SERVER_ID. at the beginning of the relay-log with the + * corresponding master-log information. + */ + MASTER_INFO *mi = get_master_info(); + if (mi != NULL && strlen(mi->master_log_name) > 0) { + Rotate_log_event + mi_event(current_thd, mi->master_log_name, + strlen(mi->master_log_name), mi->master_log_pos, 0); + mi_event.set_server_id(MASTER_INFO_SERVER_ID); + if (mi_event.write(&log_file)) { + sql_print_error("Could not write MASTER Rotate_log_event"); + goto err; + } + bytes_written += mi_event.data_written; + } + } + if (flush_io_cache(&log_file) || my_sync(log_file.file, MYF(MY_WME))) goto err; @@ -1303,6 +1356,13 @@ return !strcmp(log_file_name, log_file_name_arg); } +int MYSQL_LOG::close_index_file() { + if (my_b_inited(&index_file)) { + end_io_cache(&index_file); + my_close(index_file.file, MYF(0)); + } + return 0; +} /* Start writing to a new log file or reopen the old file @@ -2292,6 +2352,322 @@ DBUG_ENTER("MYSQL_LOG::signal_update"); pthread_cond_broadcast(&update_cond); DBUG_VOID_RETURN; +} + +bool MYSQL_LOG::extract_master_info(Log_event* ev, + char *master_log_name, + my_off_t *master_log_pos) { + bool extracted = false; + DBUG_ENTER("MYSQL_LOG::extract_master_info"); + + /* Some events always have correct master log information, like: + * . Xid_event, Master_info_log_event, Rotate_log_event, etc + * Some Query events have correct master log information (each query + * event only has one query inside), like BEGIN/COMMIT. + */ + switch (ev->get_type_code()) { + case QUERY_EVENT: { + Query_log_event *query = (Query_log_event *)ev; + + /* Check whether the query event has the correct master log information: + * if so, accept it. + */ + for (int idx = 0; idx < sizeof(query_with_log)/sizeof(QueryLogEvent); + ++idx) + if ((query->q_len == query_with_log[idx].query_length_ && + strncmp(query_with_log[idx].query_, query->query, + query->q_len) == 0)) { + *master_log_pos = query->log_pos; + extracted = true; + } + break; + } + case ROTATE_EVENT: + /* Because I/O thread can add rotate events for slave side purpose, + * like exceed file size limit, and those events would not carry the + * correct master side information, we skip them. + * Those events only have slave side information. + */ + if (ev->server_id != ::server_id) { + Rotate_log_event *rotate = (Rotate_log_event *)ev; + + /* Rotate_log_event from the master always indicates the correct + * information. + */ + strcpy(master_log_name, rotate->new_log_ident); + master_log_name[rotate->ident_len] = '\0'; + *master_log_pos = rotate->pos; + extracted = true; + } + break; + case XID_EVENT: + /* XID_EVENT is the same as COMMIT in relay-log. So, it carries the + * correct master log information. + */ + *master_log_pos = ev->log_pos; + extracted = true; + break; + case FORMAT_DESCRIPTION_EVENT: + /* Format event would not cause re-transmit the same event from the master, + * so we assume its position in relay-log is correct. + */ + extracted = true; + break; + default: + extracted = false; + break; + } + DBUG_RETURN(extracted); +} + +/* Whether we find the relay-log corresponding to the master-log + * information. + */ +bool MYSQL_LOG::find_master_pos_inlog(const char *relay_log_name, + ulonglong relay_log_pos, + const char *master_log_name, + ulonglong master_log_pos, + char *last_master_log_name, + ulonglong *last_master_log_pos, + bool *relay_file_error, + my_off_t *last_valid_offset, + my_off_t *relay_file_size, + const char **errmsg) { + IO_CACHE log_file; + DBUG_ENTER("MYSQL_LOG::find_master_pos_inlog"); + file_id = open_binlog(&log_file, relay_log_name, errmsg); + + // Note that File may be -1 and file_id is uint. + if ((File)file_id < 0) { + file_id = 0; // make is_valid() return false + *relay_file_error = true; + DBUG_RETURN(false); + } + + Format_description_log_event *desc_event = + new Format_description_log_event(3); + + for (;;) { + Log_event* ev = Log_event::read_log_event(&log_file, NULL, desc_event); + if (!ev) { + break; + } + + /* If the relay-log event has been executed by slave sql thread, then we + * can assume that the event is safe., strlen(master_log_name) + * update_master_info() might shrink the last relay-log to make sure that + * we would not re-append events. Then, we would re-transmit all events + * from the master. If the last relay-log gets shrinked, we need to make + * sure that re-appended relay-log is the same as the one before the + * shrink. Otherwise, the sql thread will get confused. + * + * TODO(wei): we still need to handle the situation that the last relay + * log is corrupted and the shrink point is before the execution point. + */ + my_off_t offset = my_b_tell(&log_file); + if (extract_master_info(ev, last_master_log_name, last_master_log_pos)) { + *last_valid_offset = offset; + } else if (offset == relay_log_pos) { + strmake(last_master_log_name, master_log_name, strlen(master_log_name)); + *last_master_log_pos = master_log_pos; + *last_valid_offset = offset; + } + + if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT) { + delete desc_event; + desc_event = (Format_description_log_event *)ev; + + /* If we have the correct last executed relay-log information, we can + * seek to the position after getting the correct format event. + */ + if (relay_log_pos != -1 && offset < relay_log_pos) { + my_b_seek(&log_file, relay_log_pos); + strmake(last_master_log_name, master_log_name, strlen(master_log_name)); + *last_master_log_pos = master_log_pos; + *last_valid_offset = relay_log_pos; + } + } else { + delete ev; + } + } + *relay_file_error = log_file.error; + if (relay_file_size) + *relay_file_size = my_b_tell(&log_file); + + my_close(file_id, MYF(MY_WME)); + end_io_cache(&log_file); + delete desc_event; + + DBUG_RETURN(!(*relay_file_error)); +} + +int MYSQL_LOG::update_master_info(const char *relay_log_name, + ulonglong relay_log_pos, + const char *master_log_name, + ulonglong master_log_pos, + bool *need_check_master_log, + bool *found_relay_info) { + int error = 0; + LOG_INFO linfo; + char last_relay_log_name[FN_REFLEN]; + char last_master_log_name[FN_REFLEN]; + + MASTER_INFO* mi = get_master_info(); + const char *errmsg = NULL; + + my_off_t last_valid_off = 0, last_master_log_pos; + + bool found_relay_file = false; + bool relay_file_error = false; + my_off_t relay_file_size = 0; + bool relay_log_info_avail; // Whether the specified relay_log_name, + // relay_log_pos is available + + char buff1[22], buff2[22]; + + DBUG_ENTER("MYSQL_LOG::update_master_info"); + + *found_relay_info = false; + *need_check_master_log = false; + relay_log_info_avail = (strcmp(relay_log_name, "") != 0 && + relay_log_pos != -1); + strmake(last_master_log_name, "", FN_REFLEN); + + if (find_log_pos(&linfo, NullS, true)) { + /* This should be fine because we are going to retrieve all master-logs + * from scratch. + */ + ha_innobase::reset_mysql_relay_info(); + sql_print_information("update_master_info(): not found any relay-log file," + " will reset replication from scratch"); + + DBUG_RETURN(0); + } else { + /* Find the last replication relay-log filename in relay-log.info and + * find the specified is in relay-log.info. + */ + for (;;) { + // find the last log file from index_log_file + strmake(last_relay_log_name, linfo.log_file_name, FN_REFLEN); + last_relay_log_name[FN_REFLEN - 1] = '\0'; + + // check whether we found the specified relay-log file + if (relay_log_info_avail && !found_relay_file && + strcmp(last_relay_log_name, relay_log_name) == 0) { + found_relay_file = true; + } + if (find_next_log(&linfo, true)) + break; + } + } + + if (relay_log_info_avail && !found_relay_file) { + /* This might be totally wrong because we could not find the last executed + * relay-log based on InnoDB information. + * It might be normal that there is a relay-log switch which cause the old + * log purged. We need to check whether master-log information match + * relay-log.info. + */ + *need_check_master_log = true; + } + + if (relay_log_info_avail && + strcmp(relay_log_name, last_relay_log_name) == 0) { + if (!find_master_pos_inlog(relay_log_name, relay_log_pos, + master_log_name, master_log_pos, + last_master_log_name, &last_master_log_pos, + &relay_file_error, &last_valid_off, + &relay_file_size, &errmsg)) { + // We could not read the relay-log file correctly. + sql_print_information("update_master_info(): open relay-log(%s) error %s", + relay_log_name, errmsg); + DBUG_RETURN(1); + } + } else { + if (!find_master_pos_inlog(last_relay_log_name, -1, NULL, -1, + last_master_log_name, &last_master_log_pos, + &relay_file_error, &last_valid_off, + &relay_file_size, &errmsg)) { + // We could not read the relay-log file correctly. + sql_print_information("update_master_info(): open relay-log(%s) error %s", + last_relay_log_name, errmsg); + DBUG_RETURN(1); + } + } + + /* If we do not find master-log reading information from all valid events, + * we assume that the information in file master.log is correct based on + * the protocol: we always write to file master.info before writing events + * into relay-log. + */ + if (strlen(last_master_log_name) > 0) { + DBUG_PRINT("info",("found master log_file_name: '%s' position: %s", + last_master_log_name, + llstr(last_master_log_pos, buff1))); + + // truncate the log to the last valid event + if (relay_file_error || last_valid_off != relay_file_size) { + File trunc_file_id = my_open(last_relay_log_name, O_WRONLY, MYF(MY_WME)); + if (trunc_file_id < 0) { + + sql_print_error("Slave I/O thread: open file '%s' for " + "truncation failed; error: %d", + last_relay_log_name, errno); + DBUG_RETURN(1); + } + + /* We might truncate the last file less than relay-log.info indicates the + * file should be. This is fine because we going to create a new + * relay-log file after this one and the sql thread will be directed to + * the new file to read relay events. + */ + off_t new_len = (off_t)last_valid_off; + if (ftruncate(trunc_file_id, new_len)) { + + sql_print_error("Slave I/O thread: truncate file(%s) from %s to %s; " + "error: %d\n", last_relay_log_name, + llstr(relay_file_size, buff1), + llstr(new_len, buff2), errno); + my_close(trunc_file_id, MYF(MY_WME)); + + DBUG_RETURN(1); + } + my_close(trunc_file_id, MYF(MY_WME)); + + sql_print_information("Slave I/O thread: truncated file(%s) from %s to %s", + last_relay_log_name, llstr(relay_file_size, buff1), + llstr(new_len, buff2)); + } + + /* update master-log reading header */ + if (strcmp(mi->master_log_name, last_master_log_name) != 0 || + mi->master_log_pos != last_master_log_pos) { + sql_print_information("Slave I/O thread: adjust master reading header:\n" + "\tOld: file:'%s', position:%s\n" + "\tNew: file:'%s', position:%s", + mi->master_log_name, llstr(mi->master_log_pos, buff1), + last_master_log_name, + llstr(last_master_log_pos, buff2)); + strcpy(mi->master_log_name, last_master_log_name); + mi->master_log_pos = last_master_log_pos; + } + + /* We must write the file to disk here even there are no changes because the + * after MYSQL_LOG::open() might create a new relay-log file. + */ + reinit_io_cache(&mi->file, WRITE_CACHE, 0L, 0, 1); + if ((error=test(flush_master_info(mi, 0)))) { + sql_print_error("Failed to flush master info file during adjustment"); + } else { + error = my_sync(mi->file.file, MYF(MY_WME)); + } + } else if (relay_log_info_avail) { + sql_print_warning("Not find master information from the last relay-log: " + "assume that master.info is correct"); + } + + *found_relay_info = relay_log_info_avail; + DBUG_RETURN(error); } #ifdef __NT__ diff -r 8fadb9f22d1c sql/log_event.h --- a/sql/log_event.h Thu Oct 09 17:29:20 2008 -0700 +++ b/sql/log_event.h Fri Oct 17 02:50:16 2008 -0700 @@ -94,6 +94,14 @@ #define LINE_TERM_EMPTY 0x4 #define LINE_START_EMPTY 0x8 #define ESCAPED_EMPTY 0x10 + +/* This server-id value is used to indicate a special master-info event + * in relay-log. + * We will enforce in database that replication can not set this value + * as the server-id. + */ +#define MASTER_INFO_SERVER_ID 0xffffffff + /***************************************************************************** @@ -702,6 +710,9 @@ *description_event); /* returns the human readable name of the event's type */ const char* get_type_str(); + inline void set_server_id(uint32 id) { + server_id = id; + } }; /* diff -r 8fadb9f22d1c sql/mysql_priv.h --- a/sql/mysql_priv.h Thu Oct 09 17:29:20 2008 -0700 +++ b/sql/mysql_priv.h Fri Oct 17 02:50:16 2008 -0700 @@ -1746,7 +1746,13 @@ #define unireg_abort(exit_code) DBUG_RETURN(exit_code) inline void kill_delayed_threads(void) {} #define check_stack_overrun(A, B, C) 0 -#endif +#endif + +/* The variable indicating whether the transaction support in replication + * is enabled. + */ +extern my_bool rpl_transaction_enabled; + #endif /* MYSQL_CLIENT */ diff -r 8fadb9f22d1c sql/mysqld.cc --- a/sql/mysqld.cc Thu Oct 09 17:29:20 2008 -0700 +++ b/sql/mysqld.cc Fri Oct 17 02:50:16 2008 -0700 @@ -566,6 +566,9 @@ static my_socket unix_sock,ip_sock; struct rand_struct sql_rand; // used by sql_class.cc:THD::THD() + +/* When set, transactional replication is enabled */ +my_bool rpl_transaction_enabled; /* OS specific variables */ @@ -4819,6 +4822,8 @@ OPT_PORT_OPEN_TIMEOUT, OPT_MERGE, OPT_INNODB_ROLLBACK_ON_TIMEOUT, + OPT_RPL_TRANX_ENABLED, + OPT_INNODB_CLEAR_REPLICATION_STATUS, OPT_SECURE_FILE_PRIV }; @@ -5038,6 +5043,12 @@ {"innodb_checksums", OPT_INNODB_CHECKSUMS, "Enable InnoDB checksums validation (enabled by default). \ Disable with --skip-innodb-checksums.", (gptr*) &innobase_use_checksums, (gptr*) &innobase_use_checksums, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"innodb_clear_replication_status", OPT_INNODB_CLEAR_REPLICATION_STATUS, + "Let the next InnoDB statement clear the replication status inside " + "the transaction log(only available to super users).", + (gptr*) &global_system_variables.innodb_clear_replication_status, + (gptr*) &global_system_variables.innodb_clear_replication_status, + 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, #endif {"innodb_data_file_path", OPT_INNODB_DATA_FILE_PATH, "Path to individual files and their sizes.", @@ -5457,6 +5468,10 @@ {"rpl-recovery-rank", OPT_RPL_RECOVERY_RANK, "Undocumented.", (gptr*) &rpl_recovery_rank, (gptr*) &rpl_recovery_rank, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"rpl_transaction_enabled", OPT_RPL_TRANX_ENABLED, + "1 = replication has transaction support. 0 = no special transaction support", + (gptr*) &rpl_transaction_enabled, + (gptr*) &rpl_transaction_enabled, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0}, {"safe-mode", OPT_SAFE, "Skip some optimize stages (for testing).", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifndef TO_BE_DELETED @@ -6372,6 +6387,7 @@ #endif /*HAVE_QUERY_CACHE*/ {"Questions", (char*) 0, SHOW_QUESTION}, {"Rpl_status", (char*) 0, SHOW_RPL_STATUS}, + {"Rpl_transaction_support", (char*) &rpl_transaction_enabled, SHOW_BOOL}, {"Select_full_join", (char*) offsetof(STATUS_VAR, select_full_join_count), SHOW_LONG_STATUS}, {"Select_full_range_join", (char*) offsetof(STATUS_VAR, select_full_range_join_count), SHOW_LONG_STATUS}, {"Select_range", (char*) offsetof(STATUS_VAR, select_range_count), SHOW_LONG_STATUS}, diff -r 8fadb9f22d1c sql/set_var.cc --- a/sql/set_var.cc Thu Oct 09 17:29:20 2008 -0700 +++ b/sql/set_var.cc Fri Oct 17 02:50:16 2008 -0700 @@ -96,6 +96,7 @@ static int check_pseudo_thread_id(THD *thd, set_var *var); static bool set_log_bin(THD *thd, set_var *var); static void fix_low_priority_updates(THD *thd, enum_var_type type); +static void fix_innodb_clear_replication_status(THD *thd, enum_var_type type); static void fix_tx_isolation(THD *thd, enum_var_type type); static int check_completion_type(THD *thd, set_var *var); static void fix_completion_type(THD *thd, enum_var_type type); @@ -321,6 +322,8 @@ #endif sys_var_long_ptr sys_rpl_recovery_rank("rpl_recovery_rank", &rpl_recovery_rank); +sys_var_bool_ptr sys_rpl_transaction_enabled("rpl_transaction_enabled", + &rpl_transaction_enabled); sys_var_long_ptr sys_query_cache_size("query_cache_size", &query_cache_size, fix_query_cache_size); @@ -442,6 +445,10 @@ &SV::innodb_support_xa); sys_var_long_ptr sys_innodb_autoextend_increment("innodb_autoextend_increment", &srv_auto_extend_increment); +sys_var_thd_bool sys_innodb_clear_replication_status( + "innodb_clear_replication_status", + &SV::innodb_clear_replication_status, + fix_innodb_clear_replication_status); sys_var_long_ptr sys_innodb_sync_spin_loops("innodb_sync_spin_loops", &srv_n_spin_wait_rounds); sys_var_long_ptr sys_innodb_concurrency_tickets("innodb_concurrency_tickets", @@ -723,6 +730,7 @@ &sys_relay_log_purge, #endif &sys_rpl_recovery_rank, + &sys_rpl_transaction_enabled, &sys_safe_updates, &sys_secure_auth, &sys_secure_file_priv, @@ -781,6 +789,7 @@ &sys_innodb_support_xa, &sys_innodb_max_purge_lag, &sys_innodb_autoextend_increment, + &sys_innodb_clear_replication_status, &sys_innodb_sync_spin_loops, &sys_innodb_concurrency_tickets, &sys_innodb_thread_sleep_delay, @@ -891,6 +900,8 @@ {"innodb_buffer_pool_awe_mem_mb", (char*) &innobase_buffer_pool_awe_mem_mb, SHOW_LONG }, {"innodb_buffer_pool_size", (char*) &innobase_buffer_pool_size, SHOW_LONGLONG }, {"innodb_checksums", (char*) &innobase_use_checksums, SHOW_MY_BOOL}, + {sys_innodb_clear_replication_status.name, + (char*) &sys_innodb_clear_replication_status, SHOW_SYS}, {sys_innodb_commit_concurrency.name, (char*) &sys_innodb_commit_concurrency, SHOW_SYS}, {sys_innodb_concurrency_tickets.name, (char*) &sys_innodb_concurrency_tickets, SHOW_SYS}, {"innodb_data_file_path", (char*) &innobase_data_file_path, SHOW_CHAR_PTR}, @@ -1038,6 +1049,8 @@ {"relay_log_space_limit", (char*) &relay_log_space_limit, SHOW_LONGLONG}, #endif {sys_rpl_recovery_rank.name,(char*) &sys_rpl_recovery_rank, SHOW_SYS}, + {sys_rpl_transaction_enabled.name, + (char *) &sys_rpl_transaction_enabled, SHOW_SYS}, {"secure_auth", (char*) &sys_secure_auth, SHOW_SYS}, {"secure_file_priv", (char*) &sys_secure_file_priv, SHOW_SYS}, #ifdef HAVE_SMEM @@ -1235,6 +1248,12 @@ TL_WRITE_LOW_PRIORITY : TL_WRITE); } +static void fix_innodb_clear_replication_status(THD *thd, enum_var_type type) +{ + /* Only super users can set "innodb_clear_replication_status" variable. */ + if (check_global_access(thd, SUPER_ACL) != 0) + thd->variables.innodb_clear_replication_status = false; +} static void fix_myisam_max_sort_file_size(THD *thd, enum_var_type type) diff -r 8fadb9f22d1c sql/slave.cc --- a/sql/slave.cc Thu Oct 09 17:29:20 2008 -0700 +++ b/sql/slave.cc Fri Oct 17 02:50:16 2008 -0700 @@ -26,6 +26,10 @@ #include #include #include + +#ifdef HAVE_INNOBASE_DB +#include "ha_innodb.h" +#endif #define MAX_SLAVE_RETRY_PAUSE 5 bool use_slave_mask = 0; @@ -1713,6 +1717,95 @@ rli->log_space_limit= relay_log_space_limit; rli->log_space_total= 0; + /* During transactional replication, we need to adjust the reading header + * of both the I/O thread and SQL thread. + * We store the replication process in InnoDB's transaction log. We will + * use the information to do the recovery to do both I/O thread and SQL + * thread adjustment. + */ + + char group_relay_log_name[FN_REFLEN], + group_master_log_name[FN_REFLEN]; + char *last_relay_log_name = NULL; + my_off_t group_master_log_pos, group_relay_log_pos; + bool found_relay_info; + bool need_check_master_log; + + strmake(group_relay_log_name, "", FN_REFLEN); + group_relay_log_pos = (my_off_t)-1; + found_relay_info = false; + need_check_master_log = false; + + if (rpl_transaction_enabled) { + /* data structure initialization */ + rli->relay_log.set_master_info(active_mi); + + if (ha_innobase::get_mysql_relay_log_pos() == -1) { + sql_print_information("replication_load_relay_commit(): no adjustment" + " from InnoDB."); + } else { + const char *name; + char llbuf1[22], llbuf2[22]; + + /* update_master_info() might truncate relay-log to avoid re-appending + * already appended events during a crash. We do not want to truncate + * before the sql thread has committed. Otherwise, the sql thread will + * get confused. We read the commit information in InnoDB transaction log + * to make sure that truncation would not operate before the point. + */ + name = ha_innobase::get_mysql_relay_log_name(); + strmake(group_relay_log_name, name, strlen(name)); + group_relay_log_pos = ha_innobase::get_mysql_relay_log_pos(); + + name = ha_innobase::get_mysql_master_log_name(); + strmake(group_master_log_name, name, strlen(name)); + group_master_log_pos = ha_innobase::get_mysql_master_log_pos(); + + sql_print_information("Replication status inside InnoDB: " + "relay-log['%s'(%s)], master-log['%s'(%s)]", + group_relay_log_name, + llstr(group_relay_log_pos, llbuf1), + group_master_log_name, + llstr(group_master_log_pos, llbuf2)); + } + + /* If InnoDB's transaction log does not have any information associated + * with replication progress, then do not adjust master.info. We + * only do best effort and trust master.info is correct. This can happen + * under two situations: + * - when we switch a database from an old binary to the new binary. + * - the database is a new copy or from a backup. + */ + if (strlen(group_relay_log_name) > 0 && group_relay_log_pos != -1) { + char buf[FN_REFLEN]; + const char *ln; + int error = 0; + + ln = rli->relay_log.generate_name(opt_relay_logname, "-relay-bin", + 1, buf); + if (rli->relay_log.open_index_file(opt_relaylog_index_name, ln)) { + sql_print_error("Failed in opening index file"); + error = 1; + } else { + error = + rli->relay_log.update_master_info(group_relay_log_name, + group_relay_log_pos, + group_master_log_name, + group_master_log_pos, + &need_check_master_log, + &found_relay_info); + if (error != 0) + sql_print_error("Failed in master_info transaction check"); + } + + rli->relay_log.close_index_file(); + if (error != 0) { + pthread_mutex_unlock(&rli->data_lock); + DBUG_RETURN(1); + } + } + } + /* The relay log will now be opened, as a SEQ_READ_APPEND IO_CACHE. Note that the I/O thread flushes it to disk after writing every @@ -1766,6 +1859,9 @@ } } + if (!rpl_transaction_enabled) + found_relay_info = !access(fname,F_OK); + /* if file does not exist */ if (access(fname,F_OK)) { @@ -1805,6 +1901,12 @@ else // file exists { error= 0; + char file_relay_log_name[FN_REFLEN], + file_master_log_name[FN_REFLEN]; + int file_master_log_pos; + int file_relay_log_pos = 0; + bool use_relay_info = 0, read_relay_info_fail = 0; + if (info_fd >= 0) reinit_io_cache(&rli->info_file, READ_CACHE, 0L,0,0); else @@ -1833,39 +1935,113 @@ DBUG_RETURN(1); } } - + + /* We are going to use relay-log.info under the following situations: + * . transaction support is not enabled + * . we did not find relay information from InnoDB + * . we found relay information from InnoDB, but we need to verify the + * information + */ + use_relay_info = + !rpl_transaction_enabled || !found_relay_info || need_check_master_log; + rli->info_fd = info_fd; - int relay_log_pos, master_log_pos; - if (init_strvar_from_file(rli->group_relay_log_name, - sizeof(rli->group_relay_log_name), + if (init_strvar_from_file(file_relay_log_name, + sizeof(file_relay_log_name), &rli->info_file, "") || - init_intvar_from_file(&relay_log_pos, - &rli->info_file, BIN_LOG_HEADER_SIZE) || - init_strvar_from_file(rli->group_master_log_name, - sizeof(rli->group_master_log_name), - &rli->info_file, "") || - init_intvar_from_file(&master_log_pos, &rli->info_file, 0)) - { - msg="Error reading slave log configuration"; - goto err; - } - strmake(rli->event_relay_log_name,rli->group_relay_log_name, + init_intvar_from_file(&file_relay_log_pos, + &rli->info_file, BIN_LOG_HEADER_SIZE) || + init_strvar_from_file(file_master_log_name, + sizeof(file_master_log_name), + &rli->info_file, "") || + init_intvar_from_file(&file_master_log_pos, &rli->info_file, 0)) + { + read_relay_info_fail = 1; + if (use_relay_info) { + msg="Error reading slave log configuration"; + goto err; + } + } + + if (read_relay_info_fail) { + sql_print_error("SQL thread read relay-log.info failed, ignored by " + "InnoDB transaction information."); + } else { + sql_print_information("Replication status inside relay-log.info: " + "relay-log['%s'(%d)], master-log['%s'(%d)]", + file_relay_log_name, file_relay_log_pos, + file_master_log_name, file_master_log_pos); + if (rpl_transaction_enabled && + (strlen(group_relay_log_name) > 0 && + group_relay_log_pos != -1) && + (strcmp(file_master_log_name, group_master_log_name) != 0 || + group_master_log_pos != (my_off_t)file_master_log_pos)) { + sql_print_error("Replication status mis-match between InnoDB and " + "relay-log.info: will take InnoDB status."); + } + } + + if (use_relay_info) { + if (need_check_master_log) { + char llbuf[22]; + + if (strcmp(file_master_log_name, group_master_log_name) != 0 || + group_master_log_pos != (my_off_t)file_master_log_pos) { + sql_print_error("InnoDB replication commit does not match" + " relay-log.info: innodb[%s(%s)], info[%s(%d)]", + group_master_log_name, + llstr(group_master_log_pos, llbuf), + file_master_log_name, file_master_log_pos); + goto err; + } else { + sql_print_information( + "InnoDB replication commit information is adjusted by" + " relay-log.info: innodb[%s(%s)], info[%s(%d)]", + group_relay_log_name, llstr(group_relay_log_pos, llbuf), + file_relay_log_name, file_relay_log_pos); + } + } + + strmake(group_relay_log_name, file_relay_log_name, + sizeof(group_relay_log_name)); + strmake(group_master_log_name, file_master_log_name, + sizeof(group_master_log_name)); + group_master_log_pos = file_master_log_pos; + group_relay_log_pos = file_relay_log_pos; + found_relay_info = true; + } + } + + if (found_relay_info) { + strmake(rli->event_relay_log_name, group_relay_log_name, sizeof(rli->event_relay_log_name)-1); - rli->group_relay_log_pos= rli->event_relay_log_pos= relay_log_pos; - rli->group_master_log_pos= master_log_pos; + strmake(rli->group_master_log_name, group_master_log_name, + sizeof(rli->group_master_log_name)-1); + rli->future_event_relay_log_pos = group_relay_log_pos; + rli->future_group_master_log_pos = group_master_log_pos; + rli->group_master_log_pos = group_master_log_pos; if (init_relay_log_pos(rli, - rli->group_relay_log_name, - rli->group_relay_log_pos, + rli->event_relay_log_name, + rli->future_event_relay_log_pos, 0 /* no data lock*/, - &msg, 0)) + &msg, 1 /*look for a description_event*/)) { char llbuf[22]; sql_print_error("Failed to open the relay log '%s' (relay_log_pos %s)", - rli->group_relay_log_name, - llstr(rli->group_relay_log_pos, llbuf)); - goto err; - } + rli->event_relay_log_name, + llstr(rli->future_event_relay_log_pos, llbuf)); + goto err; + } + } else { /* not finding relay-info */ + /* Init relay log with first entry in the relay index file */ + if (init_relay_log_pos(rli,NullS,BIN_LOG_HEADER_SIZE,0 /* no data lock */, + &msg, 1 /*look for a description_event*/)) { + sql_print_error("Failed to open the relay log 'FIRST' (relay_log_pos 4)"); + goto err; + } + rli->group_master_log_name[0]= 0; + rli->future_group_master_log_pos= 0; } #ifndef DBUG_OFF @@ -2261,6 +2437,11 @@ mi->port= (uint) port; mi->connect_retry= (uint) connect_retry; mi->ssl= (my_bool) ssl; + + char llbuff[22]; + sql_print_information("Read master.info: log_file_name: %s, pos: %s", + mi->master_log_name, + llstr(mi->master_log_pos, llbuff)); } DBUG_PRINT("master_info",("log_file_name: %s position: %ld", mi->master_log_name, @@ -2269,6 +2450,19 @@ mi->rli.mi = mi; if (init_relay_log_info(&mi->rli, slave_info_fname)) goto err; + + /* This is purely a sanity check to make sure everything is fine. */ + if (strcmp(mi->master_log_name, mi->rli.group_master_log_name) == 0 && + mi->master_log_pos > 0 && + mi->master_log_pos < mi->rli.future_group_master_log_pos) { + char llbuf1[22], llbuf2[22]; + + sql_print_error("SQL thread(%s) is ahead of I/O thread(%s): %s", + llstr(mi->rli.future_group_master_log_pos, llbuf2), + llstr(mi->master_log_pos, llbuf1), + mi->master_log_name); + goto err; + } mi->inited = 1; // now change cache READ -> WRITE - must do this before flush_master_info @@ -3786,7 +3980,7 @@ pthread_handler_t handle_slave_sql(void *arg) { THD *thd; /* needs to be first for thread_stack */ - char llbuff[22],llbuff1[22]; + char llbuff[22],llbuff1[22],llbuff2[22]; RELAY_LOG_INFO* rli = &((MASTER_INFO*)arg)->rli; const char *errmsg; @@ -3903,8 +4097,9 @@ llstr(rli->group_master_log_pos,llbuff))); if (global_system_variables.log_warnings) sql_print_information("Slave SQL thread initialized, starting replication in \ -log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME, - llstr(rli->group_master_log_pos,llbuff),rli->group_relay_log_name, +log '%s' at position %s and %s, relay log '%s' position: %s", RPL_LOG_NAME, + llstr(rli->future_group_master_log_pos,llbuff), + llstr(rli->group_master_log_pos,llbuff2),rli->group_relay_log_name, llstr(rli->group_relay_log_pos,llbuff1)); /* execute init_slave variable */ @@ -3944,6 +4139,15 @@ RPL_LOG_NAME, llstr(rli->group_master_log_pos,llbuff)); err: + /* + Last event executed may not have been a commit. Ensure InnoDB's state + is accurate. + */ + ha_innobase::set_mysql_relay_info(rli->group_relay_log_name, + rli->group_relay_log_pos, + rli->group_master_log_name, + rli->group_master_log_pos); + VOID(pthread_mutex_lock(&LOCK_thread_count)); /* Some extra safety, which should not been needed (normally, event deletion @@ -4280,6 +4484,12 @@ inc_pos= event_len; break; } + + /* We must update mi->master_log_pos before calling append() because a new + * relay-log need correct master position for transactional replicaiton. + */ + mi->master_log_pos+= inc_pos; + if (likely(!ignore_event)) { if (ev->log_pos) @@ -4292,12 +4502,12 @@ { delete ev; pthread_mutex_unlock(&mi->data_lock); + mi->master_log_pos-= inc_pos; DBUG_RETURN(1); } rli->relay_log.harvest_bytes_written(&rli->log_space_total); } delete ev; - mi->master_log_pos+= inc_pos; DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos)); pthread_mutex_unlock(&mi->data_lock); DBUG_RETURN(0); @@ -4344,15 +4554,21 @@ inc_pos= event_len; break; } + + /* We must update mi->master_log_pos before calling append() because a new + * relay-log need correct master position for transactional replicaiton. + */ + mi->master_log_pos+= inc_pos; + if (unlikely(rli->relay_log.append(ev))) { delete ev; pthread_mutex_unlock(&mi->data_lock); + mi->master_log_pos-= inc_pos; DBUG_RETURN(1); } rli->relay_log.harvest_bytes_written(&rli->log_space_total); delete ev; - mi->master_log_pos+= inc_pos; err: DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos)); pthread_mutex_unlock(&mi->data_lock); @@ -4531,15 +4747,21 @@ } else { + /* We must update mi->master_log_pos before calling appendv() because a new + * relay-log need correct master position for transactional replicaiton. + */ + mi->master_log_pos+= inc_pos; + /* write the event to the relay log */ if (likely(!(rli->relay_log.appendv(buf,event_len,0)))) { - mi->master_log_pos+= inc_pos; DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos)); rli->relay_log.harvest_bytes_written(&rli->log_space_total); } - else + else { error= 3; + mi->master_log_pos-= inc_pos; + } rli->ign_master_log_name_end[0]= 0; // last event is not ignored } pthread_mutex_unlock(log_lock); @@ -5011,8 +5233,50 @@ DBUG_ASSERT(rli->cur_log_fd >= 0); my_close(rli->cur_log_fd, MYF(MY_WME)); rli->cur_log_fd = -1; - - if (relay_log_purge) + + bool do_purge_log = relay_log_purge; + + if (rpl_transaction_enabled && do_purge_log) { + /* Get the relay-log execution process from InnoDB. */ + ha_innobase::print_mysql_relay_log_pos(); + + /* We can not purge files if InnoDB's replication status is + * different to relay-log.info. If we purge the file and stop + * the replication after the purge, then the replication can not + * continue because the file corresponding to InnoDB status is + * purged. We have to defer the purge during the situation. + * + * The following reasons can cause mis-match, which prevents from + * purging the relay-log files: + * . DDL/DML on non-InnoDB tables + * . ignore option in replication + * . rotate statements + * + * Also, we can not purge inside a begin/commit block. + */ + if ((!(thd->options & OPTION_BEGIN)) && + (strlen(ha_innobase::get_mysql_master_log_name()) > 0 && + ha_innobase::get_mysql_master_log_pos() != -1) && + (strcmp(rli->group_master_log_name, + ha_innobase::get_mysql_master_log_name()) == 0 && + rli->future_group_master_log_pos == + ha_innobase::get_mysql_master_log_pos())) { + /* Delete all files before the current one in case previous + * purges left some undelete ones. + */ + if (rli->relay_log.purge_logs( + rli->group_relay_log_name, 0, 1, 0, + &rli->log_space_total) != 0 || + rli->relay_log.find_log_pos(&rli->linfo, NullS, 1) != 0) { + errmsg = "Error purging old logs"; + goto err; + } + } else { + do_purge_log = false; + } + } + + if (do_purge_log) { /* purge_first_log will properly set up relay log coordinates in rli. diff -r 8fadb9f22d1c sql/sql_class.h --- a/sql/sql_class.h Thu Oct 09 17:29:20 2008 -0700 +++ b/sql/sql_class.h Fri Oct 17 02:50:16 2008 -0700 @@ -176,6 +176,7 @@ #define RP_FORCE_ROTATE 2 class Log_event; +typedef struct st_master_info MASTER_INFO; /* TODO split MYSQL_LOG into base MYSQL_LOG and @@ -231,6 +232,71 @@ */ bool no_auto_events; friend class Log_event; + // If true, the log will have sequence numbers appended to the filename, + // and will increment each time the log are flushed. If false, it will + // simply reopen the same filename. + bool is_sequenced; + + /* whether the log is associated with master-log's reading */ + MASTER_INFO *active_mi_; + + /* Find the master-log information specifed by relay-log position; find the + * last valid event in the relay-log. + * If the index file is missing the corresponding relay-log file, it means + * that the user has reset the replication and wants to start from scratch + * again. + * + * Input: + * relay_log_name - (IN) the relay log filename to be opened + * relay_log_pos - (IN) the relay log committed position + * (if -1, no commit information is available) + * master_log_name - (IN) master-log filename corresponding to relay pos + * master_log_pos - (IN) master-log position corresponding to relay pos + * last_master_log_name - (OUT) last valid master-log filename + * last_master_log_pos - (OUT) last valid master-log position + * relay_file_error - (OUT) whether there is relay file reading error + * last_valid_offset - (OUT) the last valid event's offset + * relay_file_size - (OUT) the relay-log file's size + * errmsg - (OUT) error message if there are any + * + * Returns: + * whether we encountered any log file openning errors + */ + bool find_master_pos_inlog(const char *relay_log_name, + ulonglong relay_log_pos, + const char *master_log_name, + ulonglong master_log_pos, + char *last_master_log_name, + ulonglong *last_master_log_pos, + bool *relay_file_error, + my_off_t *last_valid_offset, + my_off_t *relay_file_size, + const char **errmsg); + + /* Extract master-log's log filename and log position from the specified + * event if the information is guaranteed to be correct. + * + * Input: + * ev - (IN) the relay-log event to extract master information + * adjust_pos - (IN) the len of the event to adjust from end to begin + * master_log_name - (OUT) the extracted master's log name + * master_log_pos - (OUT) the extracted master's log position + * + * Return: + * true: the master-log information is extracted + * false: otherwise + * + */ + bool extract_master_info(Log_event* ev, char *master_log_name, + my_off_t *master_log_pos); + + /* Open the current sequence file */ + bool open_sequenced(const char *log_name, + enum_log_type log_type, + enum cache_type io_cache_type_arg, + bool no_auto_events_arg, ulong max_size, + bool null_created); + public: /* @@ -304,6 +370,7 @@ } bool open_index_file(const char *index_file_name_arg, const char *log_name); + int close_index_file(); void new_file(bool need_lock); bool write(THD *thd, enum enum_server_command command, const char *format, ...) ATTRIBUTE_FORMAT(printf, 4, 5); @@ -355,6 +422,34 @@ inline void unlock_index() { pthread_mutex_unlock(&LOCK_index);} inline IO_CACHE *get_index_file() { return &index_file;} inline uint32 get_open_count() { return open_count; } + void set_sequenced_flag(bool is_sequenced_arg); + + /* Update master-log's log filename and log position based on events in + * the last relay-log. + * + * Input: + * relay_log_name - (IN) replication's last committed relay-log name + * relay_log_pos - (IN) replication's last committed relay-log position + * master_log_name - (IN) replication's last committed master-log name + * master_log_pos - (IN) replication's last committed master-log position + * need_check_master_log - (OUT) whether we need to check with relay-log.info + * found_relay_info - (OUT) indicating the the relay-log information + * is valid + * Returns: + * whether encountered any errors during the function + */ + int update_master_info(const char *relay_log_name, + ulonglong relay_log_pos, + const char *master_log_name, + ulonglong master_log_pos, + bool *need_check_master_log, + bool *found_relay_info); + void set_master_info(MASTER_INFO *mi) { + active_mi_ = mi; + } + MASTER_INFO *get_master_info() { + return active_mi_; + } }; /* @@ -569,6 +664,7 @@ #ifdef HAVE_INNOBASE_DB my_bool innodb_table_locks; + my_bool innodb_clear_replication_status; my_bool innodb_support_xa; #endif /* HAVE_INNOBASE_DB */ #ifdef HAVE_NDBCLUSTER_DB diff -r 8fadb9f22d1c sql/sql_repl.cc --- a/sql/sql_repl.cc Thu Oct 09 17:29:20 2008 -0700 +++ b/sql/sql_repl.cc Fri Oct 17 02:50:16 2008 -0700 @@ -19,6 +19,9 @@ #include "sql_repl.h" #include "log_event.h" #include +#ifdef HAVE_INNOBASE_DB +#include "ha_innodb.h" +#endif int max_binlog_dump_events = 0; // unlimited my_bool opt_sporadic_binlog_dump_fail = 0; @@ -965,11 +968,6 @@ error=1; goto err; } - // delete relay logs, clear relay log coordinates - if ((error= purge_relay_logs(&mi->rli, thd, - 1 /* just reset */, - &errmsg))) - goto err; /* Clear master's log coordinates and reset host/user/etc to the values @@ -979,6 +977,13 @@ STATUS; before doing START SLAVE; */ init_master_info_with_options(mi); + + // delete relay logs, clear relay log coordinates + if ((error= purge_relay_logs(&mi->rli, thd, + 1 /* just reset */, + &errmsg))) + goto err; + /* Reset errors (the idea is that we forget about the old master). @@ -1002,6 +1007,11 @@ error=1; goto err; } + +#ifdef HAVE_INNOBASE_DB + if (have_innodb == SHOW_OPTION_YES && rpl_transaction_enabled) + ha_innobase::reset_mysql_relay_info(); +#endif err: unlock_slave_threads(mi); @@ -1262,6 +1272,24 @@ pthread_cond_broadcast(&mi->data_cond); pthread_mutex_unlock(&mi->rli.data_lock); +#ifdef HAVE_INNOBASE_DB + if (have_innodb == SHOW_OPTION_YES && rpl_transaction_enabled) + { + /* + If host is an empty string, that means the server is getting + promoted from a slave to a master. In that case, we want to + reset. + */ + if (!mi->host[0]) + ha_innobase::reset_mysql_relay_info(); + else + ha_innobase::set_mysql_relay_info(mi->rli.group_relay_log_name, + mi->rli.event_relay_log_pos, + mi->master_log_name, + mi->master_log_pos); + } +#endif + unlock_slave_threads(mi); thd->proc_info = 0; send_ok(thd);