diff -ruN base/client/mysqldump.c mysql40gpl/client/mysqldump.c --- base/client/mysqldump.c 2005-09-02 15:38:01.000000000 -0700 +++ mysql40gpl/client/mysqldump.c 2007-04-21 09:56:36.000000000 -0700 @@ -80,6 +80,7 @@ opt_delete_master_logs=0, tty_password=0, opt_single_transaction=0, opt_comments= 0, opt_hex_blob; +static my_bool opt_lossless_fp; static ulong opt_max_allowed_packet, opt_net_buffer_length; static MYSQL mysql_connection,*sock=0; static char insert_pat[12 * 1024],*opt_password=0,*current_user=0, @@ -256,6 +257,10 @@ (gptr*) &opt_net_buffer_length, (gptr*) &opt_net_buffer_length, 0, GET_ULONG, REQUIRED_ARG, 1024*1024L-1025, 4096, 16*1024L*1024L, MALLOC_OVERHEAD-1024, 1024, 0}, + {"lossless-fp", 'L', + "Convert double and float to decimal with extra precision so the reinserted values will be equal to the original values.", + (gptr*) &opt_lossless_fp, (gptr*) &opt_lossless_fp, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -611,6 +616,96 @@ return buff; } +/* + getSelectList - returns the select list in select_buf. Columns with type + double and float are wrapped with the function call IEEE754_TO_STRING. + Other columns are not wrapped with the function call. This is only needed + when --lossless-fp has been set. + RETURN + 0 on success +*/ + +static uint getSelectList(char *table, char *select_buf) +{ + char query_buf[1024]; + const char *func = "IEEE754_TO_STRING"; + // Include space for '(' and ')' + const int func_len = sizeof(func) + 2; + char quoted_table_name[NAME_LEN*2+3]; + char* quoted_table_ptr; + + quoted_table_ptr = quote_name(table, quoted_table_name, 1); + + // Use this to determine the datatypes and names of the fetched columns. + sprintf(query_buf, "SELECT * from %s limit 0", quoted_table_ptr); + + if (verbose) + fprintf(stderr, "-- Building select list from %s\n", query_buf); + + if (!mysql_query(sock, query_buf)) { + MYSQL_RES *query_result = mysql_store_result(sock); + MYSQL_ROW row; + int field_ix; + int num_fields; + int select_len = 0; + int select_ix = 0; + + if (!query_result) { + fprintf(stderr, + "-- Cannot get column types for table %s, mysql_store_result returns NULL: %s", + table, mysql_error(sock)); + mysql_free_result(query_result); + return 1; + } + if (mysql_errno(sock)) { + fprintf(stderr, + "-- Cannot get column types for table %s, error in mysql_store_result: %s", + table, mysql_error(sock)); + mysql_free_result(query_result); + return 1; + } + num_fields = mysql_num_fields(query_result); + if (num_fields <= 0) { + fprintf(stderr, + "-- Cannot get column types for table %s, no fields fetched", + table); + mysql_free_result(query_result); + return 1; + } + + // Determine the size of the select list. + for (field_ix = 0; field_ix < num_fields; ++field_ix) { + MYSQL_FIELD *field = mysql_fetch_field_direct(query_result, field_ix); + char quoted_name[NAME_LEN*2+3]; + char *name = quote_name(field->name, quoted_name, 0); + select_len += strlen(name) + 2; + if (field->type == FIELD_TYPE_FLOAT || field->type == FIELD_TYPE_DOUBLE) + select_len += func_len; + } + + // Generate the select list. + for (field_ix = 0; field_ix < num_fields; ++field_ix) { + MYSQL_FIELD *field = mysql_fetch_field_direct(query_result, field_ix); + char quoted_name[NAME_LEN*2+3]; + char *name = quote_name(field->name, quoted_name, 0); + if (field->type == FIELD_TYPE_FLOAT || field->type == FIELD_TYPE_DOUBLE) + select_ix += sprintf(select_buf + select_ix, "%s(%s)", func, name); + else + select_ix += sprintf(select_buf + select_ix, "%s", name); + if (field_ix < (num_fields - 1)) + select_ix += sprintf(select_buf + select_ix, ", "); + } + + mysql_free_result(query_result); + + if (verbose) + fprintf(stderr, "The select list for %s is %s", table, select_buf); + return 0; + } else { + fprintf(stderr, "Metadata query for %s failed: %s", table, mysql_error(sock)); + return 1; + } +} /* getStructure -- retrievs database structure, prints out corresponding @@ -990,6 +1085,7 @@ ulong rownr, row_break, total_length, init_length; const char *table_type; int error= 0; + char select_list[QUERY_LENGTH]; result_table= quote_name(table,table_buff, 1); opt_quoted_table= quote_name(table, table_buff2, 0); @@ -1004,6 +1100,11 @@ return; } + if (opt_lossless_fp) { + if (getSelectList(table, select_list)) + exit(EX_MYSQLERR); + } + if (verbose) fprintf(stderr, "-- Sending SELECT query...\n"); if (path) @@ -1015,8 +1116,13 @@ my_delete(filename, MYF(0)); /* 'INTO OUTFILE' doesn't work, if filename wasn't deleted */ to_unix_path(filename); - sprintf(query, "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '%s'", - filename); + if (!opt_lossless_fp) { + sprintf(query, "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '%s'", + filename); + } else { + sprintf(query, "SELECT /*!40001 SQL_NO_CACHE */ %s INTO OUTFILE '%s'", + select_list, filename); + } end= strend(query); if (replace) end= strmov(end, " REPLACE"); @@ -1050,8 +1156,13 @@ if (!opt_xml && opt_comments) fprintf(md_result_file,"\n--\n-- Dumping data for table %s\n--\n", result_table); - sprintf(query, "SELECT /*!40001 SQL_NO_CACHE */ * FROM %s", - result_table); + if (!opt_lossless_fp) { + sprintf(query, "SELECT /*!40001 SQL_NO_CACHE */ * FROM %s", + result_table); + } else { + sprintf(query, "SELECT /*!40001 SQL_NO_CACHE */ %s FROM %s", + select_list, result_table); + } if (where) { if (!opt_xml && opt_comments) diff -ruN base/configure mysql40gpl/configure --- base/configure 2005-09-02 15:38:41.000000000 -0700 +++ mysql40gpl/configure 2007-04-21 09:56:38.000000000 -0700 @@ -24767,8 +24767,8 @@ # Some system specific hacks # -MAX_C_OPTIMIZE="-O3" -MAX_CXX_OPTIMIZE="-O3" +MAX_C_OPTIMIZE="-O2" +MAX_CXX_OPTIMIZE="-O2" # workaround for Sun Forte/x86 see BUG#4681 case $SYSTEM_TYPE-$MACHINE_TYPE-$ac_cv_c_compiler_gnu in diff -ruN base/configure.in mysql40gpl/configure.in --- base/configure.in 2005-09-02 15:38:03.000000000 -0700 +++ mysql40gpl/configure.in 2007-04-21 09:56:38.000000000 -0700 @@ -941,8 +941,8 @@ # Some system specific hacks # -MAX_C_OPTIMIZE="-O3" -MAX_CXX_OPTIMIZE="-O3" +MAX_C_OPTIMIZE="-O2" +MAX_CXX_OPTIMIZE="-O2" # workaround for Sun Forte/x86 see BUG#4681 case $SYSTEM_TYPE-$MACHINE_TYPE-$ac_cv_prog_gcc in diff -ruN base/include/hash.h mysql40gpl/include/hash.h --- base/include/hash.h 2005-09-02 15:38:00.000000000 -0700 +++ mysql40gpl/include/hash.h 2007-04-21 09:56:39.000000000 -0700 @@ -43,10 +43,11 @@ uint (*calc_hashnr)(const byte *key,uint length); } HASH; -#define hash_init(A,B,C,D,E,F,G) _hash_init(A,B,C,D,E,F,G CALLER_INFO) -my_bool _hash_init(HASH *hash,uint default_array_elements, uint key_offset, - uint key_length, hash_get_key get_key, - void (*free_element)(void*), uint flags CALLER_INFO_PROTO); +#define hash_init(A,B,C,D,E,F,G) _hash_init(A,B,0,C,D,E,F,G CALLER_INFO) +#define hash_init2(A,B,C,D,E,F,G,H) _hash_init(A,B,C,D,E,F,G,H CALLER_INFO) +my_bool _hash_init(HASH *hash,uint default_array_elements, uint growth_size, + uint key_offset, uint key_length, hash_get_key get_key, + void (*free_element)(void*), uint flags CALLER_INFO_PROTO); void hash_free(HASH *tree); byte *hash_element(HASH *hash,uint idx); gptr hash_search(HASH *info,const byte *key,uint length); diff -ruN base/include/my_global.h mysql40gpl/include/my_global.h --- base/include/my_global.h 2005-09-02 15:37:55.000000000 -0700 +++ mysql40gpl/include/my_global.h 2007-04-21 09:56:40.000000000 -0700 @@ -388,7 +388,10 @@ #define my_reinterpret_cast(A) (A) #define my_const_cast(A) (A) #endif -#if !defined(__attribute__) && (defined(__cplusplus) || !defined(__GNUC__) || __GNUC__ == 2 && __GNUC_MINOR__ < 8) +#if !defined(__attribute__) && \ + (!defined(__GNUC__) || \ + (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || \ + (defined(__cplusplus) && (__GNUC__ < 3 || __GNUC__ == 3 && __GNUC_MINOR__ < 4))) #define __attribute__(A) #endif diff -ruN base/include/mysql_com.h mysql40gpl/include/mysql_com.h --- base/include/mysql_com.h 2005-09-02 15:38:09.000000000 -0700 +++ mysql40gpl/include/mysql_com.h 2007-04-21 12:28:27.000000000 -0700 @@ -71,6 +71,8 @@ thread */ #define REFRESH_MASTER 128 /* Remove all bin logs in the index and truncate the index */ +#define REFRESH_TABLE_STATS 256 /* Refresh table stats hash table */ +#define REFRESH_INDEX_STATS 512 /* Refresh index stats hash table */ /* The following can't be set with mysql_refresh() */ #define REFRESH_READ_LOCK 16384 /* Lock tables for read */ @@ -81,6 +83,7 @@ #define REFRESH_QUERY_CACHE_FREE 0x20000L /* pack query cache */ #define REFRESH_DES_KEY_FILE 0x40000L #define REFRESH_USER_RESOURCES 0x80000L +#define REFRESH_NO_PURGE_BINLOG 0x100000L #define CLIENT_LONG_PASSWORD 1 /* new more secure passwords */ #define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */ diff -ruN base/innobase/btr/btr0cur.c mysql40gpl/innobase/btr/btr0cur.c --- base/innobase/btr/btr0cur.c 2005-09-02 15:38:02.000000000 -0700 +++ mysql40gpl/innobase/btr/btr0cur.c 2007-04-21 09:56:40.000000000 -0700 @@ -54,7 +54,7 @@ /* When estimating number of different kay values in an index sample this many index pages */ -#define BTR_KEY_VAL_ESTIMATE_N_PAGES 8 +ulong btr_key_val_estimate_n_pages = 8; /* The structure of a BLOB part header */ /*--------------------------------------*/ @@ -2652,8 +2652,10 @@ ulint i; ulint j; ulint add_on; + ulint n_sample_pages; mtr_t mtr; + n_sample_pages = btr_key_val_estimate_n_pages; n_cols = dict_index_get_n_unique(index); n_diff = mem_alloc((n_cols + 1) * sizeof(ib_longlong)); @@ -2664,7 +2666,7 @@ /* We sample some pages in the index to get an estimate */ - for (i = 0; i < BTR_KEY_VAL_ESTIMATE_N_PAGES; i++) { + for (i = 0; i < n_sample_pages; i++) { mtr_start(&mtr); btr_cur_open_at_rnd_pos(index, BTR_SEARCH_LEAF, &cursor, &mtr); @@ -2732,7 +2734,7 @@ } /* If we saw k borders between different key values on - BTR_KEY_VAL_ESTIMATE_N_PAGES leaf pages, we can estimate how many + n_sample_pages leaf pages, we can estimate how many there will be in index->stat_n_leaf_pages */ /* We must take into account that our sample actually represents @@ -2743,25 +2745,25 @@ index->stat_n_diff_key_vals[j] = (n_diff[j] * (ib_longlong)index->stat_n_leaf_pages - + BTR_KEY_VAL_ESTIMATE_N_PAGES - 1 + + n_sample_pages - 1 + total_external_size + not_empty_flag) - / (BTR_KEY_VAL_ESTIMATE_N_PAGES + / (n_sample_pages + total_external_size); /* If the tree is small, smaller than < - 10 * BTR_KEY_VAL_ESTIMATE_N_PAGES + total_external_size, then + 10 * n_sample_pages + total_external_size, then the above estimate is ok. For bigger trees it is common that we do not see any borders between key values in the few pages - we pick. But still there may be BTR_KEY_VAL_ESTIMATE_N_PAGES + we pick. But still there may be n_sample_pages different key values, or even more. Let us try to approximate that: */ add_on = index->stat_n_leaf_pages / - (10 * (BTR_KEY_VAL_ESTIMATE_N_PAGES + total_external_size)); + (10 * (n_sample_pages + total_external_size)); - if (add_on > BTR_KEY_VAL_ESTIMATE_N_PAGES) { - add_on = BTR_KEY_VAL_ESTIMATE_N_PAGES; + if (add_on > n_sample_pages) { + add_on = n_sample_pages; } index->stat_n_diff_key_vals[j] += add_on; diff -ruN base/innobase/buf/buf0flu.c mysql40gpl/innobase/buf/buf0flu.c --- base/innobase/buf/buf0flu.c 2005-09-02 15:38:01.000000000 -0700 +++ mysql40gpl/innobase/buf/buf0flu.c 2007-04-21 09:56:40.000000000 -0700 @@ -323,7 +323,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 @@ -362,7 +362,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: */ @@ -469,7 +469,8 @@ stderr); #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 -ruN base/innobase/fil/fil0fil.c mysql40gpl/innobase/fil/fil0fil.c --- base/innobase/fil/fil0fil.c 2005-09-02 15:37:59.000000000 -0700 +++ mysql40gpl/innobase/fil/fil0fil.c 2007-04-21 09:56:40.000000000 -0700 @@ -154,6 +154,7 @@ n_open_pending < max_n_open */ 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 file system. This variable is NULL before the module is initialized. */ @@ -442,6 +443,11 @@ UT_LIST_INIT(system->space_list); + { + int x; + for (x = 0; x < FLUSH_FROM_NUMBER; ++x) + system->flush_types[x] = 0; + } return(system); } @@ -459,6 +465,23 @@ } /******************************************************************** +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]); +} + +/******************************************************************** Writes the flushed lsn to the header of each file space. */ void @@ -1047,7 +1070,7 @@ *actual_increase = i * ((1024 * 1024) / UNIV_PAGE_SIZE); - fil_flush(0); + fil_flush(0, FLUSH_FROM_OTHER); srv_data_file_sizes[srv_n_data_files - 1] += *actual_increase; @@ -1372,8 +1395,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; @@ -1381,7 +1405,6 @@ os_file_t file; mutex_enter(&(system->mutex)); - HASH_SEARCH(hash, system->spaces, space_id, space, space->id == space_id); ut_a(space); @@ -1411,6 +1434,7 @@ /* fprintf(stderr, "Flushing to file %s\n", node->name); */ + system->flush_types[flush_type]++; os_file_flush(file); mutex_enter(&(system->mutex)); @@ -1435,7 +1459,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; @@ -1448,7 +1473,7 @@ if (space->purpose == purpose) { mutex_exit(&(system->mutex)); - fil_flush(space->id); + fil_flush(space->id, flush_type); mutex_enter(&(system->mutex)); } diff -ruN base/innobase/include/fil0fil.h mysql40gpl/innobase/include/fil0fil.h --- base/innobase/include/fil0fil.h 2005-09-02 15:37:55.000000000 -0700 +++ mysql40gpl/innobase/include/fil0fil.h 2007-04-21 09:56:42.000000000 -0700 @@ -119,6 +119,13 @@ /*=====*/ ulint max_n_open); /* in: max number of open files */ /******************************************************************** +Prints internal counters. */ + +void +fil_print( +/*=====*/ + FILE* file); /* in: output stream */ +/******************************************************************** Initializes the ibuf indexes at a database start. This can be called after the file space headers have been created and the dictionary system has been initialized. */ @@ -327,13 +334,25 @@ 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. */ 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. */ @@ -341,7 +360,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 file system. */ diff -ruN base/innobase/include/log0log.h mysql40gpl/innobase/include/log0log.h --- base/innobase/include/log0log.h 2005-09-02 15:37:55.000000000 -0700 +++ mysql40gpl/innobase/include/log0log.h 2007-04-21 09:56:42.000000000 -0700 @@ -142,6 +142,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 @@ -155,9 +171,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 the caller */ /******************************************************************** Does a syncronous flush of the log buffer to disk. */ @@ -165,6 +182,13 @@ 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 buffer pool and also may make a new checkpoint. NOTE: this function may only be called if the calling thread owns no synchronization objects! */ @@ -734,6 +758,14 @@ 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 + a sync of the log file is done */ + ulint n_syncs; /* number of times fsync was done for + the 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 -ruN base/innobase/include/os0file.h mysql40gpl/innobase/include/os0file.h --- base/innobase/include/os0file.h 2005-09-02 15:38:01.000000000 -0700 +++ mysql40gpl/innobase/include/os0file.h 2007-04-21 09:56:42.000000000 -0700 @@ -292,22 +292,17 @@ offset */ ulint n); /* in: number of bytes to write */ /**************************************************************************** -Initializes the asynchronous io system. Creates separate aio array for -non-ibuf read and write, a third aio array for the ibuf i/o, with just one -segment, two aio arrays for log reads and writes with one segment, and a -synchronous aio array of the specified size. The combined number of segments -in the three first aio arrays is the parameter n_segments given to the -function. The caller must create an i/o handler thread for each segment in -the four first arrays, but not for the sync aio array. */ +Initializes the asynchronous io system. */ -void +ulint os_aio_init( /*========*/ - ulint n, /* in: maximum number of pending aio operations - allowed; n must be divisible by n_segments */ - ulint n_segments, /* in: combined number of segments in the four - first aio arrays; must be >= 4 */ - ulint n_slots_sync); /* in: number of slots in the sync aio array */ + /* out: number of AIO handler threads */ + ulint ios_per_array, /* in: maximum number of pending aio operations + allowed per IO array */ + ulint n_read_threads, /* in: number of read threads */ + ulint n_write_threads, /* in: number of write threads */ + ulint n_slots_sync); /* in: number of slots in the sync aio array */ /*********************************************************************** Requests an asynchronous i/o operation. */ diff -ruN base/innobase/include/srv0srv.h mysql40gpl/innobase/include/srv0srv.h --- base/innobase/include/srv0srv.h 2005-09-02 15:37:59.000000000 -0700 +++ mysql40gpl/innobase/include/srv0srv.h 2007-04-21 09:56:43.000000000 -0700 @@ -73,6 +73,8 @@ extern ulint srv_lock_table_size; extern ulint srv_n_file_io_threads; +extern ulint srv_n_read_io_threads; +extern ulint srv_n_write_io_threads; extern ibool srv_archive_recovery; extern dulint srv_archive_recovery_limit_lsn; @@ -426,4 +428,3 @@ extern ulint srv_n_threads_active[]; #endif - diff -ruN base/innobase/include/trx0sys.h mysql40gpl/innobase/include/trx0sys.h --- base/innobase/include/trx0sys.h 2005-09-02 15:38:00.000000000 -0700 +++ mysql40gpl/innobase/include/trx0sys.h 2007-04-21 09:56:44.000000000 -0700 @@ -36,11 +36,13 @@ trx_sys_mark_downgraded_from_4_1_1(void); /*====================================*/ -/* 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; @@ -261,6 +263,21 @@ 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 */ + /********************************************************************* Prints to stderr the MySQL binlog offset info in the trx system header if the magic number shows it valid. */ @@ -279,12 +296,18 @@ 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. + +Only when print_msg is TRUE, we print the offset to stderr. Otherwise, we +only retrieve the offset from the transaction log. +*/ 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 */ @@ -325,7 +348,54 @@ /* 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 -ruN base/innobase/include/trx0trx.h mysql40gpl/innobase/include/trx0trx.h --- base/innobase/include/trx0trx.h 2005-09-02 15:38:01.000000000 -0700 +++ mysql40gpl/innobase/include/trx0trx.h 2007-04-21 09:56:44.000000000 -0700 @@ -311,7 +311,7 @@ when the session is freed; in addition there may be session-less transactions rolling back after a database recovery */ -struct trx_struct{ +struct trx_struct { ulint magic_n; /* All the next fields are protected by the kernel mutex, except the undo logs which are protected by undo_mutex */ @@ -532,6 +532,36 @@ trx_undo_arr_t* undo_no_arr; /* array of undo numbers of undo log records which are currently processed by a rollback operation */ + + 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 */ + + char* repl_wait_binlog_name; + /* semi-synchronous binlog waiting + filename */ + + ib_longlong repl_wait_binlog_pos; + /* semi-synchronous binlog waiting + log position. */ }; #define TRX_MAX_N_THREADS 32 /* maximum number of concurrent diff -ruN base/innobase/log/log0log.c mysql40gpl/innobase/log/log0log.c --- base/innobase/log/log0log.c 2005-09-02 15:37:59.000000000 -0700 +++ mysql40gpl/innobase/log/log0log.c 2007-04-21 09:56:44.000000000 -0700 @@ -747,6 +747,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); @@ -1015,7 +1024,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); } if (log_debug_writes) { @@ -1036,7 +1045,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)); @@ -1234,9 +1243,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; @@ -1246,6 +1256,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) */ @@ -1395,13 +1406,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)); @@ -1450,10 +1465,34 @@ 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. */ static @@ -1481,7 +1520,8 @@ 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); } } @@ -1840,11 +1880,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)); @@ -1857,7 +1897,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)); @@ -2482,7 +2523,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)); @@ -2563,7 +2604,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; @@ -3046,8 +3088,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 next fil_write_... will pass the buffer pool: therefore it is essential that the buffer pool has been completely flushed @@ -3081,7 +3123,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); /* Make some checks that the server really is quiet */ ut_a(srv_n_threads_active[SRV_MASTER] == 0); @@ -3194,15 +3236,47 @@ 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", + "%lu log i/o's done, %.2f log i/o's/second, %lu syncs, %lu checkpoints\n", log_sys->n_pending_writes, log_sys->n_pending_checkpoint_writes, log_sys->n_log_ios, - (log_sys->n_log_ios - log_sys->n_log_ios_old) / time_elapsed); + (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 -ruN base/innobase/log/log0recv.c mysql40gpl/innobase/log/log0recv.c --- base/innobase/log/log0recv.c 2005-09-02 15:37:59.000000000 -0700 +++ mysql40gpl/innobase/log/log0recv.c 2007-04-21 09:56:44.000000000 -0700 @@ -2703,6 +2703,8 @@ return(DB_SUCCESS); } +extern my_bool rpl_transaction_enabled; + /************************************************************ Completes recovery from a checkpoint. */ @@ -2723,13 +2725,22 @@ recv_apply_hashed_log_recs(TRUE); } + 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 (log_debug_writes) { fprintf(stderr, "InnoDB: Log records applied to the database\n"); } if (recv_needed_recovery) { - trx_sys_print_mysql_master_log_pos(); trx_sys_print_mysql_binlog_offset(); } diff -ruN base/innobase/os/os0file.c mysql40gpl/innobase/os/os0file.c --- base/innobase/os/os0file.c 2005-09-02 15:38:00.000000000 -0700 +++ mysql40gpl/innobase/os/os0file.c 2007-04-21 09:56:45.000000000 -0700 @@ -14,6 +14,8 @@ #include "fil0fil.h" #include "buf0buf.h" +extern long innobase_max_merged_io; + #undef HAVE_FDATASYNC #ifdef POSIX_ASYNC_IO @@ -52,6 +54,28 @@ ibool os_aio_print_debug = FALSE; +/* State for the state of an IO request in simulated AIO. + Protocol for simulated aio: + client requests IO: find slot with reserved = FALSE. Add entry with + status = OS_AIO_NOT_ISSUED. + IO thread wakes: find adjacent slots with reserved = TRUE and status = + OS_AIO_NOT_ISSUED. Change status for slots to + OS_AIO_ISSUED. + IO operation completes: set status for slots to OS_AIO_DONE. set status + for the first slot to OS_AIO_CLAIMED and return + result for that slot. + When there are multiple read and write threads, they all compete to execute + the requests in the array (os_aio_array_t). This avoids the need to load + balance requests at the time the request is made at the cost of waking all + threads when a request is available. +*/ +typedef enum { + OS_AIO_NOT_ISSUED, /* Available to be processed by an IO thread. */ + OS_AIO_ISSUED, /* Being processed by an IO thread. */ + OS_AIO_DONE, /* Request processed. */ + OS_AIO_CLAIMED /* Result being returned to client. */ +} os_aio_status; + /* The aio array slot structure */ typedef struct os_aio_slot_struct os_aio_slot_t; @@ -60,6 +84,9 @@ ulint pos; /* index of the slot in the aio array */ ibool reserved; /* TRUE if this slot is reserved */ + os_aio_status status; /* Status for current request. Valid + when reserved = TRUE. Used only in + simulated aio. */ time_t reservation_time;/* time when reserved */ ulint len; /* length of the block to read or write */ @@ -70,11 +97,6 @@ ulint offset_high; /* 32 high bits of file offset */ os_file_t file; /* file where to read or write */ char* name; /* file name or path */ - ibool io_already_done;/* used only in simulated aio: - TRUE if the physical i/o already - made and only the slot message - needs to be passed to the caller - of os_aio_simulated_handle */ void* message1; /* message which is given by the */ void* message2; /* the requester of an aio operation and which can be used to identify @@ -104,9 +126,6 @@ in this array */ ulint n_slots; /* Total number of slots in the aio array. This must be divisible by n_threads. */ - ulint n_segments;/* Number of segments in the aio array of - pending aio requests. A thread can wait - separately for any one of the segments. */ ulint n_reserved;/* Number of reserved slots in the aio array outside the ibuf segment */ os_aio_slot_t* slots; /* Pointer to the slots in the array */ @@ -123,6 +142,17 @@ /* Array of events used in simulated aio */ os_event_t* os_aio_segment_wait_events = NULL; +/* Number of threads for reading and writing. */ +ulint os_aio_read_threads = 0; +ulint os_aio_write_threads = 0; + +/* Number for the first global segment for reading. */ +const ulint os_aio_first_read_segment = 2; + +/* Number for the first global segment for writing. Set to +2 + os_aio_read_write_threads. */ +ulint os_aio_first_write_segment = 0; + /* The aio arrays for non-ibuf i/o and ibuf i/o, as well as sync aio. These are NULL when the module has not yet been initialized. */ os_aio_array_t* os_aio_read_array = NULL; @@ -131,10 +161,35 @@ os_aio_array_t* os_aio_log_array = NULL; os_aio_array_t* os_aio_sync_array = NULL; +/* Per thread buffer used for merged IO requests. Used by +os_aio_simulated_handle so that a buffer doesn't have to be allocated +for each request. */ +static char* os_aio_thread_buffer[SRV_MAX_N_IO_THREADS]; +static ulint os_aio_thread_buffer_size[SRV_MAX_N_IO_THREADS]; + +/* Count pages read and written per thread */ +static ulint os_aio_thread_io_reads[SRV_MAX_N_IO_THREADS]; +static ulint os_aio_thread_io_writes[SRV_MAX_N_IO_THREADS]; + +/* Number of IO operations done. One request can be for N pages. */ +static ulint os_aio_thread_io_requests[SRV_MAX_N_IO_THREADS]; + +/* usecs spent blocked on an IO request */ +static double os_aio_thread_io_wait[SRV_MAX_N_IO_THREADS]; +/* max usecs spent blocked on an IO request */ +static double os_aio_thread_max_io_wait[SRV_MAX_N_IO_THREADS]; + +/* Number of IO global segments. An IO handler thread is created for each +global segment, except for the segment associated with os_aio_sync_array. +Several segments can be associated with os_aio_{read,write}_array. One +segment is created for each of the other arrays. This is also the number +of valid entries in srv_io_thread_reads, srv_io_thread_writes, +srv_io_thread_op_info, srv_io_thread_function and os_aio_segment_wait_events. */ ulint os_aio_n_segments = ULINT_UNDEFINED; -/* If the following is TRUE, read i/o handler threads try to -wait until a batch of new read requests have been posted */ +/* Set to TRUE to temporarily block reads from being scheduled while a batch +of read requests is added to allow them to be merged by the IO handler thread +if they are adjacent. */ ibool os_aio_recommend_sleep_for_read_threads = FALSE; ulint os_n_file_reads = 0; @@ -154,6 +209,19 @@ ulint os_file_n_pending_preads = 0; ulint os_file_n_pending_pwrites = 0; +static double timeusecs() { +#ifdef __WIN__ + return 0.0; +#else + struct timeval tv; + if (gettimeofday(&tv, NULL)) + return 0; + else { + return tv.tv_sec * 1000000.0 + tv.tv_usec; + } +#endif +} + /*************************************************************************** Gets the operating system version. Currently works only on Windows. */ @@ -828,7 +896,7 @@ if (type != OS_LOG_FILE && srv_unix_file_flush_method == SRV_UNIX_O_DIRECT) { -/* fprintf(stderr, "Using O_DIRECT for file %s\n", name); */ + fprintf(stderr, "Using O_DIRECT for file %s\n", name); create_flag = create_flag | O_DIRECT; } @@ -1115,13 +1183,21 @@ #else int ret; + + if (srv_unix_file_flush_method != SRV_UNIX_NOSYNC) { #ifdef HAVE_FDATASYNC - ret = fdatasync(file); + ret = fdatasync(file); #else /* fprintf(stderr, "Flushing to file %p\n", file); */ - ret = fsync(file); + ret = fsync(file); #endif - os_n_fsyncs++; + os_n_fsyncs++; + } else { + /* It is dangerous to set this option. If the server crashes, + it is likely that the InnoDB datafile will be corrupt. It can be + used during restore. */ + ret = 0; + } if (ret == 0) { return(TRUE); @@ -1397,6 +1473,9 @@ return(TRUE); } + fprintf(stderr, +"InnoDB: error: os_file_pread wanted %lu and got %lu.\n", + (ulint) n, (ulint) ret); #endif #ifdef __WIN__ error_handling: @@ -1605,9 +1684,8 @@ os_aio_array_create( /*================*/ /* out, own: aio array */ - ulint n, /* in: maximum number of pending aio operations - allowed; n must be divisible by n_segments */ - ulint n_segments) /* in: number of segments in the aio array */ + ulint n) /* in: maximum number of pending aio operations + allowed */ { os_aio_array_t* array; ulint i; @@ -1616,7 +1694,6 @@ OVERLAPPED* over; #endif ut_a(n > 0); - ut_a(n_segments > 0); array = ut_malloc(sizeof(os_aio_array_t)); @@ -1627,7 +1704,6 @@ os_event_set(array->is_empty); array->n_slots = n; - array->n_segments = n_segments; array->n_reserved = 0; array->slots = ut_malloc(n * sizeof(os_aio_slot_t)); #ifdef __WIN__ @@ -1654,70 +1730,75 @@ /**************************************************************************** Initializes the asynchronous io system. Calls also os_io_init_simple. -Creates a separate aio array for -non-ibuf read and write, a third aio array for the ibuf i/o, with just one -segment, two aio arrays for log reads and writes with one segment, and a -synchronous aio array of the specified size. The combined number of segments -in the three first aio arrays is the parameter n_segments given to the -function. The caller must create an i/o handler thread for each segment in -the four first arrays, but not for the sync aio array. */ +Creates an aio array for each of non-ibuf read, non-ibuf write, ibuf IO, +log IO, and synchronous IO. The caller must create i/o handler thread for all +but the synchronous aio array. Multiple threads can access the same array for +the non-ibuf read (prefetch) and write (flush dirty buffer pages) arrays. +Return the number of AIO handler threads. */ -void +ulint os_aio_init( /*========*/ - ulint n, /* in: maximum number of pending aio operations - allowed; n must be divisible by n_segments */ - ulint n_segments, /* in: combined number of segments in the four - first aio arrays; must be >= 4 */ + ulint ios_per_array, /* in: maximum number of pending aio operations + allowed per array */ + ulint n_read_threads, /* in: number of read threads */ + ulint n_write_threads, /* in: number of write threads */ ulint n_slots_sync) /* in: number of slots in the sync aio array */ { - ulint n_read_segs; - ulint n_write_segs; - ulint n_per_seg; ulint i; + ulint n_segments = 2 + n_read_threads + n_write_threads; #ifdef POSIX_ASYNC_IO sigset_t sigset; #endif - ut_ad(n % n_segments == 0); - ut_ad(n_segments >= 4); + ut_a(ios_per_array >= OS_AIO_N_PENDING_IOS_PER_THREAD); + ut_a(n_read_threads >= 1 && n_read_threads <= 64); + ut_a(n_write_threads >= 1 && n_write_threads <= 64); os_io_init_simple(); for (i = 0; i < n_segments; i++) { srv_set_io_thread_op_info(i, "not started yet"); + os_aio_thread_io_reads[i] = 0; + os_aio_thread_io_writes[i] = 0; + os_aio_thread_io_requests[i] = 0; + os_aio_thread_buffer[i] = 0; + os_aio_thread_buffer_size[i] = 0; + os_aio_thread_io_wait[i] = 0; + os_aio_thread_max_io_wait[i] = 0; } - n_per_seg = n / n_segments; - n_write_segs = (n_segments - 2) / 2; - n_read_segs = n_segments - 2 - n_write_segs; - - /* fprintf(stderr, "Array n per seg %lu\n", n_per_seg); */ + os_aio_read_threads = n_read_threads; + os_aio_write_threads = n_write_threads; + os_aio_first_write_segment = os_aio_first_read_segment + + os_aio_read_threads; + + fprintf(stderr, + "InnoDB: ios_per_array %lu read threads %lu write threads %lu\n", + ios_per_array, os_aio_read_threads, os_aio_write_threads); - os_aio_ibuf_array = os_aio_array_create(n_per_seg, 1); + os_aio_ibuf_array = os_aio_array_create(ios_per_array); srv_io_thread_function[0] = "insert buffer thread"; - os_aio_log_array = os_aio_array_create(n_per_seg, 1); + os_aio_log_array = os_aio_array_create(ios_per_array); srv_io_thread_function[1] = "log thread"; - os_aio_read_array = os_aio_array_create(n_read_segs * n_per_seg, - n_read_segs); - for (i = 2; i < 2 + n_read_segs; i++) { + os_aio_read_array = os_aio_array_create(ios_per_array); + for (i = os_aio_first_read_segment; i < os_aio_first_write_segment; i++) { ut_a(i < SRV_MAX_N_IO_THREADS); srv_io_thread_function[i] = "read thread"; } - os_aio_write_array = os_aio_array_create(n_write_segs * n_per_seg, - n_write_segs); - for (i = 2 + n_read_segs; i < n_segments; i++) { + os_aio_write_array = os_aio_array_create(ios_per_array); + for (i = os_aio_first_write_segment; i < n_segments; i++) { ut_a(i < SRV_MAX_N_IO_THREADS); srv_io_thread_function[i] = "write thread"; } - os_aio_sync_array = os_aio_array_create(n_slots_sync, 1); + os_aio_sync_array = os_aio_array_create(n_slots_sync); - os_aio_n_segments = n_segments; + os_aio_n_segments = 2 + os_aio_read_threads + os_aio_write_threads; os_aio_validate(); @@ -1745,6 +1826,7 @@ pthread_sigmask(SIG_BLOCK, &sigset, NULL); */ #endif + return os_aio_n_segments; } #ifdef WIN_ASYNC_IO @@ -1802,77 +1884,32 @@ os_event_wait(os_aio_write_array->is_empty); } -/************************************************************************** -Calculates segment number for a slot. */ -static -ulint -os_aio_get_segment_no_from_slot( -/*============================*/ - /* out: segment number (which is the number - used by, for example, i/o-handler threads) */ - os_aio_array_t* array, /* in: aio wait array */ - os_aio_slot_t* slot) /* in: slot in this array */ -{ - ulint segment; - ulint seg_len; - - if (array == os_aio_ibuf_array) { - segment = 0; - - } else if (array == os_aio_log_array) { - segment = 1; - - } else if (array == os_aio_read_array) { - seg_len = os_aio_read_array->n_slots / - os_aio_read_array->n_segments; - - segment = 2 + slot->pos / seg_len; - } else { - ut_a(array == os_aio_write_array); - seg_len = os_aio_write_array->n_slots / - os_aio_write_array->n_segments; - - segment = os_aio_read_array->n_segments + 2 - + slot->pos / seg_len; - } - - return(segment); -} /************************************************************************** -Calculates local segment number and aio array from global segment number. */ +Calculates aio array from global segment number. */ static -ulint -os_aio_get_array_and_local_segment( +os_aio_array_t* +os_aio_get_array( /*===============================*/ - /* out: local segment number within - the aio array */ - os_aio_array_t** array, /* out: aio wait array */ + /* out: aio wait array */ ulint global_segment)/* in: global segment number */ { - ulint segment; ut_a(global_segment < os_aio_n_segments); if (global_segment == 0) { - *array = os_aio_ibuf_array; - segment = 0; + return os_aio_ibuf_array; } else if (global_segment == 1) { - *array = os_aio_log_array; - segment = 0; + return os_aio_log_array; - } else if (global_segment < os_aio_read_array->n_segments + 2) { - *array = os_aio_read_array; + } else if (global_segment < os_aio_first_write_segment) { + return os_aio_read_array; - segment = global_segment - 2; } else { - *array = os_aio_write_array; + return os_aio_write_array; - segment = global_segment - (os_aio_read_array->n_segments + 2); } - - return(segment); } /*********************************************************************** @@ -2016,7 +2053,7 @@ slot->buf = buf; slot->offset = offset; slot->offset_high = offset_high; - slot->io_already_done = FALSE; + slot->status = OS_AIO_NOT_ISSUED; #ifdef WIN_ASYNC_IO control = &(slot->control); @@ -2067,8 +2104,9 @@ os_mutex_enter(array->mutex); ut_ad(slot->reserved); - + slot->reserved = FALSE; + slot->status = OS_AIO_NOT_ISSUED; array->n_reserved--; @@ -2097,24 +2135,23 @@ { os_aio_array_t* array; os_aio_slot_t* slot; - ulint segment; ulint n; ulint i; ut_ad(!os_aio_use_native_aio); - segment = os_aio_get_array_and_local_segment(&array, global_segment); + array = os_aio_get_array(global_segment); - n = array->n_slots / array->n_segments; + n = array->n_slots; - /* Look through n slots after the segment * n'th slot */ + /* Look through n slots */ os_mutex_enter(array->mutex); for (i = 0; i < n; i++) { - slot = os_aio_array_get_nth_slot(array, i + segment * n); + slot = os_aio_array_get_nth_slot(array, i ); - if (slot->reserved) { + if (slot->status == OS_AIO_NOT_ISSUED) { /* Found an i/o request */ break; @@ -2151,6 +2188,33 @@ } /************************************************************************** +Wake all handler threads for a given array. */ +static +void +os_aio_simulated_wake_handler_threads_for_array( +/*============================*/ + os_aio_array_t* array) /* in: aio wait array */ +{ + if (array == os_aio_ibuf_array) { + os_aio_simulated_wake_handler_thread(0); + + } else if (array == os_aio_log_array) { + os_aio_simulated_wake_handler_thread(1); + + } else if (array == os_aio_read_array) { + ulint x; + for (x = os_aio_first_read_segment; x < os_aio_first_write_segment; x++) + os_aio_simulated_wake_handler_thread(x); + + } else { + ut_a(array == os_aio_write_array); + ulint x; + for (x = os_aio_first_write_segment; x < os_aio_n_segments; x++) + os_aio_simulated_wake_handler_thread(x); + } +} + +/************************************************************************** This function can be called if one wants to post a batch of reads and prefers an i/o-handler thread to handle them all at once later. You must call os_aio_simulated_wake_handler_threads later to ensure the threads @@ -2160,18 +2224,13 @@ os_aio_simulated_put_read_threads_to_sleep(void) /*============================================*/ { - os_aio_array_t* array; ulint g; + /* TODO(mcallaghan): provide similar function for write? */ os_aio_recommend_sleep_for_read_threads = TRUE; - for (g = 0; g < os_aio_n_segments; g++) { - os_aio_get_array_and_local_segment(&array, g); - - if (array == os_aio_read_array) { - - os_event_reset(os_aio_segment_wait_events[g]); - } + for (g = os_aio_first_read_segment; g < os_aio_first_write_segment; g++) { + os_event_reset(os_aio_segment_wait_events[g]); } } @@ -2301,8 +2360,7 @@ #endif } else { if (!wake_later) { - os_aio_simulated_wake_handler_thread( - os_aio_get_segment_no_from_slot(array, slot)); + os_aio_simulated_wake_handler_threads_for_array(array); } } } else if (type == OS_FILE_WRITE) { @@ -2318,8 +2376,7 @@ #endif } else { if (!wake_later) { - os_aio_simulated_wake_handler_thread( - os_aio_get_segment_no_from_slot(array, slot)); + os_aio_simulated_wake_handler_threads_for_array(array); } } } else { @@ -2382,7 +2439,7 @@ os_aio_windows_handle( /*==================*/ /* out: TRUE if the aio operation succeeded */ - ulint segment, /* in: the number of the segment in the aio + ulint global_segment, /* in: the number of the segment in the aio arrays to wait for; segment 0 is the ibuf i/o thread, segment 1 the log i/o thread, then follow the non-ibuf read threads, and as @@ -2400,7 +2457,6 @@ void** message2, ulint* type) /* out: OS_FILE_WRITE or ..._READ */ { - ulint orig_seg = segment; os_aio_array_t* array; os_aio_slot_t* slot; ulint n; @@ -2409,33 +2465,30 @@ BOOL ret; DWORD len; - if (segment == ULINT_UNDEFINED) { + if (global_segment == ULINT_UNDEFINED) { array = os_aio_sync_array; - segment = 0; } else { - segment = os_aio_get_array_and_local_segment(&array, segment); + array = os_aio_get_array(global_segment); } /* NOTE! We only access constant fields in os_aio_array. Therefore we do not have to acquire the protecting mutex yet */ ut_ad(os_aio_validate()); - ut_ad(segment < array->n_segments); - n = array->n_slots / array->n_segments; + n = array->n_slots; if (array == os_aio_sync_array) { os_event_wait(os_aio_array_get_nth_slot(array, pos)->event); i = pos; } else { - srv_set_io_thread_op_info(orig_seg, "wait Windows aio"); - i = os_event_wait_multiple(n, - (array->native_events) + segment * n); + srv_set_io_thread_op_info(global_segment, "wait Windows aio"); + i = os_event_wait_multiple(n, (array->native_events)); } os_mutex_enter(array->mutex); - slot = os_aio_array_get_nth_slot(array, i + segment * n); + slot = os_aio_array_get_nth_slot(array, i); ut_a(slot->reserved); @@ -2573,7 +2626,6 @@ ulint* type) /* out: OS_FILE_WRITE or ..._READ */ { os_aio_array_t* array; - ulint segment; os_aio_slot_t* slot; os_aio_slot_t* slot2; os_aio_slot_t* consecutive_ios[OS_AIO_MERGE_N_CONSECUTIVE]; @@ -2589,8 +2641,10 @@ ulint n; ulint i; ulint len2; - - segment = os_aio_get_array_and_local_segment(&array, global_segment); + double start_usecs, stop_usecs; + time_t now; + + array = os_aio_get_array(global_segment); restart: /* NOTE! We only access constant fields in os_aio_array. Therefore @@ -2599,11 +2653,10 @@ srv_set_io_thread_op_info(global_segment, "looking for i/o requests (a)"); ut_ad(os_aio_validate()); - ut_ad(segment < array->n_segments); - n = array->n_slots / array->n_segments; + n = array->n_slots; - /* Look through n slots after the segment * n'th slot */ + /* Look through n slots */ if (array == os_aio_read_array && os_aio_recommend_sleep_for_read_threads) { @@ -2623,9 +2676,9 @@ done */ for (i = 0; i < n; i++) { - slot = os_aio_array_get_nth_slot(array, i + segment * n); + slot = os_aio_array_get_nth_slot(array, i); - if (slot->reserved && slot->io_already_done) { + if (slot->reserved && slot->status == OS_AIO_DONE) { if (os_aio_print_debug) { fprintf(stderr, @@ -2647,12 +2700,12 @@ biggest_age = 0; lowest_offset = ULINT_MAX; + now = time(NULL); for (i = 0; i < n; i++) { - slot = os_aio_array_get_nth_slot(array, i + segment * n); + slot = os_aio_array_get_nth_slot(array, i); - if (slot->reserved) { - age = (ulint)difftime(time(NULL), - slot->reservation_time); + if (slot->reserved && slot->status == OS_AIO_NOT_ISSUED) { + age = (ulint)difftime(now, slot->reservation_time); if ((age >= 2 && age > biggest_age) || (age >= 2 && age == biggest_age @@ -2677,10 +2730,11 @@ lowest_offset = ULINT_MAX; for (i = 0; i < n; i++) { - slot = os_aio_array_get_nth_slot(array, - i + segment * n); + slot = os_aio_array_get_nth_slot(array, i); - if (slot->reserved && slot->offset < lowest_offset) { + if (slot->reserved + && slot->offset < lowest_offset + && slot->status == OS_AIO_NOT_ISSUED) { /* Found an i/o request */ consecutive_ios[0] = slot; @@ -2705,7 +2759,7 @@ consecutive_loop: for (i = 0; i < n; i++) { - slot2 = os_aio_array_get_nth_slot(array, i + segment * n); + slot2 = os_aio_array_get_nth_slot(array, i); if (slot2->reserved && slot2 != slot && slot2->offset == slot->offset + slot->len @@ -2713,7 +2767,8 @@ sum does not wrap over */ && slot2->offset_high == slot->offset_high && slot2->type == slot->type - && slot2->file == slot->file) { + && slot2->file == slot->file + && slot2->status == OS_AIO_NOT_ISSUED) { /* Found a consecutive i/o request */ @@ -2722,7 +2777,8 @@ slot = slot2; - if (n_consecutive < OS_AIO_MERGE_N_CONSECUTIVE) { + if (n_consecutive < OS_AIO_MERGE_N_CONSECUTIVE + && n_consecutive < innobase_max_merged_io) { goto consecutive_loop; } else { @@ -2742,13 +2798,27 @@ for (i = 0; i < n_consecutive; i++) { total_len += consecutive_ios[i]->len; + ut_a(consecutive_ios[i]->status == OS_AIO_NOT_ISSUED); + consecutive_ios[i]->status = OS_AIO_ISSUED; } if (n_consecutive == 1) { /* We can use the buffer of the i/o request */ combined_buf = slot->buf; } else { - combined_buf2 = ut_malloc(total_len + UNIV_PAGE_SIZE); + if ((total_len + UNIV_PAGE_SIZE) > + os_aio_thread_buffer_size[global_segment]) { + + if (os_aio_thread_buffer[global_segment]) + ut_free(os_aio_thread_buffer[global_segment]); + + os_aio_thread_buffer[global_segment] = + ut_malloc(total_len + UNIV_PAGE_SIZE); + + os_aio_thread_buffer_size[global_segment] = + total_len + UNIV_PAGE_SIZE; + } + combined_buf2 = os_aio_thread_buffer[global_segment]; ut_a(combined_buf2); @@ -2759,6 +2829,9 @@ this assumes that there is just one i/o-handler thread serving a single segment of slots! */ + ut_a(slot->reserved); + ut_a(slot->status == OS_AIO_ISSUED); + os_mutex_exit(array->mutex); if (slot->type == OS_FILE_WRITE && n_consecutive > 1) { @@ -2784,6 +2857,7 @@ /* Do the i/o with ordinary, synchronous i/o functions: */ if (slot->type == OS_FILE_WRITE) { + os_aio_thread_io_writes[global_segment] += n_consecutive; if (array == os_aio_write_array) { if ((total_len % UNIV_PAGE_SIZE != 0) || (slot->offset % UNIV_PAGE_SIZE != 0)) { @@ -2817,13 +2891,21 @@ } } } - + start_usecs = timeusecs(); ret = os_file_write(slot->name, slot->file, combined_buf, slot->offset, slot->offset_high, total_len); + stop_usecs = timeusecs(); } else { + start_usecs = timeusecs(); + os_aio_thread_io_reads[global_segment] += n_consecutive; ret = os_file_read(slot->file, combined_buf, slot->offset, slot->offset_high, total_len); + stop_usecs = timeusecs(); } + if ((stop_usecs - start_usecs) > os_aio_thread_max_io_wait[global_segment]) + os_aio_thread_max_io_wait[global_segment] = stop_usecs - start_usecs; + os_aio_thread_io_wait[global_segment] += stop_usecs - start_usecs; + os_aio_thread_io_requests[global_segment]++; ut_a(ret); srv_set_io_thread_op_info(global_segment, "file i/o done"); @@ -2844,25 +2926,24 @@ } } - if (n_consecutive > 1) { - ut_free(combined_buf2); - } - os_mutex_enter(array->mutex); /* Mark the i/os done in slots */ for (i = 0; i < n_consecutive; i++) { - consecutive_ios[i]->io_already_done = TRUE; + ut_a(consecutive_ios[i]->status == OS_AIO_ISSUED); + consecutive_ios[i]->status = OS_AIO_DONE; } /* We return the messages for the first slot now, and if there were several slots, the messages will be returned with subsequent calls of this function */ - + slot_io_done: ut_a(slot->reserved); + ut_a(slot->status == OS_AIO_DONE); + slot->status = OS_AIO_CLAIMED; *message1 = slot->message1; *message2 = slot->message2; @@ -2917,7 +2998,6 @@ os_mutex_enter(array->mutex); ut_a(array->n_slots > 0); - ut_a(array->n_segments > 0); for (i = 0; i < array->n_slots; i++) { slot = os_aio_array_get_nth_slot(array, i); @@ -2968,10 +3048,18 @@ double avg_bytes_read; ulint i; - for (i = 0; i < srv_n_file_io_threads; i++) { - fprintf(file, "I/O thread %lu state: %s (%s)", i, - srv_io_thread_op_info[i], - srv_io_thread_function[i]); + for (i = 0; i < os_aio_n_segments; i++) { + fprintf(file, + "I/O thread %lu state: %s (%s) reads %lu writes %lu " + "requests %lu io secs %lf io msecs/request %lf max_io_wait %lf", + i, srv_io_thread_op_info[i], srv_io_thread_function[i], + os_aio_thread_io_reads[i], os_aio_thread_io_writes[i], + os_aio_thread_io_requests[i], + os_aio_thread_io_wait[i] / 1000000.0, + os_aio_thread_io_requests[i] ? + os_aio_thread_io_wait[i] / os_aio_thread_io_requests[i] / 1000.0 + : 0.0, + os_aio_thread_max_io_wait[i] / 1000.0); #ifndef __WIN__ if (os_aio_segment_wait_events[i]->is_set) { @@ -2991,7 +3079,6 @@ os_mutex_enter(array->mutex); ut_a(array->n_slots > 0); - ut_a(array->n_segments > 0); n_reserved = 0; diff -ruN base/innobase/srv/srv0srv.c mysql40gpl/innobase/srv/srv0srv.c --- base/innobase/srv/srv0srv.c 2005-09-02 15:37:58.000000000 -0700 +++ mysql40gpl/innobase/srv/srv0srv.c 2007-04-21 09:56:45.000000000 -0700 @@ -150,12 +150,17 @@ ulint srv_lock_table_size = ULINT_MAX; ulint srv_n_file_io_threads = ULINT_MAX; +ulint srv_n_read_io_threads = ULINT_MAX; +ulint srv_n_write_io_threads = ULINT_MAX; ibool srv_archive_recovery = 0; dulint srv_archive_recovery_limit_lsn; ulint srv_lock_wait_timeout = 1024 * 1024 * 1024; +// Counts number of lock wait timeouts. +ulint inno_lock_wait_timeouts = 0; + char* srv_file_flush_method_str = NULL; ulint srv_unix_file_flush_method = SRV_UNIX_FDATASYNC; ulint srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED; @@ -309,6 +314,23 @@ ulint srv_main_thread_process_no = 0; ulint srv_main_thread_id = 0; +// The following count work done by srv_master_thread. + +// Iterations by the 'once per second' loop. +ulint srv_main_1_second_loops = 0; +// Calls to sleep by the 'once per second' loop. +ulint srv_main_sleeps = 0; +// Iterations by the 'once per 10 seconds' loop. +ulint srv_main_10_second_loops = 0; +// Iterations of the loop bounded by the 'background_loop' label. +ulint srv_main_background_loops = 0; +// Iterations of the loop bounded by the 'flush_loop' label. +ulint srv_main_flush_loops = 0; +// Calls to log_buffer_flush_to_disk. +ulint srv_sync_flush = 0; +// Calls to log_buffer_flush_maybe_sync. +ulint srv_async_flush = 0; + /* IMPLEMENTATION OF THE SERVER MAIN PROGRAM ========================================= @@ -529,6 +551,24 @@ ulint srv_n_threads[SRV_MASTER + 1]; /************************************************************************* +Prints counters for work done by srv_master_thread. */ + +static +void +srv_print_extra( +/*===================*/ + FILE *file) /* in: output stream */ +{ + fprintf(file, "srv_master_thread loops: %lu 1_second, %lu sleeps, " + "%lu 10_second, %lu background, %lu flush\n", + srv_main_1_second_loops, srv_main_sleeps, + srv_main_10_second_loops, srv_main_background_loops, + srv_main_flush_loops); + fprintf(file, "srv_master_thread log flush: %lu sync, %lu async\n", + srv_sync_flush, srv_async_flush); +} + +/************************************************************************* Sets the info describing an i/o thread current state. */ void @@ -933,7 +973,7 @@ /* Too many threads inside: put the current thread to a queue */ - for (i = 0; i < OS_THREAD_MAX_N; i++) { + for (i = 0; i < OS_THREAD_MAX_N && !trx->always_enter_innodb; i++) { slot = srv_conc_slots + i; if (!slot->reserved) { @@ -941,13 +981,21 @@ } } - if (i == OS_THREAD_MAX_N) { - /* Could not find a free wait slot, we must let the + if (i == OS_THREAD_MAX_N || trx->always_enter_innodb) { + /* Could not find a free wait slot, OR we want the sql thread + to always enter innodb to improve replication, we must let the thread enter */ srv_conc_n_threads++; trx->declared_to_be_inside_innodb = TRUE; - trx->n_tickets_to_enter_innodb = 0; + + /* If the transaction can always enter innodb, give it enough + * tickets so that we would not check it again soon afterwards. + */ + if (trx->always_enter_innodb) + trx->n_tickets_to_enter_innodb = SRV_FREE_TICKETS_TO_ENTER; + else + trx->n_tickets_to_enter_innodb = 0; os_fast_mutex_unlock(&srv_conc_mutex); @@ -1452,8 +1500,15 @@ (ulong)time_elapsed); fputs("----------\n" + "BACKGROUND THREAD\n" + "----------\n", file); + srv_print_extra(file); + fil_print(file); + + fputs("----------\n" "SEMAPHORES\n" "----------\n", file); + fprintf(file, "Lock wait timeouts %lu\n", inno_lock_wait_timeouts); sync_print(file); /* Conceptually, srv_innodb_monitor_mutex has a very high latching @@ -1472,7 +1527,6 @@ mutex_exit(&dict_foreign_err_mutex); - lock_print_info(file); fputs("--------\n" "FILE I/O\n" "--------\n", file); @@ -1553,6 +1607,8 @@ srv_n_rows_deleted_old = srv_n_rows_deleted; srv_n_rows_read_old = srv_n_rows_read; + lock_print_info(file); + fputs("----------------------------\n" "END OF INNODB MONITOR OUTPUT\n" "============================\n", file); @@ -1702,6 +1758,7 @@ if (thr_get_trx(slot->thr)->wait_lock) { lock_cancel_waiting_and_release( thr_get_trx(slot->thr)->wait_lock); + ++inno_lock_wait_timeouts; } } } @@ -1938,11 +1995,13 @@ n_ios_old = log_sys->n_log_ios + buf_pool->n_pages_read + buf_pool->n_pages_written; srv_main_thread_op_info = (char*)"sleeping"; - + srv_main_1_second_loops++; + if (!skip_sleep) { os_thread_sleep(1000000); - } + srv_main_sleeps++; + } skip_sleep = FALSE; @@ -1968,6 +2027,7 @@ srv_main_thread_op_info = (char*)"flushing log"; log_buffer_flush_to_disk(); + srv_sync_flush++; /* If there were less than 5 i/os during the one second sleep, we assume that there is free @@ -1984,8 +2044,9 @@ ibuf_contract_for_n_pages(TRUE, 5); srv_main_thread_op_info = (char*)"flushing log"; - - log_buffer_flush_to_disk(); + // Avoid fsync when srv_flush_log_at_trx_commit != 1 + log_buffer_flush_maybe_sync(); + srv_async_flush++; } if (buf_get_modified_ratio_pct() > @@ -2016,6 +2077,7 @@ /* ---- We perform the following code approximately once per 10 seconds when there is database activity */ + srv_main_10_second_loops++; #ifdef MEM_PERIODIC_CHECK /* Check magic numbers of every allocated mem block once in 10 @@ -2035,7 +2097,9 @@ buf_flush_batch(BUF_FLUSH_LIST, 100, ut_dulint_max); srv_main_thread_op_info = (char*) "flushing log"; - log_buffer_flush_to_disk(); + // Avoid fsync when srv_flush_log_at_trx_commit != 1. + log_buffer_flush_maybe_sync(); + srv_async_flush++; } /* We run a batch of insert buffer merge every 10 seconds, @@ -2045,15 +2109,16 @@ ibuf_contract_for_n_pages(TRUE, 5); srv_main_thread_op_info = (char*)"flushing log"; - log_buffer_flush_to_disk(); + // Avoid fsync when srv_flush_log_at_trx_commit != 1. + log_buffer_flush_maybe_sync(); + last_flush_time = time(NULL); + srv_async_flush++; /* We run a full purge every 10 seconds, even if the server were active */ n_pages_purged = 1; - last_flush_time = time(NULL); - while (n_pages_purged) { if (srv_fast_shutdown && srv_shutdown_state > 0) { @@ -2071,6 +2136,7 @@ log_buffer_flush_to_disk(); last_flush_time = current_time; + srv_sync_flush++; } } @@ -2124,7 +2190,7 @@ /* The server has been quiet for a while: start running background operations */ - + srv_main_background_loops++; srv_main_thread_op_info = (char*)"doing background drop tables"; n_tables_to_drop = row_drop_tables_for_mysql_in_background(); @@ -2144,7 +2210,7 @@ n_pages_purged = 1; - last_flush_time = time(NULL); + last_flush_time = time(NULL); while (n_pages_purged) { if (srv_fast_shutdown && srv_shutdown_state > 0) { @@ -2162,6 +2228,7 @@ log_buffer_flush_to_disk(); last_flush_time = current_time; + srv_sync_flush++; } } @@ -2179,7 +2246,11 @@ if (srv_fast_shutdown && srv_shutdown_state > 0) { n_bytes_merged = 0; } else { - n_bytes_merged = ibuf_contract_for_n_pages(TRUE, 20); + // This should do an amount of IO similar to the number of + // dirty pages that will be flushed in the call to + // buf_flush_batch below. Otherwise, the system favors + // clean pages over cleanup throughput. + n_bytes_merged = ibuf_contract_for_n_pages(TRUE, 100); } srv_main_thread_op_info = (char*)"reserving kernel mutex"; @@ -2192,6 +2263,7 @@ mutex_exit(&kernel_mutex); flush_loop: + srv_main_flush_loops++; srv_main_thread_op_info = (char*)"flushing buffer pool pages"; n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 100, ut_dulint_max); @@ -2210,7 +2282,17 @@ srv_main_thread_op_info = (char*) "flushing log"; - log_buffer_flush_to_disk(); + current_time = time(NULL); + if (difftime(current_time, last_flush_time) > 1) { + srv_main_thread_op_info = (char*) "flushing log"; + log_buffer_flush_to_disk(); + last_flush_time = current_time; + srv_sync_flush++; + } else { + // Avoid fsync when srv_flush_log_at_trx_commit != 1. + log_buffer_flush_maybe_sync(); + srv_async_flush++; + } srv_main_thread_op_info = (char*)"making checkpoint"; diff -ruN base/innobase/srv/srv0start.c mysql40gpl/innobase/srv/srv0start.c --- base/innobase/srv/srv0start.c 2005-09-02 15:37:55.000000000 -0700 +++ mysql40gpl/innobase/srv/srv0start.c 2007-04-21 09:56:45.000000000 -0700 @@ -893,6 +893,7 @@ ulint i; ulint k; mtr_t mtr; + ulint n_threads; #ifdef UNIV_DEBUG fprintf(stderr, @@ -1059,25 +1060,28 @@ } /* Restrict the maximum number of file i/o threads */ - if (srv_n_file_io_threads > SRV_MAX_N_IO_THREADS) { + if (srv_n_read_io_threads > SRV_MAX_N_IO_THREADS) { - srv_n_file_io_threads = SRV_MAX_N_IO_THREADS; + srv_n_read_io_threads = SRV_MAX_N_IO_THREADS; } + /* Restrict the maximum number of file i/o threads */ + if (srv_n_write_io_threads > SRV_MAX_N_IO_THREADS) { - if (!os_aio_use_native_aio) { - /* In simulated aio we currently have use only for 4 threads */ - - srv_n_file_io_threads = 4; + srv_n_write_io_threads = SRV_MAX_N_IO_THREADS; + } - os_aio_init(8 * SRV_N_PENDING_IOS_PER_THREAD - * srv_n_file_io_threads, - srv_n_file_io_threads, - SRV_MAX_N_PENDING_SYNC_IOS); + if (!os_aio_use_native_aio) { + /* More than 4 threads are now supported. */ + n_threads = os_aio_init(8 * SRV_N_PENDING_IOS_PER_THREAD, + srv_n_read_io_threads, + srv_n_write_io_threads, + SRV_MAX_N_PENDING_SYNC_IOS); } else { - os_aio_init(SRV_N_PENDING_IOS_PER_THREAD - * srv_n_file_io_threads, - srv_n_file_io_threads, - SRV_MAX_N_PENDING_SYNC_IOS); + /* Might need more slots here. Alas, I don't have windows. */ + n_threads = os_aio_init(SRV_N_PENDING_IOS_PER_THREAD, + srv_n_read_io_threads, + srv_n_write_io_threads, + SRV_MAX_N_PENDING_SYNC_IOS); } fil_init(SRV_MAX_N_OPEN_FILES); @@ -1091,10 +1095,9 @@ /* Create i/o-handler threads: */ - for (i = 0; i < srv_n_file_io_threads; i++) { + for (i = 0; i < n_threads; i++) { n[i] = i; - os_thread_create(io_handler_thread, n + i, thread_ids + i); } diff -ruN base/innobase/trx/trx0roll.c mysql40gpl/innobase/trx/trx0roll.c --- base/innobase/trx/trx0roll.c 2005-09-02 15:38:01.000000000 -0700 +++ mysql40gpl/innobase/trx/trx0roll.c 2007-04-21 09:56:45.000000000 -0700 @@ -36,6 +36,12 @@ /* Auxiliary variable which tells the previous progress % we printed */ ulint trx_roll_progress_printed_pct; +extern char *mysql_data_home; +extern char reg_ext[]; + +/* Delete .frm schema file for the specified table. */ +static void mysql_delete_table_schema_file(const char *full_table_name); + /*********************************************************************** Rollback a transaction used in MySQL. */ @@ -348,7 +354,7 @@ int err; mutex_enter(&kernel_mutex); - + /* Open a dummy session */ if (!trx_dummy_sess) { @@ -473,6 +479,8 @@ err = row_drop_table_for_mysql(table->name, trx, TRUE); ut_a(err == (int) DB_SUCCESS); + + mysql_delete_table_schema_file(table->name); } } @@ -487,7 +495,7 @@ goto loop; } - + /*********************************************************************** Creates an undo number array. */ @@ -1245,3 +1253,24 @@ return(thr); } + +/* Delete .frm schema file for the specified table. */ +static void mysql_delete_table_schema_file(const char *full_table_name) { + char frm_filename[1000]; + + fprintf(stderr, "InnoDB: mysql dropping schema file for %s\n", + full_table_name); + if (strlen(full_table_name) + strlen(mysql_data_home) + strlen(reg_ext) + >= 1000) { + fprintf(stderr, "InnoDB: illegal table name.\n"); + return; + } + + /* Create the filename based on the database/table name. */ + sprintf(frm_filename, "%s/%s%s", mysql_data_home, full_table_name, reg_ext); + + fprintf(stderr, "InnoDB: unlink file %s\n", frm_filename); + if (unlink(frm_filename) != 0) + fprintf(stderr, "InnoDB: failed dropping schema file, %d.\n", errno); +} + diff -ruN base/innobase/trx/trx0sys.c mysql40gpl/innobase/trx/trx0sys.c --- base/innobase/trx/trx0sys.c 2005-09-02 15:38:00.000000000 -0700 +++ mysql40gpl/innobase/trx/trx0sys.c 2007-04-21 09:56:45.000000000 -0700 @@ -26,12 +26,15 @@ trx_sys_t* trx_sys = NULL; trx_doublewrite_t* trx_doublewrite = NULL; -/* 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; /* Do NOT merge this to the 4.1 code base! */ @@ -481,7 +484,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); @@ -600,6 +603,86 @@ } /********************************************************************* +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 */ +{ + 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; + } + + 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); +} + +/********************************************************************* Prints to stderr the MySQL binlog info in the system header if the magic number shows it valid. */ @@ -663,55 +746,78 @@ } /********************************************************************* -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); - - sys_header = trx_sysf_get(&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) { - - mtr_commit(&mtr); + trx_sysf_t* sys_header; + mtr_t mtr; - return; - } + mtr_start(&mtr); - fprintf(stderr, -"InnoDB: In a MySQL replication slave the last master binlog file\n" -"InnoDB: position %lu %lu, file name %s\n", - mach_read_from_4(sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO - + TRX_SYS_MYSQL_LOG_OFFSET_HIGH), - 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 */ - - 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); - - 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); + 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; + } + + 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; + } + + /* We need the relay-log related information in ha_innobase.cc to initialize + * glob_mi to right values. + */ + + /* 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)); + + /* 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); + } } /******************************************************************** diff -ruN base/innobase/trx/trx0trx.c mysql40gpl/innobase/trx/trx0trx.c --- base/innobase/trx/trx0trx.c 2005-09-02 15:37:59.000000000 -0700 +++ mysql40gpl/innobase/trx/trx0trx.c 2007-04-21 09:56:45.000000000 -0700 @@ -110,6 +110,8 @@ trx->mysql_log_offset = 0; trx->mysql_master_log_file_name = (char*) ""; trx->mysql_master_log_pos = 0; + trx->mysql_relay_log_file_name = ""; + trx->mysql_relay_log_pos = 0; mutex_create(&(trx->undo_mutex)); mutex_set_level(&(trx->undo_mutex), SYNC_TRX_UNDO); @@ -157,6 +159,12 @@ trx->read_view_heap = mem_heap_create(256); trx->read_view = NULL; + trx->always_enter_innodb = FALSE; + trx->clear_replication_status = FALSE; + + trx->repl_wait_binlog_name = NULL; + trx->repl_wait_binlog_pos = NULL; + return(trx); } @@ -295,6 +303,9 @@ } ut_a(trx->read_view == NULL); + + if (trx->repl_wait_binlog_name != NULL) + mem_free(trx->repl_wait_binlog_name); mem_free(trx); } @@ -696,14 +707,21 @@ 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( + if (trx->clear_replication_status) { + /* Clear the replication status. */ + trx_sys_update_mysql_relay_offset( + "", -1, "", -1, + TRX_SYS_MYSQL_RELAY_INFO, &mtr); + } 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_MASTER_LOG_INFO, &mtr); + TRX_SYS_MYSQL_RELAY_INFO, &mtr); } - + /* If we did not take the shortcut, the following call commits the mini-transaction, making the whole transaction committed in the file-based world at this log sequence number; @@ -808,18 +826,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; } @@ -1528,18 +1549,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 -ruN base/libmysqld/Makefile.am mysql40gpl/libmysqld/Makefile.am --- base/libmysqld/Makefile.am 2005-09-02 15:38:01.000000000 -0700 +++ mysql40gpl/libmysqld/Makefile.am 2007-04-21 13:19:24.000000000 -0700 @@ -53,7 +53,8 @@ sql_rename.cc sql_repl.cc sql_select.cc sql_do.cc sql_show.cc \ sql_string.cc sql_table.cc sql_test.cc sql_udf.cc \ sql_update.cc sql_yacc.cc table.cc thr_malloc.cc time.cc \ - unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc + unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc \ + hash_64.cc repl_semi_sync.cc repl_mule.cc EXTRA_DIST = lib_vio.c diff -ruN base/libmysqld/Makefile.in mysql40gpl/libmysqld/Makefile.in --- base/libmysqld/Makefile.in 2005-09-02 15:38:32.000000000 -0700 +++ mysql40gpl/libmysqld/Makefile.in 2007-04-21 13:22:37.000000000 -0700 @@ -108,7 +108,8 @@ sql_update.$(OBJEXT) sql_yacc.$(OBJEXT) table.$(OBJEXT) \ thr_malloc.$(OBJEXT) time.$(OBJEXT) unireg.$(OBJEXT) \ uniques.$(OBJEXT) stacktrace.$(OBJEXT) sql_union.$(OBJEXT) \ - hash_filo.$(OBJEXT) + hash_filo.$(OBJEXT) \ + hash_64.$(OBJEXT) repl_mule.$(OBJEXT) repl_semi_sync.$(OBJEXT) am_libmysqld_int_a_OBJECTS = $(am__objects_1) $(am__objects_2) \ $(am__objects_3) libmysqld_int_a_OBJECTS = $(am_libmysqld_int_a_OBJECTS) @@ -159,7 +160,10 @@ @AMDEP_TRUE@ ./$(DEPDIR)/sql_update.Po ./$(DEPDIR)/sql_yacc.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/stacktrace.Po ./$(DEPDIR)/table.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/thr_malloc.Po ./$(DEPDIR)/time.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/uniques.Po ./$(DEPDIR)/unireg.Po +@AMDEP_TRUE@ ./$(DEPDIR)/uniques.Po ./$(DEPDIR)/unireg.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/hash_64.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/repl_semi_sync.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/repl_mule.Po COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) \ @@ -442,7 +446,8 @@ sql_rename.cc sql_repl.cc sql_select.cc sql_do.cc sql_show.cc \ sql_string.cc sql_table.cc sql_test.cc sql_udf.cc \ sql_update.cc sql_yacc.cc table.cc thr_malloc.cc time.cc \ - unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc + unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc \ + repl_mule.cc repl_semi_sync.cc hash_64.cc EXTRA_DIST = lib_vio.c libmysqld_int_a_SOURCES = $(libmysqld_sources) $(libmysqlsources) $(sqlsources) @@ -614,6 +619,9 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uniques.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unireg.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash_64.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repl_semi_sync.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repl_mule.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ diff -ruN base/mysql-test/mysql-test-run.sh mysql40gpl/mysql-test/mysql-test-run.sh --- base/mysql-test/mysql-test-run.sh 2005-09-02 15:38:00.000000000 -0700 +++ mysql40gpl/mysql-test/mysql-test-run.sh 2007-04-21 09:56:49.000000000 -0700 @@ -180,6 +180,7 @@ SYST=0 REALT=0 FAST_START="" +SLAVE_INNODB=0 MYSQL_TMP_DIR=$MYSQL_TEST_DIR/var/tmp SLAVE_LOAD_TMPDIR=../../var/tmp #needs to be same length to test logging RES_SPACE=" " @@ -388,6 +389,9 @@ --fast) FAST_START=1 ;; + --slave-innodb) + SLAVE_INNODB=1 + ;; -- ) shift; break ;; --* ) $ECHO "Unrecognized option: $1"; exit 1 ;; * ) break ;; @@ -977,6 +981,11 @@ slave_datadir="$SLAVE_MYDDIR/../$slave_ident-data/" slave_pid="$MYRUN_DIR/mysqld-$slave_ident.pid" slave_sock="$SLAVE_MYSOCK-$1" + + slave_master_info_file_x="$slave_master_info_file-$1" + if [ -f $slave_master_info_file_x ] ; then + SLAVE_MASTER_INFO=`$CAT $slave_master_info_file_x` + fi else slave_server_id=2 slave_rpl_rank=2 @@ -986,7 +995,7 @@ slave_datadir=$SLAVE_MYDDIR slave_pid=$SLAVE_MYPID slave_sock="$SLAVE_MYSOCK" - fi + fi # Remove stale binary logs and old master.info files $RM -f $MYSQL_TEST_DIR/var/log/$slave_ident-*bin.* $RM -f $slave_datadir/master.info $slave_datadir/relay-log.info @@ -1004,16 +1013,35 @@ --master-password="" \ --master-port=$MASTER_MYPORT \ --server-id=$slave_server_id --rpl-recovery-rank=$slave_rpl_rank" - else - master_info=$SLAVE_MASTER_INFO - fi + else + master_info=$SLAVE_MASTER_INFO + fi $RM -f $slave_datadir/log.* - slave_args="--no-defaults $master_info \ - --exit-info=256 \ + + slave_args="--no-defaults" + + # rpl_mirror_binlog.test disables update binlog inside replicas. + SLAVE_NO_BINLOG=`$EXPR \( \( $tname : rpl_mirror_binlog \) != 0 \) \| \( \( $tname : rpl_mirror_binlog_stop \) != 0 \)` + + if [ x${SLAVE_NO_BINLOG} = x0 ] ; then + slave_args="$slave_args \ --log-bin=$MYSQL_TEST_DIR/var/log/$slave_ident-bin \ + --log-slave-updates" + fi + + if [ x${SLAVE_INNODB} = x0 ] ; then + slave_args="$slave_args \ + --skip-innodb" + else + slave_args="$slave_args \ + --default-table-type=innodb \ + --transaction-isolation=READ-COMMITTED" + fi + + slave_args="$slave_args $master_info \ + --exit-info=256 \ --relay-log=$MYSQL_TEST_DIR/var/log/$slave_ident-relay-bin \ - --log-slave-updates \ --log=$slave_log \ --basedir=$MY_BASEDIR \ --datadir=$slave_datadir \ @@ -1025,7 +1053,7 @@ --core --init-rpl-role=slave \ --tmpdir=$MYSQL_TMP_DIR \ --language=$LANGUAGE \ - --skip-innodb --skip-slave-start \ + --skip-slave-start \ --slave-load-tmpdir=$SLAVE_LOAD_TMPDIR \ --report-host=127.0.0.1 --report-user=root \ --report-port=$slave_port \ @@ -1033,6 +1061,7 @@ -O slave_net_timeout=10 \ $SMALL_SERVER \ $EXTRA_SLAVE_OPT $EXTRA_SLAVE_MYSQLD_OPT" + CUR_MYERR=$slave_err CUR_MYSOCK=$slave_sock @@ -1176,6 +1205,8 @@ mysql_loadstd () { # cp $STD_DATA/*.frm $STD_DATA/*.MRG $MASTER_MYDDIR/test + # Data files must be readable by all or in the data directory. + chmod a+r $STD_DATA/*.dat return 1 } @@ -1192,7 +1223,7 @@ echo $tname > $CURRENT_TEST SKIP_SLAVE=`$EXPR \( $tname : rpl \) = 0` if [ $USE_MANAGER = 1 ] ; then - many_slaves=`$EXPR \( \( $tname : rpl_failsafe \) != 0 \) \| \( \( $tname : rpl_chain_temp_table \) != 0 \)` + many_slaves=`$EXPR \( \( $tname : rpl_failsafe \) != 0 \) \| \( \( $tname : rpl_chain_temp_table \) != 0 \) \| \( \( $tname : rpl_mirror_binlog \) != 0 \) \| \( \( $tname : rpl_mirror_binlog_stop \) != 0 \)` fi if [ -n "$SKIP_TEST" ] ; then @@ -1301,6 +1332,7 @@ if [ -f $tf ] ; then $RM -f r/$tname.*reject mysql_test_args="-R r/$result_file.result $EXTRA_MYSQL_TEST_OPT" + if [ -z "$DO_CLIENT_GDB" ] ; then `$MYSQL_TEST $mysql_test_args < $tf 2> $TIMEFILE`; else diff -ruN base/mysql-test/r/checksum1.result mysql40gpl/mysql-test/r/checksum1.result --- base/mysql-test/r/checksum1.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/r/checksum1.result 2007-04-21 09:56:50.000000000 -0700 @@ -0,0 +1,105 @@ +drop table if exists t1; +create table t1(i int, i1 int, c1 char(1), c2 char(2), f float, d double, vc varchar(10)); +insert into t1 values (1, 3, '1', '1', 1, 1, '1'); +insert into t1 values (2, 2, '2', '2', 2, 2, '2'); +insert into t1 values (3, 1, '3', '22', 3, 3, '22'); +select hash(i) from t1 order by i; +hash(i) +12125821063809463359 +7897639797670528794 +3669458531531594229 +select hash(c1) from t1 order by i; +hash(c1) +8691557201380153181 +8691557201380153182 +8691557201380153183 +select hash(c2) from t1 order by i; +hash(c2) +8691557201380153181 +8691557201380153182 +3899139583912260744 +select hash(f) from t1 order by i; +hash(f) +16354266212739168523 +16354002329948397860 +16353993533855372172 +select hash(d) from t1 order by i; +hash(d) +16354266212739168523 +16354002329948397860 +16353993533855372172 +select hash(vc) from t1 order by i; +hash(vc) +8691557201380153181 +8691557201380153182 +3899139583912260744 +select hash(i, c1, c2, f, d, vc) from t1 order by i; +hash(i, c1, c2, f, d, vc) +8260664520004307694 +4271355524914459424 +7874794455587051588 +select '1: not match1', unordered_checksum(i, c1, c2, f, d, vc) from t1; +1: not match1 unordered_checksum(i, c1, c2, f, d, vc) +1: not match1 11569713724669558126 +select '1: not match2', unordered_checksum(i1, c1, c2, f, d, vc) from t1; +1: not match2 unordered_checksum(i1, c1, c2, f, d, vc) +1: not match2 15606142839496559570 +select '2: not match1', ordered_checksum(i, c1, c2, f, d, vc) from t1; +2: not match1 ordered_checksum(i, c1, c2, f, d, vc) +2: not match1 4192927915844138010 +select '2: not match2', ordered_checksum(i1, c1, c2, f, d, vc) from t1; +2: not match2 ordered_checksum(i1, c1, c2, f, d, vc) +2: not match2 4145976810685705126 +select '3: match1', unordered_checksum(i) from t1; +3: match1 unordered_checksum(i) +3: match1 8292030422173955636 +select '3: match2', unordered_checksum(i1) from t1; +3: match2 unordered_checksum(i1) +3: match2 8292030422173955636 +select '4: not match1', ordered_checksum(i) from t1; +4: not match1 ordered_checksum(i) +4: not match1 6859764282969517028 +select '4: not match2', ordered_checksum(i1) from t1; +4: not match2 ordered_checksum(i1) +4: not match2 6074163440810017764 +select '5: not match1', unordered_checksum(i, c1, c2, f, d, vc) from t1 group by i1 order by i; +5: not match1 unordered_checksum(i, c1, c2, f, d, vc) +5: not match1 17762730987931112970 +5: not match1 13791363591642755012 +5: not match1 16819467897398740128 +select '5: not match2', unordered_checksum(i1, c1, c2, f, d, vc) from t1 group by i order by i; +5: not match2 unordered_checksum(i1, c1, c2, f, d, vc) +5: not match2 9841470782680298596 +5: not match2 13791363591642755012 +5: not match2 17249632850956161138 +select '6: not match1', unordered_checksum(i) from t1 group by i1 order by i; +6: not match1 unordered_checksum(i) +6: not match1 3199157890669439195 +6: not match1 16841262108792413182 +6: not match1 13172653091998467345 +select '6: not match2', unordered_checksum(i1) from t1 group by i order by i; +6: not match2 unordered_checksum(i1) +6: not match2 13172653091998467345 +6: not match2 16841262108792413182 +6: not match2 3199157890669439195 +select '7: match1', ordered_checksum(i, c1, c2, f, d, vc) from t1 group by i1 order by i; +7: match1 ordered_checksum(i, c1, c2, f, d, vc) +7: match1 8260664520004307694 +7: match1 4271355524914459424 +7: match1 7874794455587051588 +select '7: match2', ordered_checksum(i1, c1, c2, f, d, vc) from t1 group by i order by i; +7: match2 ordered_checksum(i1, c1, c2, f, d, vc) +7: match2 914739442277279872 +7: match2 4271355524914459424 +7: match2 7728496414611999894 +select '8: match1', ordered_checksum(i) from t1 group by i1 order by i; +8: match1 ordered_checksum(i) +8: match1 12125821063809463359 +8: match1 7897639797670528794 +8: match1 3669458531531594229 +select '8: match2', ordered_checksum(i1) from t1 group by i order by i; +8: match2 ordered_checksum(i1) +8: match2 3669458531531594229 +8: match2 7897639797670528794 +8: match2 12125821063809463359 +drop table t1; diff -ruN base/mysql-test/r/checksum2.result mysql40gpl/mysql-test/r/checksum2.result --- base/mysql-test/r/checksum2.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/r/checksum2.result 2007-04-21 09:56:50.000000000 -0700 @@ -0,0 +1,55 @@ +drop table if exists t2; +create table t2(dt datetime, da date, ti time, ts timestamp, y year); +insert into t2 values ('2006-01-01 10:00:00', '2006-01-01', '10:00:00', '20060101100000', 2006); +insert into t2 values ('2007-01-01 11:00:00', '2007-01-01', '11:00:00', '20060101110000', 2007); +select hash(dt) from t2; +hash(dt) +1124811441346647439 +6624559493394817197 +select hash(da) from t2; +hash(da) +17033052262703112724 +32887120971591149 +select hash(ti) from t2; +hash(ti) +6465380211724811991 +2265808870231976098 +select hash(ts) from t2; +hash(ts) +16880677880901653011 +4067825358518885486 +select hash(y) from t2; +hash(y) +12909222668951978241 +1610365786966397462 +select unordered_checksum(dt) from t2; +unordered_checksum(dt) +15010824031073790406 +select unordered_checksum(da) from t2; +unordered_checksum(da) +7509606444104536861 +select unordered_checksum(ti) from t2; +unordered_checksum(ti) +14045112056351017617 +select unordered_checksum(ts) from t2; +unordered_checksum(ts) +6203081360941601433 +select unordered_checksum(y) from t2; +unordered_checksum(y) +2404303847799132147 +select ordered_checksum(dt) from t2; +ordered_checksum(dt) +7656421153328024636 +select ordered_checksum(da) from t2; +ordered_checksum(da) +10643334536526376669 +select ordered_checksum(ti) from t2; +ordered_checksum(ti) +17104658564235541997 +select ordered_checksum(ts) from t2; +ordered_checksum(ts) +12430433059171515385 +select ordered_checksum(y) from t2; +ordered_checksum(y) +6515068423295669075 +drop table t2; diff -ruN base/mysql-test/r/checksum3.result mysql40gpl/mysql-test/r/checksum3.result --- base/mysql-test/r/checksum3.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/r/checksum3.result 2007-04-21 09:56:50.000000000 -0700 @@ -0,0 +1,45 @@ +drop table if exists t3; +create table t3(bi binary(20), vb varbinary(20), bl blob, t text); +insert into t3 values ('abc', 'def', 'ghi', 'jkl'); +insert into t3 values ('abc1', 'def1', 'ghi1', 'jkl1'); +select hash(bi) from t3; +hash(bi) +12869841847494858668 +16176128574998051189 +select hash(vb) from t3; +hash(vb) +12865066668494484353 +13061924616633172994 +select hash(bl) from t3; +hash(bl) +12867869323634226642 +14876206763629245415 +select hash(t) from t3; +hash(t) +12863085348540826711 +11754429369170763748 +select unordered_checksum(bi) from t3; +unordered_checksum(bi) +15476014181871530557 +select unordered_checksum(vb) from t3; +unordered_checksum(vb) +9506678692596656999 +select unordered_checksum(bl) from t3; +unordered_checksum(bl) +17925204920421440209 +select unordered_checksum(t) from t3; +unordered_checksum(t) +10772865288369850199 +select ordered_checksum(bi) from t3; +ordered_checksum(bi) +1086334759476996029 +select ordered_checksum(vb) from t3; +ordered_checksum(vb) +9124841169666920627 +select ordered_checksum(bl) from t3; +ordered_checksum(bl) +12967862498748221529 +select ordered_checksum(t) from t3; +ordered_checksum(t) +18134691941644832235 +drop table t3; diff -ruN base/mysql-test/r/checksum4.result mysql40gpl/mysql-test/r/checksum4.result --- base/mysql-test/r/checksum4.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/r/checksum4.result 2007-04-21 09:56:50.000000000 -0700 @@ -0,0 +1,25 @@ +drop table if exists t4; +create table t4(e enum('1', '2'), s set('1', '2', '3')); +insert into t4 values('1', '1,2'); +insert into t4 values('2', '2,3'); +select hash(e) from t4; +hash(e) +8691557201380153181 +8691557201380153182 +select hash(s) from t4; +hash(s) +12946304085128770083 +12947181495407893201 +select unordered_checksum(e) from t4; +unordered_checksum(e) +9521211207457086695 +select unordered_checksum(s) from t4; +unordered_checksum(s) +9522018248992175126 +select ordered_checksum(e) from t4; +ordered_checksum(e) +3899138484400632629 +select ordered_checksum(s) from t4; +ordered_checksum(s) +13528951836076377140 +drop table t4; diff -ruN base/mysql-test/r/distinguish_privilege.result mysql40gpl/mysql-test/r/distinguish_privilege.result --- base/mysql-test/r/distinguish_privilege.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/r/distinguish_privilege.result 2007-04-21 09:56:50.000000000 -0700 @@ -0,0 +1,30 @@ +drop database if exists mysqltest; +create database mysqltest; +create table mysqltest.t1 (a int) engine = InnoDB; +insert into mysqltest.t1 values (3); +create table mysqltest.t2 (a int) engine = InnoDB; +insert into mysqltest.t2 values (3); +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; +select * from t1; +a +3 +select * from t2; +SELECT command denied to user: 'mysqltest_1@localhost' for table 't2' +desc t2; +SELECT command denied to user: 'mysqltest_1@localhost' for table 't2' +select * from t3; +Table 'mysqltest.t3' doesn't exist +desc t3; +Table 'mysqltest.t3' doesn't exist +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 -ruN base/mysql-test/r/flush.result mysql40gpl/mysql-test/r/flush.result --- base/mysql-test/r/flush.result 2005-09-02 15:50:38.000000000 -0700 +++ mysql40gpl/mysql-test/r/flush.result 2007-04-21 09:56:50.000000000 -0700 @@ -28,3 +28,9 @@ n 345 drop table t1; +flush table_statistics; +show table_statistics; +Table Rows_read Rows_changed Rows_changed_x_#indexes +flush index_statistics; +show index_statistics; +Index Rows_read diff -ruN base/mysql-test/r/ieee754_to_string.result mysql40gpl/mysql-test/r/ieee754_to_string.result --- base/mysql-test/r/ieee754_to_string.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/r/ieee754_to_string.result 2007-04-21 09:56:51.000000000 -0700 @@ -0,0 +1,19 @@ +drop table if exists t1,t2; +CREATE TABLE t1 (d double, i int); +CREATE TABLE t2 (v varchar(30), i int); +INSERT INTO t1 VALUES (1.7976931348623157e+308, 0); +INSERT INTO t1 VALUES (NULL, 0); +INSERT INTO t1 VALUES ('inf', 0); +INSERT INTO t1 VALUES ('nan', 0); +INSERT INTO t1 VALUES (-0e0, 0); +INSERT INTO t2 SELECT IEEE754_TO_STRING(d), i from t1; +INSERT INTO t1 SELECT * from t2; +SELECT COUNT(*), d from t1 group by d order by d; +COUNT(*) d +2 NULL +2 -0 +2 1.79769313486232e+308 +2 inf +2 nan +DROP TABLE t1; +DROP TABLE t2; diff -ruN base/mysql-test/r/order_by_fp.result mysql40gpl/mysql-test/r/order_by_fp.result --- base/mysql-test/r/order_by_fp.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/r/order_by_fp.result 2007-04-21 09:56:52.000000000 -0700 @@ -0,0 +1,12 @@ +drop table if exists t1; +CREATE TABLE t1 (d double); +INSERT INTO t1 VALUES (-0E0), (+0E0), (1E308), (-1E308), (1), (-1); +SELECT 2 * d AS e FROM t1 ORDER BY e; +e +-inf +-2 +-0 +0 +2 +inf +DROP TABLE t1; diff -ruN base/mysql-test/r/rpl000015.result mysql40gpl/mysql-test/r/rpl000015.result --- base/mysql-test/r/rpl000015.result 2005-09-02 15:50:38.000000000 -0700 +++ mysql40gpl/mysql-test/r/rpl000015.result 2007-04-21 09:56:52.000000000 -0700 @@ -4,20 +4,20 @@ master-bin.001 79 reset slave; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos change master to master_host='127.0.0.1'; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 test MASTER_PORT 7 4 slave-relay-bin.001 4 No No 0 0 0 4 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 test MASTER_PORT 7 4 slave-relay-bin.001 4 No No 0 0 0 4 None 0 change master to master_host='127.0.0.1',master_user='root', master_password='',master_port=MASTER_PORT; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 7 4 slave-relay-bin.001 4 No No 0 0 0 4 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 7 4 slave-relay-bin.001 4 No No 0 0 0 4 None 0 slave start; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 7 master-bin.001 79 slave-relay-bin.001 120 master-bin.001 Yes Yes 0 0 79 120 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 7 master-bin.001 79 slave-relay-bin.001 120 master-bin.001 Yes Yes 0 0 79 120 None 0 drop table if exists t1; create table t1 (n int); insert into t1 values (10),(45),(90); diff -ruN base/mysql-test/r/rpl_change_master.result mysql40gpl/mysql-test/r/rpl_change_master.result --- base/mysql-test/r/rpl_change_master.result 2005-09-02 15:50:38.000000000 -0700 +++ mysql40gpl/mysql-test/r/rpl_change_master.result 2007-04-21 09:56:52.000000000 -0700 @@ -15,12 +15,12 @@ n 1 show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_MYPORT 1 master-bin.001 273 slave-relay-bin.002 255 master-bin.001 No No 0 0 214 314 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_MYPORT 1 master-bin.001 273 slave-relay-bin.002 255 master-bin.001 No No 0 0 214 314 None 0 change master to master_user='root'; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_MYPORT 1 master-bin.001 214 slave-relay-bin.001 4 master-bin.001 No No 0 0 214 4 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_MYPORT 1 master-bin.001 214 slave-relay-bin.001 4 master-bin.001 No No 0 0 214 4 None 0 select release_lock("a"); release_lock("a") 1 diff -ruN base/mysql-test/r/rpl_empty_master_crash.result mysql40gpl/mysql-test/r/rpl_empty_master_crash.result --- base/mysql-test/r/rpl_empty_master_crash.result 2005-09-02 15:50:38.000000000 -0700 +++ mysql40gpl/mysql-test/r/rpl_empty_master_crash.result 2007-04-21 09:56:52.000000000 -0700 @@ -6,7 +6,7 @@ slave start; drop table if exists t1; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos load table t1 from master; Error connecting to master: Master is not configured load table t1 from master; diff -ruN base/mysql-test/r/rpl_error_ignored_table.result mysql40gpl/mysql-test/r/rpl_error_ignored_table.result --- base/mysql-test/r/rpl_error_ignored_table.result 2005-09-02 15:50:38.000000000 -0700 +++ mysql40gpl/mysql-test/r/rpl_error_ignored_table.result 2007-04-21 09:56:52.000000000 -0700 @@ -8,8 +8,8 @@ insert into t1 values (1),(1); Duplicate entry '1' for key 1 show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.001 213 slave-relay-bin.002 254 master-bin.001 Yes Yes 0 0 213 254 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 213 slave-relay-bin.002 254 master-bin.001 Yes Yes 0 0 213 254 None 0 show tables like 't1'; Tables_in_test (t1) drop table t1; diff -ruN base/mysql-test/r/rpl_flush_log_loop.result mysql40gpl/mysql-test/r/rpl_flush_log_loop.result --- base/mysql-test/r/rpl_flush_log_loop.result 2005-09-02 15:50:38.000000000 -0700 +++ mysql40gpl/mysql-test/r/rpl_flush_log_loop.result 2007-04-21 09:56:52.000000000 -0700 @@ -13,5 +13,5 @@ slave start; flush logs; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root SLAVE_PORT 60 slave-bin.001 79 relay-log.002 4 slave-bin.001 Yes Yes 0 0 79 4 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root SLAVE_PORT 60 slave-bin.001 79 relay-log.002 4 slave-bin.001 Yes Yes 0 0 79 4 None 0 diff -ruN base/mysql-test/r/rpl_innodb_clear_status.result mysql40gpl/mysql-test/r/rpl_innodb_clear_status.result --- base/mysql-test/r/rpl_innodb_clear_status.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/r/rpl_innodb_clear_status.result 2007-04-21 09:56:52.000000000 -0700 @@ -0,0 +1,33 @@ +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; +Access denied. You need the SUPER privilege for this operation +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 -ruN base/mysql-test/r/rpl_loaddata.result mysql40gpl/mysql-test/r/rpl_loaddata.result --- base/mysql-test/r/rpl_loaddata.result 2005-09-02 15:50:38.000000000 -0700 +++ mysql40gpl/mysql-test/r/rpl_loaddata.result 2007-04-21 09:56:52.000000000 -0700 @@ -32,8 +32,8 @@ set global sql_slave_skip_counter=1; start slave; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.001 1311 slave-relay-bin.002 1352 master-bin.001 Yes Yes 0 0 1311 1352 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 1311 slave-relay-bin.002 1352 master-bin.001 Yes Yes 0 0 1311 1352 None 0 set sql_log_bin=0; delete from t1; set sql_log_bin=1; @@ -42,8 +42,8 @@ change master to master_user='test'; change master to master_user='root'; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.001 1419 slave-relay-bin.001 4 master-bin.001 No No 0 0 1419 4 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 1419 slave-relay-bin.001 4 master-bin.001 No No 0 0 1419 4 None 0 set global sql_slave_skip_counter=1; start slave; set sql_log_bin=0; @@ -53,8 +53,8 @@ stop slave; reset slave; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 4 slave-relay-bin.001 4 No No 0 0 0 4 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 4 slave-relay-bin.001 4 No No 0 0 0 4 None 0 reset master; create table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60), unique(day)); diff -ruN base/mysql-test/r/rpl_log_pos.result mysql40gpl/mysql-test/r/rpl_log_pos.result --- base/mysql-test/r/rpl_log_pos.result 2005-09-02 15:50:38.000000000 -0700 +++ mysql40gpl/mysql-test/r/rpl_log_pos.result 2007-04-21 09:56:52.000000000 -0700 @@ -8,26 +8,26 @@ File Position Binlog_do_db Binlog_ignore_db master-bin.001 79 show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.001 79 slave-relay-bin.002 120 master-bin.001 Yes Yes 0 0 79 120 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 79 slave-relay-bin.002 120 master-bin.001 Yes Yes 0 0 79 120 None 0 slave stop; change master to master_log_pos=73; slave start; slave stop; change master to master_log_pos=73; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.001 73 slave-relay-bin.001 4 master-bin.001 No No 0 0 73 4 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 73 slave-relay-bin.001 4 master-bin.001 No No 0 0 73 4 None 0 slave start; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.001 73 slave-relay-bin.001 45 master-bin.001 No Yes 0 0 73 45 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 73 slave-relay-bin.001 45 master-bin.001 No Yes 0 0 73 45 None 0 slave stop; change master to master_log_pos=173; slave start; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.001 173 slave-relay-bin.001 4 master-bin.001 No Yes 0 0 173 4 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 173 slave-relay-bin.001 4 master-bin.001 No Yes 0 0 173 4 None 0 show master status; File Position Binlog_do_db Binlog_ignore_db master-bin.001 79 diff -ruN base/mysql-test/r/rpl_log.result mysql40gpl/mysql-test/r/rpl_log.result --- base/mysql-test/r/rpl_log.result 2005-09-02 15:50:38.000000000 -0700 +++ mysql40gpl/mysql-test/r/rpl_log.result 2007-04-21 09:56:52.000000000 -0700 @@ -95,7 +95,7 @@ slave-bin.002 62 Query 1 62 use `test`; insert into t1 values (1) slave-bin.002 122 Query 1 122 use `test`; drop table t1 show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.002 276 slave-relay-bin.003 211 master-bin.002 Yes Yes 0 0 276 211 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.002 276 slave-relay-bin.003 211 master-bin.002 Yes Yes 0 0 276 211 None 0 show binlog events in 'slave-bin.005' from 4; Error when executing command SHOW BINLOG EVENTS: Could not find target log diff -ruN base/mysql-test/r/rpl_make_master.result mysql40gpl/mysql-test/r/rpl_make_master.result --- base/mysql-test/r/rpl_make_master.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/r/rpl_make_master.result 2007-04-21 09:56:52.000000000 -0700 @@ -0,0 +1,27 @@ +drop database if exists mysqltest; +create database mysqltest; +create table mysqltest.t1 (a int) engine = InnoDB; +insert into mysqltest.t1 values (3); +create table mysqltest.t2 (a int) engine = InnoDB; +insert into mysqltest.t2 values (3); +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; +select * from mysqltest.t1; +a +3 +make master revoke session with kill; +make master grant session; +select * from mysqltest.t1; +a +3 +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 -ruN base/mysql-test/r/rpl_max_relay_size.result mysql40gpl/mysql-test/r/rpl_max_relay_size.result --- base/mysql-test/r/rpl_max_relay_size.result 2005-09-02 15:50:38.000000000 -0700 +++ mysql40gpl/mysql-test/r/rpl_max_relay_size.result 2007-04-21 09:56:53.000000000 -0700 @@ -15,8 +15,8 @@ 4096 start slave; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.001 50477 slave-relay-bin.014 1221 master-bin.001 Yes Yes 0 0 50477 1221 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 50477 slave-relay-bin.014 1221 master-bin.001 Yes Yes 0 0 50477 1221 None 0 stop slave; reset slave; set global max_relay_log_size=(5*4096); @@ -25,8 +25,8 @@ 20480 start slave; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.001 50477 slave-relay-bin.004 9457 master-bin.001 Yes Yes 0 0 50477 # +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 50477 slave-relay-bin.004 9457 master-bin.001 Yes Yes 0 0 50477 # None 0 stop slave; reset slave; set global max_relay_log_size=0; @@ -35,26 +35,26 @@ 0 start slave; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.001 50477 slave-relay-bin.008 1283 master-bin.001 Yes Yes 0 0 50477 1283 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 50477 slave-relay-bin.008 1283 master-bin.001 Yes Yes 0 0 50477 1283 None 0 stop slave; reset slave; flush logs; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 4 slave-relay-bin.001 4 No No 0 0 0 4 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 4 slave-relay-bin.001 4 No No 0 0 0 4 None 0 reset slave; start slave; flush logs; create table t1 (a int); show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.001 50535 slave-relay-bin.009 62 master-bin.001 Yes Yes 0 0 50535 62 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 50535 slave-relay-bin.009 62 master-bin.001 Yes Yes 0 0 50535 62 None 0 flush logs; drop table t1; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.001 50583 slave-relay-bin.010 52 master-bin.001 Yes Yes 0 0 50583 52 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 50583 slave-relay-bin.010 52 master-bin.001 Yes Yes 0 0 50583 52 None 0 flush logs; show master status; File Position Binlog_do_db Binlog_ignore_db diff -ruN base/mysql-test/r/rpl_mirror_binlog.result mysql40gpl/mysql-test/r/rpl_mirror_binlog.result --- base/mysql-test/r/rpl_mirror_binlog.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/r/rpl_mirror_binlog.result 2007-04-21 09:56:53.000000000 -0700 @@ -0,0 +1,522 @@ +slave stop; +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; +slave start; +drop table if exists t1; +create table t1(n int) engine = InnoDB; +insert into t1 values (300); +insert into t1 values (299); +insert into t1 values (298); +insert into t1 values (297); +insert into t1 values (296); +insert into t1 values (295); +insert into t1 values (294); +insert into t1 values (293); +insert into t1 values (292); +insert into t1 values (291); +insert into t1 values (290); +insert into t1 values (289); +insert into t1 values (288); +insert into t1 values (287); +insert into t1 values (286); +insert into t1 values (285); +insert into t1 values (284); +insert into t1 values (283); +insert into t1 values (282); +insert into t1 values (281); +insert into t1 values (280); +insert into t1 values (279); +insert into t1 values (278); +insert into t1 values (277); +insert into t1 values (276); +insert into t1 values (275); +insert into t1 values (274); +insert into t1 values (273); +insert into t1 values (272); +insert into t1 values (271); +insert into t1 values (270); +insert into t1 values (269); +insert into t1 values (268); +insert into t1 values (267); +insert into t1 values (266); +insert into t1 values (265); +insert into t1 values (264); +insert into t1 values (263); +insert into t1 values (262); +insert into t1 values (261); +insert into t1 values (260); +insert into t1 values (259); +insert into t1 values (258); +insert into t1 values (257); +insert into t1 values (256); +insert into t1 values (255); +insert into t1 values (254); +insert into t1 values (253); +insert into t1 values (252); +insert into t1 values (251); +insert into t1 values (250); +insert into t1 values (249); +insert into t1 values (248); +insert into t1 values (247); +insert into t1 values (246); +insert into t1 values (245); +insert into t1 values (244); +insert into t1 values (243); +insert into t1 values (242); +insert into t1 values (241); +insert into t1 values (240); +insert into t1 values (239); +insert into t1 values (238); +insert into t1 values (237); +insert into t1 values (236); +insert into t1 values (235); +insert into t1 values (234); +insert into t1 values (233); +insert into t1 values (232); +insert into t1 values (231); +insert into t1 values (230); +insert into t1 values (229); +insert into t1 values (228); +insert into t1 values (227); +insert into t1 values (226); +insert into t1 values (225); +insert into t1 values (224); +insert into t1 values (223); +insert into t1 values (222); +insert into t1 values (221); +insert into t1 values (220); +insert into t1 values (219); +insert into t1 values (218); +insert into t1 values (217); +insert into t1 values (216); +insert into t1 values (215); +insert into t1 values (214); +insert into t1 values (213); +insert into t1 values (212); +insert into t1 values (211); +insert into t1 values (210); +insert into t1 values (209); +insert into t1 values (208); +insert into t1 values (207); +insert into t1 values (206); +insert into t1 values (205); +insert into t1 values (204); +insert into t1 values (203); +insert into t1 values (202); +insert into t1 values (201); +insert into t1 values (200); +insert into t1 values (199); +insert into t1 values (198); +insert into t1 values (197); +insert into t1 values (196); +insert into t1 values (195); +insert into t1 values (194); +insert into t1 values (193); +insert into t1 values (192); +insert into t1 values (191); +insert into t1 values (190); +insert into t1 values (189); +insert into t1 values (188); +insert into t1 values (187); +insert into t1 values (186); +insert into t1 values (185); +insert into t1 values (184); +insert into t1 values (183); +insert into t1 values (182); +insert into t1 values (181); +insert into t1 values (180); +insert into t1 values (179); +insert into t1 values (178); +insert into t1 values (177); +insert into t1 values (176); +insert into t1 values (175); +insert into t1 values (174); +insert into t1 values (173); +insert into t1 values (172); +insert into t1 values (171); +insert into t1 values (170); +insert into t1 values (169); +insert into t1 values (168); +insert into t1 values (167); +insert into t1 values (166); +insert into t1 values (165); +insert into t1 values (164); +insert into t1 values (163); +insert into t1 values (162); +insert into t1 values (161); +insert into t1 values (160); +insert into t1 values (159); +insert into t1 values (158); +insert into t1 values (157); +insert into t1 values (156); +insert into t1 values (155); +insert into t1 values (154); +insert into t1 values (153); +insert into t1 values (152); +insert into t1 values (151); +insert into t1 values (150); +insert into t1 values (149); +insert into t1 values (148); +insert into t1 values (147); +insert into t1 values (146); +insert into t1 values (145); +insert into t1 values (144); +insert into t1 values (143); +insert into t1 values (142); +insert into t1 values (141); +insert into t1 values (140); +insert into t1 values (139); +insert into t1 values (138); +insert into t1 values (137); +insert into t1 values (136); +insert into t1 values (135); +insert into t1 values (134); +insert into t1 values (133); +insert into t1 values (132); +insert into t1 values (131); +insert into t1 values (130); +insert into t1 values (129); +insert into t1 values (128); +insert into t1 values (127); +insert into t1 values (126); +insert into t1 values (125); +insert into t1 values (124); +insert into t1 values (123); +insert into t1 values (122); +insert into t1 values (121); +insert into t1 values (120); +insert into t1 values (119); +insert into t1 values (118); +insert into t1 values (117); +insert into t1 values (116); +insert into t1 values (115); +insert into t1 values (114); +insert into t1 values (113); +insert into t1 values (112); +insert into t1 values (111); +insert into t1 values (110); +insert into t1 values (109); +insert into t1 values (108); +insert into t1 values (107); +insert into t1 values (106); +insert into t1 values (105); +insert into t1 values (104); +insert into t1 values (103); +insert into t1 values (102); +insert into t1 values (101); +insert into t1 values (100); +insert into t1 values (99); +insert into t1 values (98); +insert into t1 values (97); +insert into t1 values (96); +insert into t1 values (95); +insert into t1 values (94); +insert into t1 values (93); +insert into t1 values (92); +insert into t1 values (91); +insert into t1 values (90); +insert into t1 values (89); +insert into t1 values (88); +insert into t1 values (87); +insert into t1 values (86); +insert into t1 values (85); +insert into t1 values (84); +insert into t1 values (83); +insert into t1 values (82); +insert into t1 values (81); +insert into t1 values (80); +insert into t1 values (79); +insert into t1 values (78); +insert into t1 values (77); +insert into t1 values (76); +insert into t1 values (75); +insert into t1 values (74); +insert into t1 values (73); +insert into t1 values (72); +insert into t1 values (71); +insert into t1 values (70); +insert into t1 values (69); +insert into t1 values (68); +insert into t1 values (67); +insert into t1 values (66); +insert into t1 values (65); +insert into t1 values (64); +insert into t1 values (63); +insert into t1 values (62); +insert into t1 values (61); +insert into t1 values (60); +insert into t1 values (59); +insert into t1 values (58); +insert into t1 values (57); +insert into t1 values (56); +insert into t1 values (55); +insert into t1 values (54); +insert into t1 values (53); +insert into t1 values (52); +insert into t1 values (51); +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); +show status like 'Rpl_mirror_binlog_clients'; +Variable_name Value +Rpl_mirror_binlog_clients 1 +select "The following are SLAVE."; +The following are SLAVE. +The following are SLAVE. +show status like 'Rpl_mirror_binlog_status'; +Variable_name Value +Rpl_mirror_binlog_status 1 +show variables like 'log_bin'; +Variable_name Value +log_bin OFF +select count(distinct n) from t1; +count(distinct n) +300 +select min(n) from t1; +min(n) +1 +select max(n) from t1; +max(n) +300 +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root 9306 1 master-bin.005 2252 slave-relay-bin.002 19013 master-bin.005 Yes Yes 0 0 2252 19013 None 0 +select "The following are SLAVE1."; +The following are SLAVE1. +The following are SLAVE1. +start slave; +select count(distinct n) from t1; +count(distinct n) +300 +select min(n) from t1; +min(n) +1 +select max(n) from t1; +max(n) +300 +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root 9307 1 master-bin.005 2252 slave1-relay-bin.001 # master-bin.005 Yes Yes 0 0 2252 # None 0 +select "The following are SLAVE2."; +The following are SLAVE2. +The following are SLAVE2. +start slave; +stop slave; +select count(distinct n) from t1; +count(distinct n) +300 +select min(n) from t1; +min(n) +1 +select max(n) from t1; +max(n) +300 +select "The following are SLAVE."; +The following are SLAVE. +The following are SLAVE. +show master status; +File Position Binlog_do_db Binlog_ignore_db +master-bin.005 2252 +MAKE MASTER MASTER_LOG_FILE='master-bin', +MASTER_SERVER_ID=2, +INDEX='replication-log'; +Could not initialize master info structure, more error messages can be found in the MySQL error log +stop slave; +select "The following are SLAVE."; +The following are SLAVE. +The following are SLAVE. +MAKE MASTER MASTER_LOG_FILE='master-bin', +MASTER_SERVER_ID=2, +INDEX='replication_log'; +Could not initialize master info structure, more error messages can be found in the MySQL error log +MAKE MASTER REVOKE SESSION WITH KILL; +MAKE MASTER MASTER_LOG_FILE='master-bin', +MASTER_SERVER_ID=2, +INDEX='replication_log' + WITH BINLOG; +MAKE MASTER GRANT SESSION; +show master status; +File Position Binlog_do_db Binlog_ignore_db +master-bin.006 4 +delete from t1 where n > 250; +select count(distinct n) from t1; +count(distinct n) +250 +select "The following are SLAVE1."; +The following are SLAVE1. +The following are SLAVE1. +show variables like 'server_id'; +Variable_name Value +server_id 3 +select count(distinct n) from t1; +count(distinct n) +250 +select min(n) from t1; +min(n) +1 +select max(n) from t1; +max(n) +250 +select "The following are SLAVE2."; +The following are SLAVE2. +The following are SLAVE2. +show variables like 'server_id'; +Variable_name Value +server_id 4 +CHANGE MASTER TO +MASTER_HOST='127.0.0.1', +MASTER_USER='root', +MASTER_PASSWORD='', +MASTER_PORT=9307, +MASTER_LOG_FILE='master-bin.006', +MASTER_LOG_POS=4; +start slave; +select count(distinct n) from t1; +count(distinct n) +250 +select min(n) from t1; +min(n) +1 +select max(n) from t1; +max(n) +250 +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root 9307 1 master-bin.006 67 slave2-relay-bin.001 # master-bin.006 Yes Yes 0 0 67 # None 0 +drop table t1; +show status like 'Rpl_mirror_binlog_clients'; +Variable_name Value +Rpl_mirror_binlog_clients 2 +show status like 'Rpl_mirror_binlog_status'; +Variable_name Value +Rpl_mirror_binlog_status 0 +drop table t1; +select "The following are SLAVE1."; +The following are SLAVE1. +The following are SLAVE1. +master-bin.001 +master-bin.002 +master-bin.003 +master-bin.004 +master-bin.005 +master-bin.006 +master.info +mysql +relay-log.info +replication_log.index +test +stop slave; +reset slave no purge binlog; +master-bin.001 +master-bin.002 +master-bin.003 +master-bin.004 +master-bin.005 +master-bin.006 +mysql +replication_log.index +test +reset slave; +mysql +test +select "The following are SLAVE."; +The following are SLAVE. +The following are SLAVE. +show variables like 'log_bin'; +Variable_name Value +log_bin ON +show master logs; +Log_name +master-bin.001 +master-bin.002 +master-bin.003 +master-bin.004 +master-bin.005 +master-bin.006 +show master status; +File Position Binlog_do_db Binlog_ignore_db +master-bin.006 115 +select "The following are SLAVE2."; +The following are SLAVE2. +The following are SLAVE2. +show master logs; +Log_name +master-bin.001 +master-bin.002 +master-bin.003 +master-bin.004 +master-bin.005 +master-bin.006 +purge master logs to 'master-bin.006'; +show master logs; +Log_name +master-bin.006 +reset master; +Binlog closed, cannot RESET MASTER +stop slave; +master-bin.006 +master.info +mysql +relay-log.info +replication_log.index +test +CHANGE MASTER TO +MASTER_HOST='127.0.0.1', +MASTER_USER='root', +MASTER_PASSWORD='', +MASTER_PORT=9307, +MASTER_LOG_FILE='master-bin.001', +MASTER_LOG_POS=4; +master.info +mysql +relay-log.info +test diff -ruN base/mysql-test/r/rpl_mirror_binlog_stop.result mysql40gpl/mysql-test/r/rpl_mirror_binlog_stop.result --- base/mysql-test/r/rpl_mirror_binlog_stop.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/r/rpl_mirror_binlog_stop.result 2007-04-21 09:56:53.000000000 -0700 @@ -0,0 +1,730 @@ +slave stop; +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; +slave start; +drop table if exists t1; +create table t1(n int) engine = InnoDB; +insert into t1 values (100); +insert into t1 values (99); +insert into t1 values (98); +insert into t1 values (97); +insert into t1 values (96); +insert into t1 values (95); +insert into t1 values (94); +insert into t1 values (93); +insert into t1 values (92); +insert into t1 values (91); +insert into t1 values (90); +insert into t1 values (89); +insert into t1 values (88); +insert into t1 values (87); +insert into t1 values (86); +insert into t1 values (85); +insert into t1 values (84); +insert into t1 values (83); +insert into t1 values (82); +insert into t1 values (81); +insert into t1 values (80); +insert into t1 values (79); +insert into t1 values (78); +insert into t1 values (77); +insert into t1 values (76); +insert into t1 values (75); +insert into t1 values (74); +insert into t1 values (73); +insert into t1 values (72); +insert into t1 values (71); +insert into t1 values (70); +insert into t1 values (69); +insert into t1 values (68); +insert into t1 values (67); +insert into t1 values (66); +insert into t1 values (65); +insert into t1 values (64); +insert into t1 values (63); +insert into t1 values (62); +insert into t1 values (61); +insert into t1 values (60); +insert into t1 values (59); +insert into t1 values (58); +insert into t1 values (57); +insert into t1 values (56); +insert into t1 values (55); +insert into t1 values (54); +insert into t1 values (53); +insert into t1 values (52); +insert into t1 values (51); +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); +show status like 'Rpl_mirror_binlog_clients'; +Variable_name Value +Rpl_mirror_binlog_clients 1 +select "The following are SLAVE."; +The following are SLAVE. +The following are SLAVE. +show status like 'Rpl_mirror_binlog_status'; +Variable_name Value +Rpl_mirror_binlog_status 1 +show status like 'Rpl_mirror_binlog_clients'; +Variable_name Value +Rpl_mirror_binlog_clients 0 +select count(distinct n) from t1; +count(distinct n) +100 +select min(n) from t1; +min(n) +1 +select max(n) from t1; +max(n) +100 +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root 9306 1 master-bin.002 2130 slave-relay-bin.002 6367 master-bin.002 Yes Yes 0 0 2130 6367 None 0 +select "The following are SLAVE1."; +The following are SLAVE1. +The following are SLAVE1. +start slave; +select count(distinct n) from t1; +count(distinct n) +100 +select min(n) from t1; +min(n) +1 +select max(n) from t1; +max(n) +100 +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root 9307 1 master-bin.002 2130 slave1-relay-bin.001 # master-bin.002 Yes Yes 0 0 2130 # None 0 +select "The following are SLAVE."; +The following are SLAVE. +The following are SLAVE. +stop slave; +set global rpl_mirror_binlog_enabled=0; +start slave; +insert into t1 values (200); +insert into t1 values (199); +insert into t1 values (198); +insert into t1 values (197); +insert into t1 values (196); +insert into t1 values (195); +insert into t1 values (194); +insert into t1 values (193); +insert into t1 values (192); +insert into t1 values (191); +insert into t1 values (190); +insert into t1 values (189); +insert into t1 values (188); +insert into t1 values (187); +insert into t1 values (186); +insert into t1 values (185); +insert into t1 values (184); +insert into t1 values (183); +insert into t1 values (182); +insert into t1 values (181); +insert into t1 values (180); +insert into t1 values (179); +insert into t1 values (178); +insert into t1 values (177); +insert into t1 values (176); +insert into t1 values (175); +insert into t1 values (174); +insert into t1 values (173); +insert into t1 values (172); +insert into t1 values (171); +insert into t1 values (170); +insert into t1 values (169); +insert into t1 values (168); +insert into t1 values (167); +insert into t1 values (166); +insert into t1 values (165); +insert into t1 values (164); +insert into t1 values (163); +insert into t1 values (162); +insert into t1 values (161); +insert into t1 values (160); +insert into t1 values (159); +insert into t1 values (158); +insert into t1 values (157); +insert into t1 values (156); +insert into t1 values (155); +insert into t1 values (154); +insert into t1 values (153); +insert into t1 values (152); +insert into t1 values (151); +insert into t1 values (150); +insert into t1 values (149); +insert into t1 values (148); +insert into t1 values (147); +insert into t1 values (146); +insert into t1 values (145); +insert into t1 values (144); +insert into t1 values (143); +insert into t1 values (142); +insert into t1 values (141); +insert into t1 values (140); +insert into t1 values (139); +insert into t1 values (138); +insert into t1 values (137); +insert into t1 values (136); +insert into t1 values (135); +insert into t1 values (134); +insert into t1 values (133); +insert into t1 values (132); +insert into t1 values (131); +insert into t1 values (130); +insert into t1 values (129); +insert into t1 values (128); +insert into t1 values (127); +insert into t1 values (126); +insert into t1 values (125); +insert into t1 values (124); +insert into t1 values (123); +insert into t1 values (122); +insert into t1 values (121); +insert into t1 values (120); +insert into t1 values (119); +insert into t1 values (118); +insert into t1 values (117); +insert into t1 values (116); +insert into t1 values (115); +insert into t1 values (114); +insert into t1 values (113); +insert into t1 values (112); +insert into t1 values (111); +insert into t1 values (110); +insert into t1 values (109); +insert into t1 values (108); +insert into t1 values (107); +insert into t1 values (106); +insert into t1 values (105); +insert into t1 values (104); +insert into t1 values (103); +insert into t1 values (102); +insert into t1 values (101); +insert into t1 values (100); +insert into t1 values (99); +insert into t1 values (98); +insert into t1 values (97); +insert into t1 values (96); +insert into t1 values (95); +insert into t1 values (94); +insert into t1 values (93); +insert into t1 values (92); +insert into t1 values (91); +insert into t1 values (90); +insert into t1 values (89); +insert into t1 values (88); +insert into t1 values (87); +insert into t1 values (86); +insert into t1 values (85); +insert into t1 values (84); +insert into t1 values (83); +insert into t1 values (82); +insert into t1 values (81); +insert into t1 values (80); +insert into t1 values (79); +insert into t1 values (78); +insert into t1 values (77); +insert into t1 values (76); +insert into t1 values (75); +insert into t1 values (74); +insert into t1 values (73); +insert into t1 values (72); +insert into t1 values (71); +insert into t1 values (70); +insert into t1 values (69); +insert into t1 values (68); +insert into t1 values (67); +insert into t1 values (66); +insert into t1 values (65); +insert into t1 values (64); +insert into t1 values (63); +insert into t1 values (62); +insert into t1 values (61); +insert into t1 values (60); +insert into t1 values (59); +insert into t1 values (58); +insert into t1 values (57); +insert into t1 values (56); +insert into t1 values (55); +insert into t1 values (54); +insert into t1 values (53); +insert into t1 values (52); +insert into t1 values (51); +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 "The following are SLAVE."; +The following are SLAVE. +The following are SLAVE. +show status like 'Rpl_mirror_binlog_status'; +Variable_name Value +Rpl_mirror_binlog_status 0 +show status like 'Rpl_mirror_binlog_clients'; +Variable_name Value +Rpl_mirror_binlog_clients 0 +select count(distinct n) from t1; +count(distinct n) +200 +select min(n) from t1; +min(n) +1 +select max(n) from t1; +max(n) +200 +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +select "The following are SLAVE1."; +The following are SLAVE1. +The following are SLAVE1. +select count(distinct n) from t1; +count(distinct n) +100 +select min(n) from t1; +min(n) +1 +select max(n) from t1; +max(n) +100 +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root 9307 1 master-bin.002 2130 slave1-relay-bin.001 # master-bin.002 Yes Yes 0 0 2130 # None 0 +select "The following are SLAVE."; +The following are SLAVE. +The following are SLAVE. +stop slave; +set global rpl_mirror_binlog_enabled=1; +start slave; +insert into t1 values (300); +insert into t1 values (299); +insert into t1 values (298); +insert into t1 values (297); +insert into t1 values (296); +insert into t1 values (295); +insert into t1 values (294); +insert into t1 values (293); +insert into t1 values (292); +insert into t1 values (291); +insert into t1 values (290); +insert into t1 values (289); +insert into t1 values (288); +insert into t1 values (287); +insert into t1 values (286); +insert into t1 values (285); +insert into t1 values (284); +insert into t1 values (283); +insert into t1 values (282); +insert into t1 values (281); +insert into t1 values (280); +insert into t1 values (279); +insert into t1 values (278); +insert into t1 values (277); +insert into t1 values (276); +insert into t1 values (275); +insert into t1 values (274); +insert into t1 values (273); +insert into t1 values (272); +insert into t1 values (271); +insert into t1 values (270); +insert into t1 values (269); +insert into t1 values (268); +insert into t1 values (267); +insert into t1 values (266); +insert into t1 values (265); +insert into t1 values (264); +insert into t1 values (263); +insert into t1 values (262); +insert into t1 values (261); +insert into t1 values (260); +insert into t1 values (259); +insert into t1 values (258); +insert into t1 values (257); +insert into t1 values (256); +insert into t1 values (255); +insert into t1 values (254); +insert into t1 values (253); +insert into t1 values (252); +insert into t1 values (251); +insert into t1 values (250); +insert into t1 values (249); +insert into t1 values (248); +insert into t1 values (247); +insert into t1 values (246); +insert into t1 values (245); +insert into t1 values (244); +insert into t1 values (243); +insert into t1 values (242); +insert into t1 values (241); +insert into t1 values (240); +insert into t1 values (239); +insert into t1 values (238); +insert into t1 values (237); +insert into t1 values (236); +insert into t1 values (235); +insert into t1 values (234); +insert into t1 values (233); +insert into t1 values (232); +insert into t1 values (231); +insert into t1 values (230); +insert into t1 values (229); +insert into t1 values (228); +insert into t1 values (227); +insert into t1 values (226); +insert into t1 values (225); +insert into t1 values (224); +insert into t1 values (223); +insert into t1 values (222); +insert into t1 values (221); +insert into t1 values (220); +insert into t1 values (219); +insert into t1 values (218); +insert into t1 values (217); +insert into t1 values (216); +insert into t1 values (215); +insert into t1 values (214); +insert into t1 values (213); +insert into t1 values (212); +insert into t1 values (211); +insert into t1 values (210); +insert into t1 values (209); +insert into t1 values (208); +insert into t1 values (207); +insert into t1 values (206); +insert into t1 values (205); +insert into t1 values (204); +insert into t1 values (203); +insert into t1 values (202); +insert into t1 values (201); +insert into t1 values (200); +insert into t1 values (199); +insert into t1 values (198); +insert into t1 values (197); +insert into t1 values (196); +insert into t1 values (195); +insert into t1 values (194); +insert into t1 values (193); +insert into t1 values (192); +insert into t1 values (191); +insert into t1 values (190); +insert into t1 values (189); +insert into t1 values (188); +insert into t1 values (187); +insert into t1 values (186); +insert into t1 values (185); +insert into t1 values (184); +insert into t1 values (183); +insert into t1 values (182); +insert into t1 values (181); +insert into t1 values (180); +insert into t1 values (179); +insert into t1 values (178); +insert into t1 values (177); +insert into t1 values (176); +insert into t1 values (175); +insert into t1 values (174); +insert into t1 values (173); +insert into t1 values (172); +insert into t1 values (171); +insert into t1 values (170); +insert into t1 values (169); +insert into t1 values (168); +insert into t1 values (167); +insert into t1 values (166); +insert into t1 values (165); +insert into t1 values (164); +insert into t1 values (163); +insert into t1 values (162); +insert into t1 values (161); +insert into t1 values (160); +insert into t1 values (159); +insert into t1 values (158); +insert into t1 values (157); +insert into t1 values (156); +insert into t1 values (155); +insert into t1 values (154); +insert into t1 values (153); +insert into t1 values (152); +insert into t1 values (151); +insert into t1 values (150); +insert into t1 values (149); +insert into t1 values (148); +insert into t1 values (147); +insert into t1 values (146); +insert into t1 values (145); +insert into t1 values (144); +insert into t1 values (143); +insert into t1 values (142); +insert into t1 values (141); +insert into t1 values (140); +insert into t1 values (139); +insert into t1 values (138); +insert into t1 values (137); +insert into t1 values (136); +insert into t1 values (135); +insert into t1 values (134); +insert into t1 values (133); +insert into t1 values (132); +insert into t1 values (131); +insert into t1 values (130); +insert into t1 values (129); +insert into t1 values (128); +insert into t1 values (127); +insert into t1 values (126); +insert into t1 values (125); +insert into t1 values (124); +insert into t1 values (123); +insert into t1 values (122); +insert into t1 values (121); +insert into t1 values (120); +insert into t1 values (119); +insert into t1 values (118); +insert into t1 values (117); +insert into t1 values (116); +insert into t1 values (115); +insert into t1 values (114); +insert into t1 values (113); +insert into t1 values (112); +insert into t1 values (111); +insert into t1 values (110); +insert into t1 values (109); +insert into t1 values (108); +insert into t1 values (107); +insert into t1 values (106); +insert into t1 values (105); +insert into t1 values (104); +insert into t1 values (103); +insert into t1 values (102); +insert into t1 values (101); +insert into t1 values (100); +insert into t1 values (99); +insert into t1 values (98); +insert into t1 values (97); +insert into t1 values (96); +insert into t1 values (95); +insert into t1 values (94); +insert into t1 values (93); +insert into t1 values (92); +insert into t1 values (91); +insert into t1 values (90); +insert into t1 values (89); +insert into t1 values (88); +insert into t1 values (87); +insert into t1 values (86); +insert into t1 values (85); +insert into t1 values (84); +insert into t1 values (83); +insert into t1 values (82); +insert into t1 values (81); +insert into t1 values (80); +insert into t1 values (79); +insert into t1 values (78); +insert into t1 values (77); +insert into t1 values (76); +insert into t1 values (75); +insert into t1 values (74); +insert into t1 values (73); +insert into t1 values (72); +insert into t1 values (71); +insert into t1 values (70); +insert into t1 values (69); +insert into t1 values (68); +insert into t1 values (67); +insert into t1 values (66); +insert into t1 values (65); +insert into t1 values (64); +insert into t1 values (63); +insert into t1 values (62); +insert into t1 values (61); +insert into t1 values (60); +insert into t1 values (59); +insert into t1 values (58); +insert into t1 values (57); +insert into t1 values (56); +insert into t1 values (55); +insert into t1 values (54); +insert into t1 values (53); +insert into t1 values (52); +insert into t1 values (51); +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 "The following are SLAVE."; +The following are SLAVE. +The following are SLAVE. +show status like 'Rpl_mirror_binlog_status'; +Variable_name Value +Rpl_mirror_binlog_status 0 +show status like 'Rpl_mirror_binlog_clients'; +Variable_name Value +Rpl_mirror_binlog_clients 1 +select count(distinct n) from t1; +count(distinct n) +300 +select min(n) from t1; +min(n) +1 +select max(n) from t1; +max(n) +300 +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +select "The following are SLAVE1."; +The following are SLAVE1. +The following are SLAVE1. +select count(distinct n) from t1; +count(distinct n) +300 +select min(n) from t1; +min(n) +1 +select max(n) from t1; +max(n) +300 +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root 9307 1 master-bin.010 4 slave1-relay-bin.001 # master-bin.010 Yes Yes 0 0 4 # None 0 diff -ruN base/mysql-test/r/rpl_redirect.result mysql40gpl/mysql-test/r/rpl_redirect.result --- base/mysql-test/r/rpl_redirect.result 2005-09-02 15:50:38.000000000 -0700 +++ mysql40gpl/mysql-test/r/rpl_redirect.result 2007-04-21 09:56:53.000000000 -0700 @@ -5,7 +5,7 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; slave start; SHOW SLAVE STATUS; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos SHOW SLAVE HOSTS; Server_id Host Port Rpl_recovery_rank Master_id 2 127.0.0.1 SLAVE_PORT 2 1 diff -ruN base/mysql-test/r/rpl_reset_slave.result mysql40gpl/mysql-test/r/rpl_reset_slave.result --- base/mysql-test/r/rpl_reset_slave.result 2005-09-02 15:50:38.000000000 -0700 +++ mysql40gpl/mysql-test/r/rpl_reset_slave.result 2007-04-21 09:56:53.000000000 -0700 @@ -5,21 +5,21 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; slave start; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.001 79 slave-relay-bin.002 120 master-bin.001 Yes Yes 0 0 79 120 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 79 slave-relay-bin.002 120 master-bin.001 Yes Yes 0 0 79 120 None 0 stop slave; change master to master_user='test'; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 test MASTER_PORT 1 master-bin.001 79 slave-relay-bin.001 4 master-bin.001 No No 0 0 79 4 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 test MASTER_PORT 1 master-bin.001 79 slave-relay-bin.001 4 master-bin.001 No No 0 0 79 4 None 0 reset slave; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 4 slave-relay-bin.001 4 No No 0 0 0 4 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 4 slave-relay-bin.001 4 No No 0 0 0 4 None 0 start slave; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.001 79 slave-relay-bin.002 120 master-bin.001 Yes Yes 0 0 79 120 +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 79 slave-relay-bin.002 120 master-bin.001 Yes Yes 0 0 79 120 None 0 stop slave; reset slave; start slave; diff -ruN base/mysql-test/r/rpl_rotate_logs.result mysql40gpl/mysql-test/r/rpl_rotate_logs.result --- base/mysql-test/r/rpl_rotate_logs.result 2005-09-02 15:50:38.000000000 -0700 +++ mysql40gpl/mysql-test/r/rpl_rotate_logs.result 2007-04-21 09:56:53.000000000 -0700 @@ -15,8 +15,8 @@ create table t1 (s text); insert into t1 values('Could not break slave'),('Tried hard'); show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 60 master-bin.001 417 slave-relay-bin.001 458 master-bin.001 Yes Yes 0 0 417 # +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 60 master-bin.001 417 slave-relay-bin.001 458 master-bin.001 Yes Yes 0 0 417 # None 0 select * from t1; s Could not break slave @@ -46,8 +46,8 @@ master-bin.003 insert into t2 values (65); show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 60 master-bin.003 290 slave-relay-bin.001 1073 master-bin.003 Yes Yes 0 0 290 # +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 60 master-bin.003 290 slave-relay-bin.001 1073 master-bin.003 Yes Yes 0 0 290 # None 0 select * from t2; m 34 @@ -73,8 +73,8 @@ a testing temporary tables part 2 show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 60 master-bin.004 2886 slave-relay-bin.001 7870 master-bin.004 Yes Yes 0 0 2886 # +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 60 master-bin.004 2886 slave-relay-bin.001 7870 master-bin.004 Yes Yes 0 0 2886 # None 0 lock tables t3 read; select count(*) from t3 where n >= 4; count(*) diff -ruN base/mysql-test/r/rpl_semi_sync.result mysql40gpl/mysql-test/r/rpl_semi_sync.result --- base/mysql-test/r/rpl_semi_sync.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/r/rpl_semi_sync.result 2007-04-21 09:56:53.000000000 -0700 @@ -0,0 +1,400 @@ +slave stop; +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; +slave start; +show status like 'Rpl_semi_sync_no_tx'; +Variable_name Value +Rpl_semi_sync_no_tx 0 +show status like 'Rpl_semi_sync_yes_tx'; +Variable_name Value +Rpl_semi_sync_yes_tx 0 +stop slave; +start slave; +show status like 'Rpl_semi_sync_clients'; +Variable_name Value +Rpl_semi_sync_clients 1 +drop table if exists t1; +create table t1(n int) engine = InnoDB; +insert into t1 values (300); +insert into t1 values (299); +insert into t1 values (298); +insert into t1 values (297); +insert into t1 values (296); +insert into t1 values (295); +insert into t1 values (294); +insert into t1 values (293); +insert into t1 values (292); +insert into t1 values (291); +insert into t1 values (290); +insert into t1 values (289); +insert into t1 values (288); +insert into t1 values (287); +insert into t1 values (286); +insert into t1 values (285); +insert into t1 values (284); +insert into t1 values (283); +insert into t1 values (282); +insert into t1 values (281); +insert into t1 values (280); +insert into t1 values (279); +insert into t1 values (278); +insert into t1 values (277); +insert into t1 values (276); +insert into t1 values (275); +insert into t1 values (274); +insert into t1 values (273); +insert into t1 values (272); +insert into t1 values (271); +insert into t1 values (270); +insert into t1 values (269); +insert into t1 values (268); +insert into t1 values (267); +insert into t1 values (266); +insert into t1 values (265); +insert into t1 values (264); +insert into t1 values (263); +insert into t1 values (262); +insert into t1 values (261); +insert into t1 values (260); +insert into t1 values (259); +insert into t1 values (258); +insert into t1 values (257); +insert into t1 values (256); +insert into t1 values (255); +insert into t1 values (254); +insert into t1 values (253); +insert into t1 values (252); +insert into t1 values (251); +insert into t1 values (250); +insert into t1 values (249); +insert into t1 values (248); +insert into t1 values (247); +insert into t1 values (246); +insert into t1 values (245); +insert into t1 values (244); +insert into t1 values (243); +insert into t1 values (242); +insert into t1 values (241); +insert into t1 values (240); +insert into t1 values (239); +insert into t1 values (238); +insert into t1 values (237); +insert into t1 values (236); +insert into t1 values (235); +insert into t1 values (234); +insert into t1 values (233); +insert into t1 values (232); +insert into t1 values (231); +insert into t1 values (230); +insert into t1 values (229); +insert into t1 values (228); +insert into t1 values (227); +insert into t1 values (226); +insert into t1 values (225); +insert into t1 values (224); +insert into t1 values (223); +insert into t1 values (222); +insert into t1 values (221); +insert into t1 values (220); +insert into t1 values (219); +insert into t1 values (218); +insert into t1 values (217); +insert into t1 values (216); +insert into t1 values (215); +insert into t1 values (214); +insert into t1 values (213); +insert into t1 values (212); +insert into t1 values (211); +insert into t1 values (210); +insert into t1 values (209); +insert into t1 values (208); +insert into t1 values (207); +insert into t1 values (206); +insert into t1 values (205); +insert into t1 values (204); +insert into t1 values (203); +insert into t1 values (202); +insert into t1 values (201); +insert into t1 values (200); +insert into t1 values (199); +insert into t1 values (198); +insert into t1 values (197); +insert into t1 values (196); +insert into t1 values (195); +insert into t1 values (194); +insert into t1 values (193); +insert into t1 values (192); +insert into t1 values (191); +insert into t1 values (190); +insert into t1 values (189); +insert into t1 values (188); +insert into t1 values (187); +insert into t1 values (186); +insert into t1 values (185); +insert into t1 values (184); +insert into t1 values (183); +insert into t1 values (182); +insert into t1 values (181); +insert into t1 values (180); +insert into t1 values (179); +insert into t1 values (178); +insert into t1 values (177); +insert into t1 values (176); +insert into t1 values (175); +insert into t1 values (174); +insert into t1 values (173); +insert into t1 values (172); +insert into t1 values (171); +insert into t1 values (170); +insert into t1 values (169); +insert into t1 values (168); +insert into t1 values (167); +insert into t1 values (166); +insert into t1 values (165); +insert into t1 values (164); +insert into t1 values (163); +insert into t1 values (162); +insert into t1 values (161); +insert into t1 values (160); +insert into t1 values (159); +insert into t1 values (158); +insert into t1 values (157); +insert into t1 values (156); +insert into t1 values (155); +insert into t1 values (154); +insert into t1 values (153); +insert into t1 values (152); +insert into t1 values (151); +insert into t1 values (150); +insert into t1 values (149); +insert into t1 values (148); +insert into t1 values (147); +insert into t1 values (146); +insert into t1 values (145); +insert into t1 values (144); +insert into t1 values (143); +insert into t1 values (142); +insert into t1 values (141); +insert into t1 values (140); +insert into t1 values (139); +insert into t1 values (138); +insert into t1 values (137); +insert into t1 values (136); +insert into t1 values (135); +insert into t1 values (134); +insert into t1 values (133); +insert into t1 values (132); +insert into t1 values (131); +insert into t1 values (130); +insert into t1 values (129); +insert into t1 values (128); +insert into t1 values (127); +insert into t1 values (126); +insert into t1 values (125); +insert into t1 values (124); +insert into t1 values (123); +insert into t1 values (122); +insert into t1 values (121); +insert into t1 values (120); +insert into t1 values (119); +insert into t1 values (118); +insert into t1 values (117); +insert into t1 values (116); +insert into t1 values (115); +insert into t1 values (114); +insert into t1 values (113); +insert into t1 values (112); +insert into t1 values (111); +insert into t1 values (110); +insert into t1 values (109); +insert into t1 values (108); +insert into t1 values (107); +insert into t1 values (106); +insert into t1 values (105); +insert into t1 values (104); +insert into t1 values (103); +insert into t1 values (102); +insert into t1 values (101); +insert into t1 values (100); +insert into t1 values (99); +insert into t1 values (98); +insert into t1 values (97); +insert into t1 values (96); +insert into t1 values (95); +insert into t1 values (94); +insert into t1 values (93); +insert into t1 values (92); +insert into t1 values (91); +insert into t1 values (90); +insert into t1 values (89); +insert into t1 values (88); +insert into t1 values (87); +insert into t1 values (86); +insert into t1 values (85); +insert into t1 values (84); +insert into t1 values (83); +insert into t1 values (82); +insert into t1 values (81); +insert into t1 values (80); +insert into t1 values (79); +insert into t1 values (78); +insert into t1 values (77); +insert into t1 values (76); +insert into t1 values (75); +insert into t1 values (74); +insert into t1 values (73); +insert into t1 values (72); +insert into t1 values (71); +insert into t1 values (70); +insert into t1 values (69); +insert into t1 values (68); +insert into t1 values (67); +insert into t1 values (66); +insert into t1 values (65); +insert into t1 values (64); +insert into t1 values (63); +insert into t1 values (62); +insert into t1 values (61); +insert into t1 values (60); +insert into t1 values (59); +insert into t1 values (58); +insert into t1 values (57); +insert into t1 values (56); +insert into t1 values (55); +insert into t1 values (54); +insert into t1 values (53); +insert into t1 values (52); +insert into t1 values (51); +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); +show master status; +File Position Binlog_do_db Binlog_ignore_db +master-bin.000001 18644 +show status like 'Rpl_semi_sync_slave_status'; +Variable_name Value +Rpl_semi_sync_slave_status 1 +select count(distinct n) from t1; +count(distinct n) +300 +select min(n) from t1; +min(n) +1 +select max(n) from t1; +max(n) +300 +stop slave; +show status like 'Rpl_semi_sync_status'; +Variable_name Value +Rpl_semi_sync_status 1 +show status like 'Rpl_semi_sync_no_tx'; +Variable_name Value +Rpl_semi_sync_no_tx 0 +show status like 'Rpl_semi_sync_yes_tx'; +Variable_name Value +Rpl_semi_sync_yes_tx 301 +show status like 'Rpl_semi_sync_clients'; +Variable_name Value +Rpl_semi_sync_clients 1 +begin; +insert into t1 values (500); +delete from t1 where n < 500; +commit; +insert into t1 values (100); +show status like 'Rpl_semi_sync_status'; +Variable_name Value +Rpl_semi_sync_status 0 +show status like 'Rpl_semi_sync_no_tx'; +Variable_name Value +Rpl_semi_sync_no_tx 2 +show status like 'Rpl_semi_sync_yes_tx'; +Variable_name Value +Rpl_semi_sync_yes_tx 301 +show status like 'Rpl_semi_sync_slave_status'; +Variable_name Value +Rpl_semi_sync_slave_status 0 +start slave; +show status like 'Rpl_semi_sync_slave_status'; +Variable_name Value +Rpl_semi_sync_slave_status 1 +select count(distinct n) from t1; +count(distinct n) +2 +select min(n) from t1; +min(n) +100 +select max(n) from t1; +max(n) +500 +drop table t1; +show status like 'Rpl_semi_sync_status'; +Variable_name Value +Rpl_semi_sync_status 1 +show status like 'Rpl_semi_sync_no_tx'; +Variable_name Value +Rpl_semi_sync_no_tx 2 +show status like 'Rpl_semi_sync_yes_tx'; +Variable_name Value +Rpl_semi_sync_yes_tx 302 +show master logs; +Log_name +master-bin.000001 +show variables like 'rpl_semi_sync_enabled'; +Variable_name Value +rpl_semi_sync_enabled 1 +set global rpl_semi_sync_enabled=0; +show variables like 'rpl_semi_sync_enabled'; +Variable_name Value +rpl_semi_sync_enabled 0 +show status like 'Rpl_semi_sync_status'; +Variable_name Value +Rpl_semi_sync_status 0 diff -ruN base/mysql-test/r/rpl_server_id1.result mysql40gpl/mysql-test/r/rpl_server_id1.result --- base/mysql-test/r/rpl_server_id1.result 2005-09-02 15:50:38.000000000 -0700 +++ mysql40gpl/mysql-test/r/rpl_server_id1.result 2007-04-21 09:56:53.000000000 -0700 @@ -10,8 +10,8 @@ stop slave; change master to master_port=SLAVE_PORT; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root SLAVE_PORT 1 4 slave-relay-bin.001 4 No No 0 0 0 # +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root SLAVE_PORT 1 4 slave-relay-bin.001 4 No No 0 0 0 # None 0 start slave; insert into t1 values (1); show status like "slave_running"; diff -ruN base/mysql-test/r/rpl_server_id2.result mysql40gpl/mysql-test/r/rpl_server_id2.result --- base/mysql-test/r/rpl_server_id2.result 2005-09-02 15:50:38.000000000 -0700 +++ mysql40gpl/mysql-test/r/rpl_server_id2.result 2007-04-21 09:56:53.000000000 -0700 @@ -9,8 +9,8 @@ stop slave; change master to master_port=SLAVE_PORT; show slave status; -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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root SLAVE_PORT 1 4 slave-relay-bin.001 4 No No 0 0 0 # +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root SLAVE_PORT 1 4 slave-relay-bin.001 4 No No 0 0 0 # None 0 start slave; insert into t1 values (1); select * from t1; diff -ruN base/mysql-test/r/rpl_show_processlist.result mysql40gpl/mysql-test/r/rpl_show_processlist.result --- base/mysql-test/r/rpl_show_processlist.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/r/rpl_show_processlist.result 2007-04-21 09:56:53.000000000 -0700 @@ -0,0 +1,323 @@ +slave stop; +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; +slave start; +drop table if exists t1; +create table t1(n int); +insert into t1 values (300); +insert into t1 values (299); +insert into t1 values (298); +insert into t1 values (297); +insert into t1 values (296); +insert into t1 values (295); +insert into t1 values (294); +insert into t1 values (293); +insert into t1 values (292); +insert into t1 values (291); +insert into t1 values (290); +insert into t1 values (289); +insert into t1 values (288); +insert into t1 values (287); +insert into t1 values (286); +insert into t1 values (285); +insert into t1 values (284); +insert into t1 values (283); +insert into t1 values (282); +insert into t1 values (281); +insert into t1 values (280); +insert into t1 values (279); +insert into t1 values (278); +insert into t1 values (277); +insert into t1 values (276); +insert into t1 values (275); +insert into t1 values (274); +insert into t1 values (273); +insert into t1 values (272); +insert into t1 values (271); +insert into t1 values (270); +insert into t1 values (269); +insert into t1 values (268); +insert into t1 values (267); +insert into t1 values (266); +insert into t1 values (265); +insert into t1 values (264); +insert into t1 values (263); +insert into t1 values (262); +insert into t1 values (261); +insert into t1 values (260); +insert into t1 values (259); +insert into t1 values (258); +insert into t1 values (257); +insert into t1 values (256); +insert into t1 values (255); +insert into t1 values (254); +insert into t1 values (253); +insert into t1 values (252); +insert into t1 values (251); +insert into t1 values (250); +insert into t1 values (249); +insert into t1 values (248); +insert into t1 values (247); +insert into t1 values (246); +insert into t1 values (245); +insert into t1 values (244); +insert into t1 values (243); +insert into t1 values (242); +insert into t1 values (241); +insert into t1 values (240); +insert into t1 values (239); +insert into t1 values (238); +insert into t1 values (237); +insert into t1 values (236); +insert into t1 values (235); +insert into t1 values (234); +insert into t1 values (233); +insert into t1 values (232); +insert into t1 values (231); +insert into t1 values (230); +insert into t1 values (229); +insert into t1 values (228); +insert into t1 values (227); +insert into t1 values (226); +insert into t1 values (225); +insert into t1 values (224); +insert into t1 values (223); +insert into t1 values (222); +insert into t1 values (221); +insert into t1 values (220); +insert into t1 values (219); +insert into t1 values (218); +insert into t1 values (217); +insert into t1 values (216); +insert into t1 values (215); +insert into t1 values (214); +insert into t1 values (213); +insert into t1 values (212); +insert into t1 values (211); +insert into t1 values (210); +insert into t1 values (209); +insert into t1 values (208); +insert into t1 values (207); +insert into t1 values (206); +insert into t1 values (205); +insert into t1 values (204); +insert into t1 values (203); +insert into t1 values (202); +insert into t1 values (201); +insert into t1 values (200); +insert into t1 values (199); +insert into t1 values (198); +insert into t1 values (197); +insert into t1 values (196); +insert into t1 values (195); +insert into t1 values (194); +insert into t1 values (193); +insert into t1 values (192); +insert into t1 values (191); +insert into t1 values (190); +insert into t1 values (189); +insert into t1 values (188); +insert into t1 values (187); +insert into t1 values (186); +insert into t1 values (185); +insert into t1 values (184); +insert into t1 values (183); +insert into t1 values (182); +insert into t1 values (181); +insert into t1 values (180); +insert into t1 values (179); +insert into t1 values (178); +insert into t1 values (177); +insert into t1 values (176); +insert into t1 values (175); +insert into t1 values (174); +insert into t1 values (173); +insert into t1 values (172); +insert into t1 values (171); +insert into t1 values (170); +insert into t1 values (169); +insert into t1 values (168); +insert into t1 values (167); +insert into t1 values (166); +insert into t1 values (165); +insert into t1 values (164); +insert into t1 values (163); +insert into t1 values (162); +insert into t1 values (161); +insert into t1 values (160); +insert into t1 values (159); +insert into t1 values (158); +insert into t1 values (157); +insert into t1 values (156); +insert into t1 values (155); +insert into t1 values (154); +insert into t1 values (153); +insert into t1 values (152); +insert into t1 values (151); +insert into t1 values (150); +insert into t1 values (149); +insert into t1 values (148); +insert into t1 values (147); +insert into t1 values (146); +insert into t1 values (145); +insert into t1 values (144); +insert into t1 values (143); +insert into t1 values (142); +insert into t1 values (141); +insert into t1 values (140); +insert into t1 values (139); +insert into t1 values (138); +insert into t1 values (137); +insert into t1 values (136); +insert into t1 values (135); +insert into t1 values (134); +insert into t1 values (133); +insert into t1 values (132); +insert into t1 values (131); +insert into t1 values (130); +insert into t1 values (129); +insert into t1 values (128); +insert into t1 values (127); +insert into t1 values (126); +insert into t1 values (125); +insert into t1 values (124); +insert into t1 values (123); +insert into t1 values (122); +insert into t1 values (121); +insert into t1 values (120); +insert into t1 values (119); +insert into t1 values (118); +insert into t1 values (117); +insert into t1 values (116); +insert into t1 values (115); +insert into t1 values (114); +insert into t1 values (113); +insert into t1 values (112); +insert into t1 values (111); +insert into t1 values (110); +insert into t1 values (109); +insert into t1 values (108); +insert into t1 values (107); +insert into t1 values (106); +insert into t1 values (105); +insert into t1 values (104); +insert into t1 values (103); +insert into t1 values (102); +insert into t1 values (101); +insert into t1 values (100); +insert into t1 values (99); +insert into t1 values (98); +insert into t1 values (97); +insert into t1 values (96); +insert into t1 values (95); +insert into t1 values (94); +insert into t1 values (93); +insert into t1 values (92); +insert into t1 values (91); +insert into t1 values (90); +insert into t1 values (89); +insert into t1 values (88); +insert into t1 values (87); +insert into t1 values (86); +insert into t1 values (85); +insert into t1 values (84); +insert into t1 values (83); +insert into t1 values (82); +insert into t1 values (81); +insert into t1 values (80); +insert into t1 values (79); +insert into t1 values (78); +insert into t1 values (77); +insert into t1 values (76); +insert into t1 values (75); +insert into t1 values (74); +insert into t1 values (73); +insert into t1 values (72); +insert into t1 values (71); +insert into t1 values (70); +insert into t1 values (69); +insert into t1 values (68); +insert into t1 values (67); +insert into t1 values (66); +insert into t1 values (65); +insert into t1 values (64); +insert into t1 values (63); +insert into t1 values (62); +insert into t1 values (61); +insert into t1 values (60); +insert into t1 values (59); +insert into t1 values (58); +insert into t1 values (57); +insert into t1 values (56); +insert into t1 values (55); +insert into t1 values (54); +insert into t1 values (53); +insert into t1 values (52); +insert into t1 values (51); +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); +show processlist; +Id User Host db Command Time State Info +# root # test Sleep # NULL +# root # test Query # NULL show processlist +# root # test Sleep # NULL +# root # NULL Binlog Dump # Has sent all binlog to slave; waiting for binlog to be updated :master-bin.001:18628: NULL +delete from t1 where n > 50; +delete from t1 where n > 25; +drop table t1; +show processlist; +Id User Host db Command Time State Info +# root # test Sleep # NULL +# root # test Query # NULL show processlist +# root # test Sleep # NULL +# root # NULL Binlog Dump # Has sent all binlog to slave; waiting for binlog to be updated :master-bin.001:18800: NULL diff -ruN base/mysql-test/r/variables.result mysql40gpl/mysql-test/r/variables.result --- base/mysql-test/r/variables.result 2005-09-02 15:50:38.000000000 -0700 +++ mysql40gpl/mysql-test/r/variables.result 2007-04-21 09:56:54.000000000 -0700 @@ -100,6 +100,26 @@ show variables like 'concurrent_insert'; Variable_name Value concurrent_insert ON +set global innodb_btr_estimate_n_pages=1; +show variables like 'innodb_btr_estimate_n_pages'; +Variable_name Value +innodb_btr_estimate_n_pages 1 +set global innodb_btr_estimate_n_pages=0; +show variables like 'innodb_btr_estimate_n_pages'; +Variable_name Value +innodb_btr_estimate_n_pages 1 +set global innodb_btr_estimate_n_pages=100; +show variables like 'innodb_btr_estimate_n_pages'; +Variable_name Value +innodb_btr_estimate_n_pages 100 +set global innodb_btr_estimate_n_pages=10000; +show variables like 'innodb_btr_estimate_n_pages'; +Variable_name Value +innodb_btr_estimate_n_pages 2048 +set global innodb_btr_estimate_n_pages=DEFAULT; +show variables like 'innodb_btr_estimate_n_pages'; +Variable_name Value +innodb_btr_estimate_n_pages 8 set table_type=MYISAM, table_type="HEAP", global table_type="INNODB"; show local variables like 'table_type'; Variable_name Value @@ -282,7 +302,7 @@ set join_buffer_size=100; set last_insert_id=1; set global local_infile=1; -set long_query_time=100; +set global long_query_time=100; set low_priority_updates=1; set max_allowed_packet=100; set global max_binlog_cache_size=100; @@ -290,6 +310,7 @@ set global max_connect_errors=100; set global max_connections=100; set global max_delayed_threads=100; +set global reserved_super_connections=10; set max_heap_table_size=100; set max_join_size=100; set max_sort_length=100; diff -ruN base/mysql-test/rpl_transaction_test/r/rpl000003.result mysql40gpl/mysql-test/rpl_transaction_test/r/rpl000003.result --- base/mysql-test/rpl_transaction_test/r/rpl000003.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/rpl_transaction_test/r/rpl000003.result 2007-04-21 09:56:54.000000000 -0700 @@ -0,0 +1,15 @@ +slave stop; +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; +slave start; +drop table if exists t1; +create table t1(n int primary key); +insert into t1 values (1),(2),(2); +Duplicate entry '2' for key 1 +insert into t1 values (3); +select * from t1; +n +3 +drop table t1; diff -ruN base/mysql-test/rpl_transaction_test/r/rpl000015.result mysql40gpl/mysql-test/rpl_transaction_test/r/rpl000015.result --- base/mysql-test/rpl_transaction_test/r/rpl000015.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/rpl_transaction_test/r/rpl000015.result 2007-04-21 09:56:54.000000000 -0700 @@ -0,0 +1,29 @@ +reset master; +show master status; +File Position Binlog_do_db Binlog_ignore_db +master-bin.001 79 +reset slave; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +change master to master_host='127.0.0.1'; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 test MASTER_PORT 7 4 slave-relay-bin.001 4 No No 0 0 0 4 None 0 +change master to master_host='127.0.0.1',master_user='root', +master_password='',master_port=MASTER_PORT; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 7 4 slave-relay-bin.001 4 No No 0 0 0 4 None 0 +slave start; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 7 master-bin.001 79 slave-relay-bin.001 120 master-bin.001 Yes Yes 0 0 79 120 None 0 +drop table if exists t1; +create table t1 (n int); +insert into t1 values (10),(45),(90); +select * from t1; +n +10 +45 +90 +drop table t1; diff -ruN base/mysql-test/rpl_transaction_test/r/rpl_change_master.result mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_change_master.result --- base/mysql-test/rpl_transaction_test/r/rpl_change_master.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_change_master.result 2007-04-21 09:56:54.000000000 -0700 @@ -0,0 +1,32 @@ +slave stop; +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; +slave start; +select get_lock("a",5); +get_lock("a",5) +1 +create table t1(n int); +insert into t1 values(1+get_lock("a",15)*0); +insert into t1 values(2); +stop slave; +select * from t1; +n +1 +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_MYPORT 1 master-bin.001 273 slave-relay-bin.002 255 master-bin.001 No No 0 0 214 318 None 0 +change master to master_user='root'; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_MYPORT 1 master-bin.001 214 slave-relay-bin.001 4 master-bin.001 No No 0 0 214 4 None 0 +select release_lock("a"); +release_lock("a") +1 +start slave; +select * from t1; +n +1 +2 +drop table t1; diff -ruN base/mysql-test/rpl_transaction_test/r/rpl_error_ignored_table.result mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_error_ignored_table.result --- base/mysql-test/rpl_transaction_test/r/rpl_error_ignored_table.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_error_ignored_table.result 2007-04-21 09:56:54.000000000 -0700 @@ -0,0 +1,40 @@ +slave stop; +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; +slave start; +create table t1 (a int primary key); +insert into t1 values (1),(1); +Duplicate entry '1' for key 1 +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 213 slave-relay-bin.002 254 master-bin.001 Yes Yes 0 0 213 258 None 0 +show tables like 't1'; +Tables_in_test (t1) +drop table t1; +select get_lock('crash_lock%20C', 10); +get_lock('crash_lock%20C', 10) +1 +create table t2 (a int primary key); +insert into t2 values(1); +create table t3 (id int); +insert into t3 values(connection_id()); + update t2 set a = a + 1 + get_lock('crash_lock%20C', 10); +select (@id := id) - id from t3; +(@id := id) - id +0 +kill @id; +drop table t2,t3; +Got one of the listed errors +show binlog events from 79; +Log_name Pos Event_type Server_id Orig_log_pos Info +master-bin.001 79 Query 1 79 use `test`; create table t1 (a int primary key) +master-bin.001 149 Query 1 149 use `test`; insert into t1 values (1),(1) +master-bin.001 213 Query 1 213 use `test`; drop table t1 +master-bin.001 261 Query 1 261 use `test`; create table t2 (a int primary key) +master-bin.001 331 Query 1 331 use `test`; insert into t2 values(1) +master-bin.001 390 Query 1 390 use `test`; create table t3 (id int) +master-bin.001 449 Query 1 449 use `test`; insert into t3 values(connection_id()) +master-bin.001 522 Query 1 522 use `test`; update t2 set a = a + 1 + get_lock('crash_lock%20C', 10) +master-bin.001 613 Query 1 613 use `test`; drop table t2,t3 diff -ruN base/mysql-test/rpl_transaction_test/r/rpl_flush_log_loop.result mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_flush_log_loop.result --- base/mysql-test/rpl_transaction_test/r/rpl_flush_log_loop.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_flush_log_loop.result 2007-04-21 09:56:54.000000000 -0700 @@ -0,0 +1,17 @@ +slave stop; +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; +slave start; +change master to master_host='127.0.0.1',master_user='root', +master_password='',master_port=MASTER_PORT; +slave start; +slave stop; +change master to master_host='127.0.0.1',master_user='root', +master_password='',master_port=SLAVE_PORT; +slave start; +flush logs; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root SLAVE_PORT 60 slave-bin.001 79 relay-log.002 44 slave-bin.001 Yes Yes 0 0 79 163 None 0 diff -ruN base/mysql-test/rpl_transaction_test/r/rpl_loaddata.result mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_loaddata.result --- base/mysql-test/rpl_transaction_test/r/rpl_loaddata.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_loaddata.result 2007-04-21 09:56:54.000000000 -0700 @@ -0,0 +1,68 @@ +slave stop; +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; +slave start; +reset master; +create table t1(a int not null auto_increment, b int, primary key(a) ); +load data infile '../../std_data/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/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.001 964 +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/rpl_loaddata.dat' into table t1; +set global sql_slave_skip_counter=1; +start slave; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 1311 slave-relay-bin.002 1352 master-bin.001 Yes Yes 0 0 1311 1356 None 0 +set sql_log_bin=0; +delete from t1; +set sql_log_bin=1; +load data infile '../../std_data/rpl_loaddata.dat' into table t1; +stop slave; +change master to master_user='test'; +change master to master_user='root'; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 1419 slave-relay-bin.001 4 master-bin.001 No No 0 0 1419 4 None 0 +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/rpl_loaddata.dat' into table t1; +stop slave; +reset slave; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 4 slave-relay-bin.001 4 No No 0 0 0 4 None 0 +reset master; +create table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60), +unique(day)); +load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields +terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by +'\n##\n' starting by '>' ignore 1 lines; +Duplicate entry '2003-03-22' for key 1 +show master status; +File Position Binlog_do_db Binlog_ignore_db +master-bin.001 491 +drop table t2; diff -ruN base/mysql-test/rpl_transaction_test/r/rpl_log_pos.result mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_log_pos.result --- base/mysql-test/rpl_transaction_test/r/rpl_log_pos.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_log_pos.result 2007-04-21 09:56:54.000000000 -0700 @@ -0,0 +1,46 @@ +slave stop; +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; +slave start; +show master status; +File Position Binlog_do_db Binlog_ignore_db +master-bin.001 79 +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 79 slave-relay-bin.002 120 master-bin.001 Yes Yes 0 0 79 124 None 0 +slave stop; +change master to master_log_pos=73; +slave start; +slave stop; +change master to master_log_pos=73; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 73 slave-relay-bin.001 4 master-bin.001 No No 0 0 73 4 None 0 +slave start; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 73 slave-relay-bin.001 86 master-bin.001 No Yes 0 0 73 45 None 0 +slave stop; +change master to master_log_pos=173; +slave start; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 173 slave-relay-bin.001 45 master-bin.001 No Yes 0 0 173 4 None 0 +show master status; +File Position Binlog_do_db Binlog_ignore_db +master-bin.001 79 +create table if not exists t1 (n int); +drop table if exists t1; +create table t1 (n int); +insert into t1 values (1),(2),(3); +slave stop; +change master to master_log_pos=79; +slave start; +select * from t1; +n +1 +2 +3 +drop table t1; diff -ruN base/mysql-test/rpl_transaction_test/r/rpl_log.result mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_log.result --- base/mysql-test/rpl_transaction_test/r/rpl_log.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_log.result 2007-04-21 09:56:54.000000000 -0700 @@ -0,0 +1,101 @@ +slave stop; +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; +slave start; +slave stop; +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/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 Orig_log_pos Info +master-bin.001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3 +master-bin.001 79 Query 1 79 use `test`; create table t1(n int not null auto_increment primary key) +master-bin.001 172 Intvar 1 172 INSERT_ID=1 +master-bin.001 200 Query 1 200 use `test`; insert into t1 values (NULL) +master-bin.001 263 Query 1 263 use `test`; drop table t1 +master-bin.001 311 Query 1 311 use `test`; create table t1 (word char(20) not null) +master-bin.001 386 Create_file 1 386 db=test;table=t1;file_id=1;block_len=581 +master-bin.001 1056 Exec_load 1 1056 ;file_id=1 +master-bin.001 1079 Query 1 1079 use `test`; drop table t1 +show binlog events from 79 limit 1; +Log_name Pos Event_type Server_id Orig_log_pos Info +master-bin.001 79 Query 1 79 use `test`; create table t1(n int not null auto_increment primary key) +show binlog events from 79 limit 2; +Log_name Pos Event_type Server_id Orig_log_pos Info +master-bin.001 79 Query 1 79 use `test`; create table t1(n int not null auto_increment primary key) +master-bin.001 172 Intvar 1 172 INSERT_ID=1 +show binlog events from 79 limit 2,1; +Log_name Pos Event_type Server_id Orig_log_pos Info +master-bin.001 200 Query 1 200 use `test`; insert into t1 values (NULL) +flush logs; +create table t5 (a int); +drop table t5; +slave start; +flush logs; +slave stop; +create table t1 (n int); +insert into t1 values (1); +drop table t1; +show binlog events; +Log_name Pos Event_type Server_id Orig_log_pos Info +master-bin.001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3 +master-bin.001 79 Query 1 79 use `test`; create table t1(n int not null auto_increment primary key) +master-bin.001 172 Intvar 1 172 INSERT_ID=1 +master-bin.001 200 Query 1 200 use `test`; insert into t1 values (NULL) +master-bin.001 263 Query 1 263 use `test`; drop table t1 +master-bin.001 311 Query 1 311 use `test`; create table t1 (word char(20) not null) +master-bin.001 386 Create_file 1 386 db=test;table=t1;file_id=1;block_len=581 +master-bin.001 1056 Exec_load 1 1056 ;file_id=1 +master-bin.001 1079 Query 1 1079 use `test`; drop table t1 +master-bin.001 1127 Rotate 1 1127 master-bin.002;pos=4 +show binlog events in 'master-bin.002'; +Log_name Pos Event_type Server_id Orig_log_pos Info +master-bin.002 4 Query 1 4 use `test`; create table t5 (a int) +master-bin.002 62 Query 1 62 use `test`; drop table t5 +master-bin.002 110 Query 1 110 use `test`; create table t1 (n int) +master-bin.002 168 Query 1 168 use `test`; insert into t1 values (1) +master-bin.002 228 Query 1 228 use `test`; drop table t1 +show master logs; +Log_name +master-bin.001 +master-bin.002 +slave start; +show master logs; +Log_name +slave-bin.001 +slave-bin.002 +show binlog events in 'slave-bin.001' from 4; +Log_name Pos Event_type Server_id Orig_log_pos Info +slave-bin.001 4 Start 2 4 Server ver: VERSION, Binlog ver: 3 +slave-bin.001 79 Query 1 79 use `test`; create table t1(n int not null auto_increment primary key) +slave-bin.001 172 Intvar 1 172 INSERT_ID=1 +slave-bin.001 200 Query 1 200 use `test`; insert into t1 values (NULL) +slave-bin.001 263 Query 1 263 use `test`; drop table t1 +slave-bin.001 311 Query 1 311 use `test`; create table t1 (word char(20) not null) +slave-bin.001 386 Create_file 1 386 db=test;table=t1;file_id=1;block_len=581 +slave-bin.001 1065 Exec_load 1 1065 ;file_id=1 +slave-bin.001 1088 Query 1 1088 use `test`; drop table t1 +slave-bin.001 1136 Query 1 1136 use `test`; create table t5 (a int) +slave-bin.001 1194 Query 1 1194 use `test`; drop table t5 +slave-bin.001 1242 Rotate 2 1242 slave-bin.002;pos=4 +show binlog events in 'slave-bin.002' from 4; +Log_name Pos Event_type Server_id Orig_log_pos Info +slave-bin.002 4 Query 1 4 use `test`; create table t1 (n int) +slave-bin.002 62 Query 1 62 use `test`; insert into t1 values (1) +slave-bin.002 122 Query 1 122 use `test`; drop table t1 +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.002 276 slave-relay-bin.003 252 master-bin.002 Yes Yes 0 0 276 1612 None 0 +show binlog events in 'slave-bin.005' from 4; +Error when executing command SHOW BINLOG EVENTS: Could not find target log diff -ruN base/mysql-test/rpl_transaction_test/r/rpl_max_relay_size.result mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_max_relay_size.result --- base/mysql-test/rpl_transaction_test/r/rpl_max_relay_size.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_max_relay_size.result 2007-04-21 09:56:54.000000000 -0700 @@ -0,0 +1,61 @@ +slave stop; +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; +slave start; +stop slave; +create table t1 (a int); +drop table t1; +reset slave; +set global max_binlog_size=8192; +set global max_relay_log_size=8192-1; +select @@global.max_relay_log_size; +@@global.max_relay_log_size +4096 +start slave; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 50477 slave-relay-bin.014 1386 master-bin.001 Yes Yes 0 0 50477 1390 None 0 +stop slave; +reset slave; +set global max_relay_log_size=(5*4096); +select @@global.max_relay_log_size; +@@global.max_relay_log_size +20480 +start slave; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 50477 slave-relay-bin.004 9561 master-bin.001 Yes Yes 0 0 50477 # None 0 +stop slave; +reset slave; +set global max_relay_log_size=0; +select @@global.max_relay_log_size; +@@global.max_relay_log_size +0 +start slave; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 50477 slave-relay-bin.008 1386 master-bin.001 Yes Yes 0 0 50477 1390 None 0 +stop slave; +reset slave; +flush logs; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 4 slave-relay-bin.001 4 No No 0 0 0 4 None 0 +reset slave; +start slave; +flush logs; +create table t1 (a int); +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 50535 slave-relay-bin.009 103 master-bin.001 Yes Yes 0 0 50535 1493 None 0 +flush logs; +drop table t1; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 50583 slave-relay-bin.010 93 master-bin.001 Yes Yes 0 0 50583 1483 None 0 +flush logs; +show master status; +File Position Binlog_do_db Binlog_ignore_db +master-bin.002 4 diff -ruN base/mysql-test/rpl_transaction_test/r/rpl_reset_slave.result mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_reset_slave.result --- base/mysql-test/rpl_transaction_test/r/rpl_reset_slave.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_reset_slave.result 2007-04-21 09:56:54.000000000 -0700 @@ -0,0 +1,32 @@ +slave stop; +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; +slave start; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 79 slave-relay-bin.002 120 master-bin.001 Yes Yes 0 0 79 124 None 0 +stop slave; +change master to master_user='test'; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 test MASTER_PORT 1 master-bin.001 79 slave-relay-bin.001 4 master-bin.001 No No 0 0 79 4 None 0 +reset slave; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 4 slave-relay-bin.001 4 No No 0 0 0 4 None 0 +start slave; +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 1 master-bin.001 79 slave-relay-bin.002 120 master-bin.001 Yes Yes 0 0 79 124 None 0 +stop slave; +reset slave; +start slave; +create temporary table t1 (a int); +stop slave; +reset slave; +start slave; +show status like 'slave_open_temp_tables'; +Variable_name Value +Slave_open_temp_tables 1 diff -ruN base/mysql-test/rpl_transaction_test/r/rpl_rotate_logs.result mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_rotate_logs.result --- base/mysql-test/rpl_transaction_test/r/rpl_rotate_logs.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_rotate_logs.result 2007-04-21 09:56:54.000000000 -0700 @@ -0,0 +1,83 @@ +drop table if exists t1, t2, t3, t4; +drop table if exists t1, t2, t3, t4; +slave start; +Could not initialize master info structure, more error messages can be found in the MySQL error log +slave start; +Could not initialize master info structure, more error messages can be found in the MySQL error log +change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root'; +Could not initialize master info structure, more error messages can be found in the MySQL error log +reset slave; +change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root'; +reset master; +slave start; +create temporary table temp_table (a char(80) not null); +insert into temp_table values ("testing temporary tables"); +create table t1 (s text); +insert into t1 values('Could not break slave'),('Tried hard'); +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 60 master-bin.001 417 slave-relay-bin.001 458 master-bin.001 Yes Yes 0 0 417 # None 0 +select * from t1; +s +Could not break slave +Tried hard +flush logs; +create table t2(m int not null auto_increment primary key); +insert into t2 values (34),(67),(123); +flush logs; +show master logs; +Log_name +master-bin.001 +master-bin.002 +master-bin.003 +create table t3 select * from temp_table; +select * from t3; +a +testing temporary tables +drop table temp_table, t3; +insert into t2 values(1234); +set insert_id=1234; +insert into t2 values(NULL); +set global sql_slave_skip_counter=1; +slave start; +purge master logs to 'master-bin.003'; +show master logs; +Log_name +master-bin.003 +insert into t2 values (65); +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 60 master-bin.003 290 slave-relay-bin.001 1073 master-bin.003 Yes Yes 0 0 290 # None 0 +select * from t2; +m +34 +65 +67 +123 +1234 +create temporary table temp_table (a char(80) not null); +insert into temp_table values ("testing temporary tables part 2"); +create table t3 (n int); +select count(*) from t3 where n >= 4; +count(*) +100 +create table t4 select * from temp_table; +show master logs; +Log_name +master-bin.003 +master-bin.004 +show master status; +File Position Binlog_do_db Binlog_ignore_db +master-bin.004 2886 +select * from t4; +a +testing temporary tables part 2 +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root MASTER_PORT 60 master-bin.004 2886 slave-relay-bin.001 7870 master-bin.004 Yes Yes 0 0 2886 # None 0 +lock tables t3 read; +select count(*) from t3 where n >= 4; +count(*) +100 +unlock tables; +drop table if exists t1,t2,t3,t4; diff -ruN base/mysql-test/rpl_transaction_test/r/rpl_transaction_001.result mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_transaction_001.result --- base/mysql-test/rpl_transaction_test/r/rpl_transaction_001.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_transaction_001.result 2007-04-21 09:56:54.000000000 -0700 @@ -0,0 +1,143 @@ +slave stop; +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; +slave start; +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; +Table 'test.ign1' doesn't exist +drop table t1; +drop database ignore_db; diff -ruN base/mysql-test/rpl_transaction_test/r/rpl_transaction_002.result mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_transaction_002.result --- base/mysql-test/rpl_transaction_test/r/rpl_transaction_002.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/rpl_transaction_test/r/rpl_transaction_002.result 2007-04-21 09:56:54.000000000 -0700 @@ -0,0 +1,264 @@ +slave stop; +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; +slave start; +drop table if exists t1; +create table t1(n int) engine = InnoDB; +use test; +begin; +insert into t1 values (300); +insert into t1 values (299); +insert into t1 values (298); +insert into t1 values (297); +insert into t1 values (296); +insert into t1 values (295); +insert into t1 values (294); +insert into t1 values (293); +insert into t1 values (292); +insert into t1 values (291); +insert into t1 values (290); +insert into t1 values (289); +insert into t1 values (288); +insert into t1 values (287); +insert into t1 values (286); +insert into t1 values (285); +insert into t1 values (284); +insert into t1 values (283); +insert into t1 values (282); +insert into t1 values (281); +insert into t1 values (280); +insert into t1 values (279); +insert into t1 values (278); +insert into t1 values (277); +insert into t1 values (276); +insert into t1 values (275); +insert into t1 values (274); +insert into t1 values (273); +insert into t1 values (272); +insert into t1 values (271); +insert into t1 values (270); +insert into t1 values (269); +insert into t1 values (268); +insert into t1 values (267); +insert into t1 values (266); +insert into t1 values (265); +insert into t1 values (264); +insert into t1 values (263); +insert into t1 values (262); +insert into t1 values (261); +insert into t1 values (260); +insert into t1 values (259); +insert into t1 values (258); +insert into t1 values (257); +insert into t1 values (256); +insert into t1 values (255); +insert into t1 values (254); +insert into t1 values (253); +insert into t1 values (252); +insert into t1 values (251); +insert into t1 values (250); +insert into t1 values (249); +insert into t1 values (248); +insert into t1 values (247); +insert into t1 values (246); +insert into t1 values (245); +insert into t1 values (244); +insert into t1 values (243); +insert into t1 values (242); +insert into t1 values (241); +insert into t1 values (240); +insert into t1 values (239); +insert into t1 values (238); +insert into t1 values (237); +insert into t1 values (236); +insert into t1 values (235); +insert into t1 values (234); +insert into t1 values (233); +insert into t1 values (232); +insert into t1 values (231); +insert into t1 values (230); +insert into t1 values (229); +insert into t1 values (228); +insert into t1 values (227); +insert into t1 values (226); +insert into t1 values (225); +insert into t1 values (224); +insert into t1 values (223); +insert into t1 values (222); +insert into t1 values (221); +commit; +insert into t1 values (700); +begin; +insert into t1 values (300); +insert into t1 values (299); +insert into t1 values (298); +insert into t1 values (297); +insert into t1 values (296); +insert into t1 values (295); +insert into t1 values (294); +insert into t1 values (293); +insert into t1 values (292); +insert into t1 values (291); +insert into t1 values (290); +insert into t1 values (289); +insert into t1 values (288); +insert into t1 values (287); +insert into t1 values (286); +insert into t1 values (285); +insert into t1 values (284); +insert into t1 values (283); +insert into t1 values (282); +insert into t1 values (281); +insert into t1 values (280); +insert into t1 values (279); +insert into t1 values (278); +insert into t1 values (277); +insert into t1 values (276); +insert into t1 values (275); +insert into t1 values (274); +insert into t1 values (273); +insert into t1 values (272); +insert into t1 values (271); +insert into t1 values (270); +insert into t1 values (269); +insert into t1 values (268); +insert into t1 values (267); +insert into t1 values (266); +insert into t1 values (265); +insert into t1 values (264); +insert into t1 values (263); +insert into t1 values (262); +insert into t1 values (261); +insert into t1 values (260); +insert into t1 values (259); +insert into t1 values (258); +insert into t1 values (257); +insert into t1 values (256); +insert into t1 values (255); +insert into t1 values (254); +insert into t1 values (253); +insert into t1 values (252); +insert into t1 values (251); +insert into t1 values (250); +insert into t1 values (249); +insert into t1 values (248); +insert into t1 values (247); +insert into t1 values (246); +insert into t1 values (245); +insert into t1 values (244); +insert into t1 values (243); +insert into t1 values (242); +insert into t1 values (241); +insert into t1 values (240); +insert into t1 values (239); +insert into t1 values (238); +insert into t1 values (237); +insert into t1 values (236); +insert into t1 values (235); +insert into t1 values (234); +insert into t1 values (233); +insert into t1 values (232); +insert into t1 values (231); +insert into t1 values (230); +insert into t1 values (229); +insert into t1 values (228); +insert into t1 values (227); +insert into t1 values (226); +insert into t1 values (225); +insert into t1 values (224); +insert into t1 values (223); +insert into t1 values (222); +insert into t1 values (221); +commit; +select count(*) from t1; +count(*) +161 +select n, count(*) from t1 group by n; +n count(*) +221 2 +222 2 +223 2 +224 2 +225 2 +226 2 +227 2 +228 2 +229 2 +230 2 +231 2 +232 2 +233 2 +234 2 +235 2 +236 2 +237 2 +238 2 +239 2 +240 2 +241 2 +242 2 +243 2 +244 2 +245 2 +246 2 +247 2 +248 2 +249 2 +250 2 +251 2 +252 2 +253 2 +254 2 +255 2 +256 2 +257 2 +258 2 +259 2 +260 2 +261 2 +262 2 +263 2 +264 2 +265 2 +266 2 +267 2 +268 2 +269 2 +270 2 +271 2 +272 2 +273 2 +274 2 +275 2 +276 2 +277 2 +278 2 +279 2 +280 2 +281 2 +282 2 +283 2 +284 2 +285 2 +286 2 +287 2 +288 2 +289 2 +290 2 +291 2 +292 2 +293 2 +294 2 +295 2 +296 2 +297 2 +298 2 +299 2 +300 2 +700 1 +show slave status; +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 Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Until_Condition Until_Log_File Until_Log_Pos +127.0.0.1 root 9306 1 master-bin.001 10296 slave-relay-bin.004 2132 master-bin.001 Yes Yes ignore_db 0 0 10296 10431 None 0 +drop table t1; diff -ruN base/mysql-test/rpl_transaction_test/README mysql40gpl/mysql-test/rpl_transaction_test/README --- base/mysql-test/rpl_transaction_test/README 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/rpl_transaction_test/README 2007-04-21 09:56:54.000000000 -0700 @@ -0,0 +1,19 @@ +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 --local --mysqld="--rpl_transaction_enabled=1" --slave-innodb --do-test=rpl + + +rpl_transaction_001 need manual verification: + . ./mysql-test-run --local --mysqld="--rpl_transaction_enabled=1" --slave-innodb rpl_transaction_001 + . slave-relay-bin.004: should be the only relay-log (slave-relay-bin.00[123] should be deleted) + . the first event in slave-relay-bin.004 should be (pos 8140 must correct): + "#070124 18:49:45 server id -1 log_pos 0 Rotate to master-bin.001 pos: 8140" + +rpl_transaction_002 need manual verification: + . ./mysql-test-run --local --mysqld="--rpl_transaction_enabled=1" --slave-innodb rpl_transaction_002 + . slave-relay-bin.003, slave-relay-bin.004 should be left + . slave-relay-bin.001, slave-relay-bin.002 should be dropped diff -ruN base/mysql-test/rpl_transaction_test/t/rpl_transaction_001-slave.opt mysql40gpl/mysql-test/rpl_transaction_test/t/rpl_transaction_001-slave.opt --- base/mysql-test/rpl_transaction_test/t/rpl_transaction_001-slave.opt 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/rpl_transaction_test/t/rpl_transaction_001-slave.opt 2007-04-21 09:56:54.000000000 -0700 @@ -0,0 +1 @@ +-O max_binlog_size=4096 --replicate-ignore-db=ignore_db diff -ruN base/mysql-test/rpl_transaction_test/t/rpl_transaction_001.test mysql40gpl/mysql-test/rpl_transaction_test/t/rpl_transaction_001.test --- base/mysql-test/rpl_transaction_test/t/rpl_transaction_001.test 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/rpl_transaction_test/t/rpl_transaction_001.test 2007-04-21 09:56:54.000000000 -0700 @@ -0,0 +1,46 @@ +source include/master-slave.inc; + +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); +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 -ruN base/mysql-test/rpl_transaction_test/t/rpl_transaction_002-slave.opt mysql40gpl/mysql-test/rpl_transaction_test/t/rpl_transaction_002-slave.opt --- base/mysql-test/rpl_transaction_test/t/rpl_transaction_002-slave.opt 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/rpl_transaction_test/t/rpl_transaction_002-slave.opt 2007-04-21 09:56:54.000000000 -0700 @@ -0,0 +1 @@ +-O max_binlog_size=4096 --replicate-ignore-db=ignore_db diff -ruN base/mysql-test/rpl_transaction_test/t/rpl_transaction_002.test mysql40gpl/mysql-test/rpl_transaction_test/t/rpl_transaction_002.test --- base/mysql-test/rpl_transaction_test/t/rpl_transaction_002.test 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/rpl_transaction_test/t/rpl_transaction_002.test 2007-04-21 09:56:54.000000000 -0700 @@ -0,0 +1,191 @@ +source include/master-slave.inc; + +drop table if exists t1; +create table t1(n int) engine = InnoDB; + +use test; + +begin; +insert into t1 values (300); +insert into t1 values (299); +insert into t1 values (298); +insert into t1 values (297); +insert into t1 values (296); +insert into t1 values (295); +insert into t1 values (294); +insert into t1 values (293); +insert into t1 values (292); +insert into t1 values (291); +insert into t1 values (290); +insert into t1 values (289); +insert into t1 values (288); +insert into t1 values (287); +insert into t1 values (286); +insert into t1 values (285); +insert into t1 values (284); +insert into t1 values (283); +insert into t1 values (282); +insert into t1 values (281); +insert into t1 values (280); +insert into t1 values (279); +insert into t1 values (278); +insert into t1 values (277); +insert into t1 values (276); +insert into t1 values (275); +insert into t1 values (274); +insert into t1 values (273); +insert into t1 values (272); +insert into t1 values (271); +insert into t1 values (270); +insert into t1 values (269); +insert into t1 values (268); +insert into t1 values (267); +insert into t1 values (266); +insert into t1 values (265); +insert into t1 values (264); +insert into t1 values (263); +insert into t1 values (262); +insert into t1 values (261); +insert into t1 values (260); +insert into t1 values (259); +insert into t1 values (258); +insert into t1 values (257); +insert into t1 values (256); +insert into t1 values (255); +insert into t1 values (254); +insert into t1 values (253); +insert into t1 values (252); +insert into t1 values (251); +insert into t1 values (250); +insert into t1 values (249); +insert into t1 values (248); +insert into t1 values (247); +insert into t1 values (246); +insert into t1 values (245); +insert into t1 values (244); +insert into t1 values (243); +insert into t1 values (242); +insert into t1 values (241); +insert into t1 values (240); +insert into t1 values (239); +insert into t1 values (238); +insert into t1 values (237); +insert into t1 values (236); +insert into t1 values (235); +insert into t1 values (234); +insert into t1 values (233); +insert into t1 values (232); +insert into t1 values (231); +insert into t1 values (230); +insert into t1 values (229); +insert into t1 values (228); +insert into t1 values (227); +insert into t1 values (226); +insert into t1 values (225); +insert into t1 values (224); +insert into t1 values (223); +insert into t1 values (222); +insert into t1 values (221); +commit; + +insert into t1 values (700); + +begin; +insert into t1 values (300); +insert into t1 values (299); +insert into t1 values (298); +insert into t1 values (297); +insert into t1 values (296); +insert into t1 values (295); +insert into t1 values (294); +insert into t1 values (293); +insert into t1 values (292); +insert into t1 values (291); +insert into t1 values (290); +insert into t1 values (289); +insert into t1 values (288); +insert into t1 values (287); +insert into t1 values (286); +insert into t1 values (285); +insert into t1 values (284); +insert into t1 values (283); +insert into t1 values (282); +insert into t1 values (281); +insert into t1 values (280); +insert into t1 values (279); +insert into t1 values (278); +insert into t1 values (277); +insert into t1 values (276); +insert into t1 values (275); +insert into t1 values (274); +insert into t1 values (273); +insert into t1 values (272); +insert into t1 values (271); +insert into t1 values (270); +insert into t1 values (269); +insert into t1 values (268); +insert into t1 values (267); +insert into t1 values (266); +insert into t1 values (265); +insert into t1 values (264); +insert into t1 values (263); +insert into t1 values (262); +insert into t1 values (261); +insert into t1 values (260); +insert into t1 values (259); +insert into t1 values (258); +insert into t1 values (257); +insert into t1 values (256); +insert into t1 values (255); +insert into t1 values (254); +insert into t1 values (253); +insert into t1 values (252); +insert into t1 values (251); +insert into t1 values (250); +insert into t1 values (249); +insert into t1 values (248); +insert into t1 values (247); +insert into t1 values (246); +insert into t1 values (245); +insert into t1 values (244); +insert into t1 values (243); +insert into t1 values (242); +insert into t1 values (241); +insert into t1 values (240); +insert into t1 values (239); +insert into t1 values (238); +insert into t1 values (237); +insert into t1 values (236); +insert into t1 values (235); +insert into t1 values (234); +insert into t1 values (233); +insert into t1 values (232); +insert into t1 values (231); +insert into t1 values (230); +insert into t1 values (229); +insert into t1 values (228); +insert into t1 values (227); +insert into t1 values (226); +insert into t1 values (225); +insert into t1 values (224); +insert into t1 values (223); +insert into t1 values (222); +insert into t1 values (221); +commit; + +save_master_pos; + +connection slave; +sync_with_master; + +select count(*) from t1; +select n, count(*) from t1 group by n; + +show slave status; + +connection master; +drop table t1; +save_master_pos; + +connection slave; +sync_with_master; diff -ruN base/mysql-test/t/checksum1.test mysql40gpl/mysql-test/t/checksum1.test --- base/mysql-test/t/checksum1.test 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/checksum1.test 2007-04-21 09:56:55.000000000 -0700 @@ -0,0 +1,52 @@ +# Test hash() function +# Test unordered_checksum() and ordered_checksum() aggregate functions + +drop table if exists t1; + +create table t1(i int, i1 int, c1 char(1), c2 char(2), f float, d double, vc varchar(10)); +insert into t1 values (1, 3, '1', '1', 1, 1, '1'); +insert into t1 values (2, 2, '2', '2', 2, 2, '2'); +insert into t1 values (3, 1, '3', '22', 3, 3, '22'); + +# For each of these queries, each hash value should be different +select hash(i) from t1 order by i; +select hash(c1) from t1 order by i; +select hash(c2) from t1 order by i; +select hash(f) from t1 order by i; +select hash(d) from t1 order by i; +select hash(vc) from t1 order by i; +select hash(i, c1, c2, f, d, vc) from t1 order by i; + +# The results for these queries should not match +select '1: not match1', unordered_checksum(i, c1, c2, f, d, vc) from t1; +select '1: not match2', unordered_checksum(i1, c1, c2, f, d, vc) from t1; + +# The results for these queries should not match +select '2: not match1', ordered_checksum(i, c1, c2, f, d, vc) from t1; +select '2: not match2', ordered_checksum(i1, c1, c2, f, d, vc) from t1; + +# The results for these queries should match +select '3: match1', unordered_checksum(i) from t1; +select '3: match2', unordered_checksum(i1) from t1; + +# The results for these queries should not match +select '4: not match1', ordered_checksum(i) from t1; +select '4: not match2', ordered_checksum(i1) from t1; + +# The results for these queries should not match +select '5: not match1', unordered_checksum(i, c1, c2, f, d, vc) from t1 group by i1 order by i; +select '5: not match2', unordered_checksum(i1, c1, c2, f, d, vc) from t1 group by i order by i; + +# The results for these queries should not match +select '6: not match1', unordered_checksum(i) from t1 group by i1 order by i; +select '6: not match2', unordered_checksum(i1) from t1 group by i order by i; + +# The results for these queries should not match +select '7: match1', ordered_checksum(i, c1, c2, f, d, vc) from t1 group by i1 order by i; +select '7: match2', ordered_checksum(i1, c1, c2, f, d, vc) from t1 group by i order by i; + +# The results for these queries should not match +select '8: match1', ordered_checksum(i) from t1 group by i1 order by i; +select '8: match2', ordered_checksum(i1) from t1 group by i order by i; + +drop table t1; diff -ruN base/mysql-test/t/checksum2.test mysql40gpl/mysql-test/t/checksum2.test --- base/mysql-test/t/checksum2.test 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/checksum2.test 2007-04-21 09:56:55.000000000 -0700 @@ -0,0 +1,27 @@ +# Test hash() function +# Test unordered_checksum() and ordered_checksum() aggregate functions + +drop table if exists t2; +create table t2(dt datetime, da date, ti time, ts timestamp, y year); +insert into t2 values ('2006-01-01 10:00:00', '2006-01-01', '10:00:00', '20060101100000', 2006); +insert into t2 values ('2007-01-01 11:00:00', '2007-01-01', '11:00:00', '20060101110000', 2007); + +select hash(dt) from t2; +select hash(da) from t2; +select hash(ti) from t2; +select hash(ts) from t2; +select hash(y) from t2; + +select unordered_checksum(dt) from t2; +select unordered_checksum(da) from t2; +select unordered_checksum(ti) from t2; +select unordered_checksum(ts) from t2; +select unordered_checksum(y) from t2; + +select ordered_checksum(dt) from t2; +select ordered_checksum(da) from t2; +select ordered_checksum(ti) from t2; +select ordered_checksum(ts) from t2; +select ordered_checksum(y) from t2; + +drop table t2; diff -ruN base/mysql-test/t/checksum3.test mysql40gpl/mysql-test/t/checksum3.test --- base/mysql-test/t/checksum3.test 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/checksum3.test 2007-04-21 09:56:55.000000000 -0700 @@ -0,0 +1,24 @@ +# Test hash() function +# Test unordered_checksum() and ordered_checksum() aggregate functions + +drop table if exists t3; +create table t3(bi binary(20), vb varbinary(20), bl blob, t text); +insert into t3 values ('abc', 'def', 'ghi', 'jkl'); +insert into t3 values ('abc1', 'def1', 'ghi1', 'jkl1'); + +select hash(bi) from t3; +select hash(vb) from t3; +select hash(bl) from t3; +select hash(t) from t3; + +select unordered_checksum(bi) from t3; +select unordered_checksum(vb) from t3; +select unordered_checksum(bl) from t3; +select unordered_checksum(t) from t3; + +select ordered_checksum(bi) from t3; +select ordered_checksum(vb) from t3; +select ordered_checksum(bl) from t3; +select ordered_checksum(t) from t3; + +drop table t3; diff -ruN base/mysql-test/t/checksum4.test mysql40gpl/mysql-test/t/checksum4.test --- base/mysql-test/t/checksum4.test 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/checksum4.test 2007-04-21 09:56:55.000000000 -0700 @@ -0,0 +1,18 @@ +# Test hash() function +# Test unordered_checksum() and ordered_checksum() aggregate functions + +drop table if exists t4; +create table t4(e enum('1', '2'), s set('1', '2', '3')); +insert into t4 values('1', '1,2'); +insert into t4 values('2', '2,3'); + +select hash(e) from t4; +select hash(s) from t4; + +select unordered_checksum(e) from t4; +select unordered_checksum(s) from t4; +select ordered_checksum(e) from t4; +select ordered_checksum(s) from t4; + +drop table t4; + diff -ruN base/mysql-test/t/distinguish_privilege.test mysql40gpl/mysql-test/t/distinguish_privilege.test --- base/mysql-test/t/distinguish_privilege.test 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/distinguish_privilege.test 2007-04-21 09:56:55.000000000 -0700 @@ -0,0 +1,54 @@ +# Test behavior of correct reporting error type for Google bug[211975] +# - Lack of Permissions looks like missing tables +# + +# Requires privileges to be enabled +-- source include/not_embedded.inc + +# Prepare play-ground +--disable_warnings +drop database if exists mysqltest; +--enable_warnings +create database mysqltest; +create table mysqltest.t1 (a int) engine = InnoDB; +insert into mysqltest.t1 values (3); +create table mysqltest.t2 (a int) engine = InnoDB; +insert into mysqltest.t2 values (3); + +# 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; + +grant all on mysqltest.t1 to mysqltest_1@localhost; +# This ensures that counters are reset and makes test scheduling independent +flush user_resources; + +connect (user1, localhost, mysqltest_1,,mysqltest); +connection user1; +select * from t1; +--error 1142 +select * from t2; +--error 1142 +desc t2; +--error 1146 +select * from t3; +--error 1146 +desc t3; + +# cleanup +connection default; + +# 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; + +# Final cleanup +drop database mysqltest; diff -ruN base/mysql-test/t/flush.test mysql40gpl/mysql-test/t/flush.test --- base/mysql-test/t/flush.test 2005-09-02 15:50:38.000000000 -0700 +++ mysql40gpl/mysql-test/t/flush.test 2007-04-21 09:56:55.000000000 -0700 @@ -67,3 +67,9 @@ insert into t1 values (345); select * from t1; drop table t1; + +# test flush table_statistics and index_statistics +flush table_statistics; +show table_statistics; +flush index_statistics; +show index_statistics; diff -ruN base/mysql-test/t/ieee754_to_string.test mysql40gpl/mysql-test/t/ieee754_to_string.test --- base/mysql-test/t/ieee754_to_string.test 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/ieee754_to_string.test 2007-04-21 09:56:56.000000000 -0700 @@ -0,0 +1,21 @@ +# +# Test for lossless conversion from double -> decimal -> double +# + +drop table if exists t1,t2; + +CREATE TABLE t1 (d double, i int); +CREATE TABLE t2 (v varchar(30), i int); + +INSERT INTO t1 VALUES (1.7976931348623157e+308, 0); +INSERT INTO t1 VALUES (NULL, 0); +INSERT INTO t1 VALUES ('inf', 0); +INSERT INTO t1 VALUES ('nan', 0); +INSERT INTO t1 VALUES (-0e0, 0); +INSERT INTO t2 SELECT IEEE754_TO_STRING(d), i from t1; +INSERT INTO t1 SELECT * from t2; + +SELECT COUNT(*), d from t1 group by d order by d; + +DROP TABLE t1; +DROP TABLE t2; diff -ruN base/mysql-test/t/order_by_fp.test mysql40gpl/mysql-test/t/order_by_fp.test --- base/mysql-test/t/order_by_fp.test 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/order_by_fp.test 2007-04-21 09:56:56.000000000 -0700 @@ -0,0 +1,11 @@ +# +# Test order by for floating point types +# + +drop table if exists t1; + +CREATE TABLE t1 (d double); + +INSERT INTO t1 VALUES (-0E0), (+0E0), (1E308), (-1E308), (1), (-1); +SELECT 2 * d AS e FROM t1 ORDER BY e; +DROP TABLE t1; diff -ruN base/mysql-test/t/rpl_innodb_clear_status.test mysql40gpl/mysql-test/t/rpl_innodb_clear_status.test --- base/mysql-test/t/rpl_innodb_clear_status.test 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/rpl_innodb_clear_status.test 2007-04-21 09:56:58.000000000 -0700 @@ -0,0 +1,45 @@ +--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"; +--error 1227 +SET innodb_clear_replication_status = 1; + +connection con1; + +drop table if exists t1; + +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 -ruN base/mysql-test/t/rpl_make_master.test mysql40gpl/mysql-test/t/rpl_make_master.test --- base/mysql-test/t/rpl_make_master.test 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/rpl_make_master.test 2007-04-21 09:56:58.000000000 -0700 @@ -0,0 +1,60 @@ +# +# Testing of make a master database in fast failover. +# +-- source include/not_embedded.inc + +connect (con1,localhost,root,,); + +# Prepare play-ground +--disable_warnings +drop database if exists mysqltest; +--enable_warnings +create database mysqltest; +create table mysqltest.t1 (a int) engine = InnoDB; +insert into mysqltest.t1 values (3); +create table mysqltest.t2 (a int) engine = InnoDB; +insert into mysqltest.t2 values (3); + +# 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; + +grant all on mysqltest.t1 to mysqltest_1@localhost; +# This ensures that counters are reset and makes test scheduling independent +flush user_resources; + +connect (user1, localhost, mysqltest_1,,mysqltest); + +connection user1; +select * from mysqltest.t1; + +connection con1; +make master revoke session with kill; + +connection user1; +--error 2013 +ping +select * from mysqltest.t1; + +connection con1; +make master grant session; + +connection user1; +select * from mysqltest.t1; + +connection con1; + +# 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; + +# Final cleanup +drop database mysqltest; diff -ruN base/mysql-test/t/rpl_mirror_binlog-master.opt mysql40gpl/mysql-test/t/rpl_mirror_binlog-master.opt --- base/mysql-test/t/rpl_mirror_binlog-master.opt 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/rpl_mirror_binlog-master.opt 2007-04-21 09:56:58.000000000 -0700 @@ -0,0 +1 @@ +-O max_binlog_size=4096 diff -ruN base/mysql-test/t/rpl_mirror_binlog.slave-mi-1 mysql40gpl/mysql-test/t/rpl_mirror_binlog.slave-mi-1 --- base/mysql-test/t/rpl_mirror_binlog.slave-mi-1 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/rpl_mirror_binlog.slave-mi-1 2007-04-21 09:56:58.000000000 -0700 @@ -0,0 +1 @@ +--master-user=root --master-connect-retry=1 --master-host=127.0.0.1 --master-password="" --master-port=9307 --server-id=3 diff -ruN base/mysql-test/t/rpl_mirror_binlog.slave-mi-2 mysql40gpl/mysql-test/t/rpl_mirror_binlog.slave-mi-2 --- base/mysql-test/t/rpl_mirror_binlog.slave-mi-2 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/rpl_mirror_binlog.slave-mi-2 2007-04-21 09:56:58.000000000 -0700 @@ -0,0 +1 @@ +--master-user=root --master-connect-retry=1 --master-host=127.0.0.1 --master-password="" --master-port=9307 --server-id=4 diff -ruN base/mysql-test/t/rpl_mirror_binlog-slave.opt mysql40gpl/mysql-test/t/rpl_mirror_binlog-slave.opt --- base/mysql-test/t/rpl_mirror_binlog-slave.opt 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/rpl_mirror_binlog-slave.opt 2007-04-21 09:56:58.000000000 -0700 @@ -0,0 +1 @@ +--rpl_mirror_binlog_enabled=1 --log-bin-index=replication_log diff -ruN base/mysql-test/t/rpl_mirror_binlog_stop-master.opt mysql40gpl/mysql-test/t/rpl_mirror_binlog_stop-master.opt --- base/mysql-test/t/rpl_mirror_binlog_stop-master.opt 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/rpl_mirror_binlog_stop-master.opt 2007-04-21 09:56:58.000000000 -0700 @@ -0,0 +1 @@ +-O max_binlog_size=4096 diff -ruN base/mysql-test/t/rpl_mirror_binlog_stop.slave-mi-1 mysql40gpl/mysql-test/t/rpl_mirror_binlog_stop.slave-mi-1 --- base/mysql-test/t/rpl_mirror_binlog_stop.slave-mi-1 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/rpl_mirror_binlog_stop.slave-mi-1 2007-04-21 09:56:58.000000000 -0700 @@ -0,0 +1 @@ +--master-user=root --master-connect-retry=1 --master-host=127.0.0.1 --master-password="" --master-port=9307 --server-id=3 diff -ruN base/mysql-test/t/rpl_mirror_binlog_stop-slave.opt mysql40gpl/mysql-test/t/rpl_mirror_binlog_stop-slave.opt --- base/mysql-test/t/rpl_mirror_binlog_stop-slave.opt 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/rpl_mirror_binlog_stop-slave.opt 2007-04-21 09:56:58.000000000 -0700 @@ -0,0 +1 @@ +--rpl_mirror_binlog_enabled=1 --log-bin-index=replication_log diff -ruN base/mysql-test/t/rpl_mirror_binlog_stop.test mysql40gpl/mysql-test/t/rpl_mirror_binlog_stop.test --- base/mysql-test/t/rpl_mirror_binlog_stop.test 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/rpl_mirror_binlog_stop.test 2007-04-21 09:56:58.000000000 -0700 @@ -0,0 +1,110 @@ +require_manager; +source include/master-slave.inc; +connect (slave_sec,localhost,root,,test,0,slave.sock-1); + +connection master; +drop table if exists t1; +create table t1(n int) engine = InnoDB; + +let $i=100; +while ($i) +{ + eval insert into t1 values ($i); + dec $i; +} + +save_master_pos; +show status like 'Rpl_mirror_binlog_clients'; + +connection slave; +sync_with_master; + +select "The following are SLAVE."; +show status like 'Rpl_mirror_binlog_status'; +show status like 'Rpl_mirror_binlog_clients'; + +select count(distinct n) from t1; +select min(n) from t1; +select max(n) from t1; +show slave status; + +connection slave_sec; +select "The following are SLAVE1."; +start slave; +sync_with_master; + +select count(distinct n) from t1; +select min(n) from t1; +select max(n) from t1; +--replace_column 8 # 18 # +show slave status; + +# Stop the mirror binlog on slave, but let replication continue. +connection slave; +select "The following are SLAVE."; +stop slave; +set global rpl_mirror_binlog_enabled=0; +start slave; + +connection master; +let $i=200; +while ($i) +{ + eval insert into t1 values ($i); + dec $i; +} +save_master_pos; + +select "The following are SLAVE."; +show status like 'Rpl_mirror_binlog_status'; +show status like 'Rpl_mirror_binlog_clients'; + +select count(distinct n) from t1; +select min(n) from t1; +select max(n) from t1; +show slave status; + +connection slave_sec; +select "The following are SLAVE1."; + +select count(distinct n) from t1; +select min(n) from t1; +select max(n) from t1; +--replace_column 8 # 18 # +show slave status; + +# Start the mirror binlog again. +connection slave; +select "The following are SLAVE."; +stop slave; +set global rpl_mirror_binlog_enabled=1; +start slave; + +connection master; +let $i=300; +while ($i) +{ + eval insert into t1 values ($i); + dec $i; +} +save_master_pos; + +select "The following are SLAVE."; +show status like 'Rpl_mirror_binlog_status'; +show status like 'Rpl_mirror_binlog_clients'; + +select count(distinct n) from t1; +select min(n) from t1; +select max(n) from t1; +show slave status; + +connection slave_sec; +select "The following are SLAVE1."; +sync_with_master; + +select count(distinct n) from t1; +select min(n) from t1; +select max(n) from t1; +--replace_column 8 # 18 # +show slave status; + diff -ruN base/mysql-test/t/rpl_mirror_binlog.test mysql40gpl/mysql-test/t/rpl_mirror_binlog.test --- base/mysql-test/t/rpl_mirror_binlog.test 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/rpl_mirror_binlog.test 2007-04-21 09:56:58.000000000 -0700 @@ -0,0 +1,175 @@ +require_manager; +source include/master-slave.inc; +connect (slave_sec,localhost,root,,test,0,slave.sock-1); +connect (slave_ter,localhost,root,,test,0,slave.sock-2); + +connection master; +drop table if exists t1; +create table t1(n int) engine = InnoDB; + +let $i=300; +while ($i) +{ + eval insert into t1 values ($i); + dec $i; +} + +save_master_pos; +show status like 'Rpl_mirror_binlog_clients'; + +connection slave; +sync_with_master; + +select "The following are SLAVE."; +show status like 'Rpl_mirror_binlog_status'; +show variables like 'log_bin'; + +select count(distinct n) from t1; +select min(n) from t1; +select max(n) from t1; +show slave status; + +connection slave_sec; +select "The following are SLAVE1."; +start slave; +sync_with_master; + +select count(distinct n) from t1; +select min(n) from t1; +select max(n) from t1; +--replace_column 8 # 18 # +show slave status; + +connection slave_ter; +select "The following are SLAVE2."; +start slave; +sync_with_master; + +# Stop here because we will use . +stop slave; + +select count(distinct n) from t1; +select min(n) from t1; +select max(n) from t1; + +# make the slave the new master +connection slave; +select "The following are SLAVE."; + +# show master status during mirror binlog time +show master status; + +# The first 1201 error is caused by running slave. +--error 1201 +MAKE MASTER MASTER_LOG_FILE='master-bin', + MASTER_SERVER_ID=2, + INDEX='replication-log'; +stop slave; + +connection slave; +select "The following are SLAVE."; + +# The second 1201 error is caused by failover mode. +--error 1201 +MAKE MASTER MASTER_LOG_FILE='master-bin', + MASTER_SERVER_ID=2, + INDEX='replication_log'; + +MAKE MASTER REVOKE SESSION WITH KILL; +MAKE MASTER MASTER_LOG_FILE='master-bin', + MASTER_SERVER_ID=2, + INDEX='replication_log' + WITH BINLOG; + +MAKE MASTER GRANT SESSION; + +show master status; +delete from t1 where n > 250; +save_master_pos; + +select count(distinct n) from t1; + +connection slave_sec; +select "The following are SLAVE1."; +show variables like 'server_id'; + +sync_with_master; select count(distinct n) from t1; +select min(n) from t1; +select max(n) from t1; + +connection slave_ter; +select "The following are SLAVE2."; +show variables like 'server_id'; + +CHANGE MASTER TO + MASTER_HOST='127.0.0.1', + MASTER_USER='root', + MASTER_PASSWORD='', + MASTER_PORT=9307, + MASTER_LOG_FILE='master-bin.006', + MASTER_LOG_POS=4; +start slave; +sync_with_master; + +select count(distinct n) from t1; +select min(n) from t1; +select max(n) from t1; + +--replace_column 8 # 18 # +show slave status; + +connection master; +drop table t1; + +connection slave; +show status like 'Rpl_mirror_binlog_clients'; +show status like 'Rpl_mirror_binlog_status'; + +drop table t1; +save_master_pos; + +connection slave_sec; +select "The following are SLAVE1."; +sync_with_master; +--exec ls $MYSQL_TEST_DIR/var/slave1-data + +stop slave; +reset slave no purge binlog; +--exec ls $MYSQL_TEST_DIR/var/slave1-data + +reset slave; +--exec ls $MYSQL_TEST_DIR/var/slave1-data + +connection slave; +select "The following are SLAVE."; + +show variables like 'log_bin'; +show master logs; +show master status; + +connection slave_ter; +select "The following are SLAVE2."; +sync_with_master; + +show master logs; +purge master logs to 'master-bin.006'; +show master logs; +--error 1186 +reset master; + +stop slave; + +--exec ls $MYSQL_TEST_DIR/var/slave2-data + +# This must be the last command in the test. Never 'start slave' +# after this. +CHANGE MASTER TO + MASTER_HOST='127.0.0.1', + MASTER_USER='root', + MASTER_PASSWORD='', + MASTER_PORT=9307, + MASTER_LOG_FILE='master-bin.001', + MASTER_LOG_POS=4; + +--exec ls $MYSQL_TEST_DIR/var/slave2-data + diff -ruN base/mysql-test/t/rpl_semi_sync-master.opt mysql40gpl/mysql-test/t/rpl_semi_sync-master.opt --- base/mysql-test/t/rpl_semi_sync-master.opt 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/rpl_semi_sync-master.opt 2007-04-21 09:57:00.000000000 -0700 @@ -0,0 +1 @@ +--rpl_semi_sync_enabled=1 --rpl_semi_sync_timeout=1000 --rpl_long_filename=1 diff -ruN base/mysql-test/t/rpl_semi_sync-slave.opt mysql40gpl/mysql-test/t/rpl_semi_sync-slave.opt --- base/mysql-test/t/rpl_semi_sync-slave.opt 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/rpl_semi_sync-slave.opt 2007-04-21 09:57:00.000000000 -0700 @@ -0,0 +1 @@ +--rpl_semi_sync_slave_enabled=1 diff -ruN base/mysql-test/t/rpl_semi_sync.test mysql40gpl/mysql-test/t/rpl_semi_sync.test --- base/mysql-test/t/rpl_semi_sync.test 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/rpl_semi_sync.test 2007-04-21 09:57:00.000000000 -0700 @@ -0,0 +1,91 @@ +source include/master-slave.inc; + +connection master; +show status like 'Rpl_semi_sync_no_tx'; +show status like 'Rpl_semi_sync_yes_tx'; + +connection slave; +# Restart I/O thread to make sure that semi-sync is caught up. +stop slave; +start slave; +--sleep 2 + +connection master; +show status like 'Rpl_semi_sync_clients'; + +drop table if exists t1; +create table t1(n int) engine = InnoDB; +let $i=300; +while ($i) +{ + eval insert into t1 values ($i); + dec $i; +} + +show master status; +save_master_pos; + +connection slave; +sync_with_master; + +show status like 'Rpl_semi_sync_slave_status'; + +select count(distinct n) from t1; +select min(n) from t1; +select max(n) from t1; +# stop slave to let semi-sync replication fail. +stop slave; + +connection master; + +# The first semi-sync check should be on because after slave stop, +# there are no transactions on the master. +show status like 'Rpl_semi_sync_status'; +show status like 'Rpl_semi_sync_no_tx'; +show status like 'Rpl_semi_sync_yes_tx'; +show status like 'Rpl_semi_sync_clients'; + +begin; +insert into t1 values (500); +delete from t1 where n < 500; +commit; +insert into t1 values (100); +--sleep 2 + +# The second semi-sync check should be off because one transaction +# times out during waiting. +show status like 'Rpl_semi_sync_status'; +show status like 'Rpl_semi_sync_no_tx'; +show status like 'Rpl_semi_sync_yes_tx'; +save_master_pos; + +connection slave; +show status like 'Rpl_semi_sync_slave_status'; +start slave; +sync_with_master; +show status like 'Rpl_semi_sync_slave_status'; + +select count(distinct n) from t1; +select min(n) from t1; +select max(n) from t1; + +connection master; +drop table t1; +save_master_pos; + +# The third semi-sync check should be on again. +show status like 'Rpl_semi_sync_status'; +show status like 'Rpl_semi_sync_no_tx'; +show status like 'Rpl_semi_sync_yes_tx'; + +connection slave; +sync_with_master; + +connection master; +show master logs; +show variables like 'rpl_semi_sync_enabled'; + +# disable semi-sync on the fly +set global rpl_semi_sync_enabled=0; +show variables like 'rpl_semi_sync_enabled'; +show status like 'Rpl_semi_sync_status'; diff -ruN base/mysql-test/t/rpl_show_processlist.test mysql40gpl/mysql-test/t/rpl_show_processlist.test --- base/mysql-test/t/rpl_show_processlist.test 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/mysql-test/t/rpl_show_processlist.test 2007-04-21 09:57:00.000000000 -0700 @@ -0,0 +1,39 @@ +source include/master-slave.inc; + +connection master; +drop table if exists t1; +create table t1(n int); + +let $i=300; +while ($i) +{ + eval insert into t1 values ($i); + dec $i; +} + +save_master_pos; + +connection slave; +sync_with_master; + +connection master; +--replace_column 1 # 3 # 6 # +show processlist; + +delete from t1 where n > 50; +delete from t1 where n > 25; +save_master_pos; + +connection slave; +sync_with_master; + +connection master; +drop table t1; +save_master_pos; + +connection slave; +sync_with_master; + +connection master; +--replace_column 1 # 3 # 6 # +show processlist; diff -ruN base/mysql-test/t/variables.test mysql40gpl/mysql-test/t/variables.test --- base/mysql-test/t/variables.test 2005-09-02 15:50:38.000000000 -0700 +++ mysql40gpl/mysql-test/t/variables.test 2007-04-21 09:57:01.000000000 -0700 @@ -64,6 +64,17 @@ set global concurrent_insert=DEFAULT; show variables like 'concurrent_insert'; +set global innodb_btr_estimate_n_pages=1; +show variables like 'innodb_btr_estimate_n_pages'; +set global innodb_btr_estimate_n_pages=0; +show variables like 'innodb_btr_estimate_n_pages'; +set global innodb_btr_estimate_n_pages=100; +show variables like 'innodb_btr_estimate_n_pages'; +set global innodb_btr_estimate_n_pages=10000; +show variables like 'innodb_btr_estimate_n_pages'; +set global innodb_btr_estimate_n_pages=DEFAULT; +show variables like 'innodb_btr_estimate_n_pages'; + set table_type=MYISAM, table_type="HEAP", global table_type="INNODB"; show local variables like 'table_type'; show global variables like 'table_type'; @@ -184,7 +195,7 @@ set join_buffer_size=100; set last_insert_id=1; set global local_infile=1; -set long_query_time=100; +set global long_query_time=100; set low_priority_updates=1; set max_allowed_packet=100; set global max_binlog_cache_size=100; @@ -192,6 +203,7 @@ set global max_connect_errors=100; set global max_connections=100; set global max_delayed_threads=100; +set global reserved_super_connections=10; set max_heap_table_size=100; set max_join_size=100; set max_sort_length=100; diff -ruN base/mysys/hash.c mysql40gpl/mysys/hash.c --- base/mysys/hash.c 2005-09-02 15:38:07.000000000 -0700 +++ mysql40gpl/mysys/hash.c 2007-04-21 09:57:01.000000000 -0700 @@ -36,15 +36,15 @@ static int hashcmp(HASH *hash,HASH_LINK *pos,const byte *key,uint length); -my_bool _hash_init(HASH *hash,uint size,uint key_offset,uint key_length, - hash_get_key get_key, - void (*free_element)(void*),uint flags CALLER_INFO_PROTO) +my_bool _hash_init(HASH *hash,uint size,uint growth_size, + uint key_offset,uint key_length, hash_get_key get_key, + void (*free_element)(void*),uint flags CALLER_INFO_PROTO) { DBUG_ENTER("hash_init"); DBUG_PRINT("enter",("hash: %lx size: %d",hash,size)); hash->records=0; - if (my_init_dynamic_array_ci(&hash->array,sizeof(HASH_LINK),size,0)) + if (my_init_dynamic_array_ci(&hash->array,sizeof(HASH_LINK),size,growth_size)) { hash->free=0; /* Allow call to hash_free */ DBUG_RETURN(TRUE); diff -ruN base/mysys/mf_iocache.c mysql40gpl/mysys/mf_iocache.c --- base/mysys/mf_iocache.c 2005-09-02 15:38:01.000000000 -0700 +++ mysql40gpl/mysys/mf_iocache.c 2007-04-21 09:57:01.000000000 -0700 @@ -71,6 +71,8 @@ #define IO_ROUND_UP(X) (((X)+IO_SIZE-1) & ~(IO_SIZE-1)) #define IO_ROUND_DN(X) ( (X) & ~(IO_SIZE-1)) +static void get_date_local(register my_string to, int flag, time_t date); + /* Setup internal pointers inside IO_CACHE @@ -397,7 +399,19 @@ pos_in_file=info->pos_in_file+(uint) (info->read_end - info->buffer); if (info->seek_not_done) { /* File touched, do seek */ - VOID(my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0))); + if (my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)) == + MY_FILEPOS_ERROR) { + char date_buff[40]; + + get_date_local(date_buff, 3, 0); + if (info->file != -1) { + // An error is expected when the fd == 1. Otherwise log it. + fprintf(stderr, + "%s _my_b_read: seek error %d at fd %d for pos %lld in %s\n", + date_buff, my_errno, info->file, pos_in_file, + info->file_name ? info->file_name : "no_name"); + } + } info->seek_not_done=0; } diff_length=(uint) (pos_in_file & (IO_SIZE-1)); @@ -1206,6 +1220,42 @@ DBUG_RETURN(error); } /* end_io_cache */ +static void get_date_local(register my_string to, int flag, time_t date) +{ + reg2 struct tm *start_time; + time_t skr; +#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT) + struct tm tm_tmp; +#endif + + skr=date ? (time_t) date : time((time_t*) 0); +#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT) + localtime_r(&skr,&tm_tmp); + start_time= &tm_tmp; +#else + start_time=localtime(&skr); +#endif + if (flag & 2) + sprintf(to,"%02d%02d%02d", + start_time->tm_year % 100, + start_time->tm_mon+1, + start_time->tm_mday); + else + sprintf(to,"%d-%02d-%02d", + start_time->tm_year+1900, + start_time->tm_mon+1, + start_time->tm_mday); + if (flag & 1) + sprintf(strend(to)," %2d:%02d:%02d", + start_time->tm_hour, + start_time->tm_min, + start_time->tm_sec); + else if (flag & 4) + sprintf(strend(to),"%02d%02d%02d", + start_time->tm_hour, + start_time->tm_min, + start_time->tm_sec); +} /* get_date_local */ /********************************************************************** Testing of MF_IOCACHE diff -ruN base/mysys/my_compress.c mysql40gpl/mysys/my_compress.c --- base/mysys/my_compress.c 2005-09-02 15:38:04.000000000 -0700 +++ mysql40gpl/mysys/my_compress.c 2007-04-21 09:57:02.000000000 -0700 @@ -55,8 +55,8 @@ *complen= *len * 120 / 100 + 12; if (!(compbuf= (byte *) my_malloc(*complen,MYF(MY_WME)))) return 0; /* Not enough memory */ - if (compress((Bytef*) compbuf,(ulong *) complen, (Bytef*) packet, - (uLong) *len ) != Z_OK) + if (compress2((Bytef*) compbuf,(ulong *) complen, (Bytef*) packet, + (uLong) *len, 1) != Z_OK) { my_free(compbuf,MYF(MY_WME)); return 0; diff -ruN base/mysys/safemalloc.c mysql40gpl/mysys/safemalloc.c --- base/mysys/safemalloc.c 2005-09-02 15:38:07.000000000 -0700 +++ mysql40gpl/mysys/safemalloc.c 2007-04-21 09:57:03.000000000 -0700 @@ -156,6 +156,9 @@ size, (size + 1023L) / 1024L, sf_malloc_max_memory, (sf_malloc_max_memory + 1023L) / 1024L); my_message(EE_OUTOFMEMORY,buff,MYF(ME_BELL+ME_WAITTANG)); + + /* Print the message in the trace. */ + fprintf(stderr, "MySQL: %s\n", buff); } DBUG_PRINT("error",("Out of memory, in use: %ld at line %d, '%s'", sf_malloc_max_memory,lineno, filename)); diff -ruN base/sql/filesort.cc mysql40gpl/sql/filesort.cc --- base/sql/filesort.cc 2005-09-02 15:38:00.000000000 -0700 +++ mysql40gpl/sql/filesort.cc 2007-04-21 09:57:09.000000000 -0700 @@ -1028,6 +1028,8 @@ #endif } #endif + // Order values as: + // -INF < negative < -0 < +0 < positive < +INF < NaN if (tmp[0] & 128) /* Negative */ { /* make complement */ uint i; @@ -1035,12 +1037,8 @@ tmp[i]=tmp[i] ^ (uchar) 255; } else - { /* Set high and move exponent one up */ - ushort exp_part=(((ushort) tmp[0] << 8) | (ushort) tmp[1] | - (ushort) 32768); - exp_part+= (ushort) 1 << (16-1-DBL_EXP_DIG); - tmp[0]= (uchar) (exp_part >> 8); - tmp[1]= (uchar) exp_part; + { /* Set high */ + tmp[0] |= 128; } } } diff -ruN base/sql/gen_lex_hash.cc mysql40gpl/sql/gen_lex_hash.cc --- base/sql/gen_lex_hash.cc 2005-09-02 15:38:07.000000000 -0700 +++ mysql40gpl/sql/gen_lex_hash.cc 2007-04-21 13:04:31.000000000 -0700 @@ -469,7 +469,15 @@ int error; MY_INIT(argv[0]); +#if 0 + /* original values */ start_value=2925024L; best_t1=654916L; best_t2=1723390L; best_type=3; /* mode=4943 add=1 type: 0 */ +#else + /* values after running gen_lex_hash --search */ + /*start_value=3127171L; best_t1=376896L; best_t2=6499924L; best_type=3;*/ /* mode=6857 add=2 type: 0 */ + start_value=1920267L; best_t1=5306333L; best_t2=7518242L; best_type=2; /* mode=7621 add=4 type: 0 */ + +#endif if (get_options(argc,(char **) argv)) exit(1); diff -ruN base/sql/ha_innodb.cc mysql40gpl/sql/ha_innodb.cc --- base/sql/ha_innodb.cc 2005-09-02 15:37:59.000000000 -0700 +++ mysql40gpl/sql/ha_innodb.cc 2007-04-21 11:14:01.000000000 -0700 @@ -36,6 +36,7 @@ #define MAX_ULONG_BIT ((ulong) 1 << (sizeof(ulong)*8-1)) #include "ha_innodb.h" +#include "repl_semi_sync.h" pthread_mutex_t innobase_mutex; @@ -86,6 +87,7 @@ innobase_buffer_pool_size, innobase_additional_mem_pool_size, innobase_file_io_threads, innobase_lock_wait_timeout, innobase_thread_concurrency, innobase_force_recovery; +long innobase_read_io_threads, innobase_write_io_threads; /* The default values for the following char* start-up parameters are determined in innobase_init below: */ @@ -107,6 +109,21 @@ my_bool innobase_fast_shutdown = TRUE; my_bool innobase_create_status_file = FALSE; +/* When this is true and binary logging is disabled the following statements + do not lock rows in S mode for reads from the selected tables: + insert ... select from foo + update ... select from foo + create table ... select from foo + replace ... select from foo + delete ... select from foo + */ +my_bool innodb_no_share_locks_on_dml_select = TRUE; + +/* Max number of IO requests merged to perform large IO in background + IO threads. +*/ +long innobase_max_merged_io = 64; + static char *internal_innobase_data_file_path = NULL; /* The following counter is used to convey information to InnoDB @@ -133,6 +150,8 @@ static void free_share(INNOBASE_SHARE *share); static void innobase_print_error(const char* db_errpfx, char* buffer); +extern ReplSemiSync semi_sync_replicator; + /* General functions */ /********************************************************************** @@ -478,11 +497,8 @@ if (trx == NULL) { DBUG_ASSERT(thd != NULL); - trx = trx_allocate_for_mysql(); + trx = ha_innobase::allocate_trx(thd, &((*thd).query)); - trx->mysql_thd = thd; - trx->mysql_query_str = &((*thd).query); - thd->transaction.all.innobase_tid = trx; /* The execution of a single SQL statement is denoted by @@ -910,6 +926,8 @@ srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size; srv_n_file_io_threads = (ulint) innobase_file_io_threads; + srv_n_read_io_threads = (ulint) innobase_read_io_threads; + srv_n_write_io_threads = (ulint) innobase_write_io_threads; srv_lock_wait_timeout = (ulint) innobase_lock_wait_timeout; srv_thread_concurrency = (ulint) innobase_thread_concurrency; @@ -1047,6 +1065,16 @@ if (current_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.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.master_log_name; trx->mysql_master_log_pos = (ib_longlong) @@ -1057,6 +1085,10 @@ #endif } + if (current_thd->variables.innodb_clear_replication_status) { + trx->clear_replication_status = TRUE; + } + trx_commit_for_mysql(trx); } @@ -1161,6 +1193,26 @@ trx->flush_log_later = TRUE; + if (semi_sync_replicator.getMasterEnabled()) { + /* Let us store the binlog file name and the position, so that + we know how long to wait for the binlog to the replicated to + the slave in synchronous replication. */ + + if (trx->repl_wait_binlog_name == NULL) { + trx->repl_wait_binlog_name = + (char*)mem_alloc_noninline(FN_REFLEN + 100); + } + + ut_a(strlen(log_file_name) <= FN_REFLEN + 100); + strcpy(trx->repl_wait_binlog_name, + log_file_name + dirname_length(log_file_name)); + trx->repl_wait_binlog_pos = (ib_longlong)end_offset; + + /* Store transaction ending position for semi-sync replication. */ + semi_sync_replicator.writeTranxInBinlog( + trx->repl_wait_binlog_name, end_offset); + } + innobase_commit(thd, trx_handle); trx->flush_log_later = FALSE; @@ -1191,6 +1243,9 @@ trx_commit_complete_for_mysql(trx); + semi_sync_replicator.commitTrx(trx->repl_wait_binlog_name, + trx->repl_wait_binlog_pos); + return(0); } @@ -2309,7 +2364,9 @@ && prebuilt->trx->auto_inc_lock) { auto_inc_counter_for_this_stat--; } - } + } else { + rows_changed++; + } error = convert_error_code_to_mysql(error, user_thd); @@ -2536,6 +2593,10 @@ error = row_update_for_mysql((byte*) old_row, prebuilt); + if (error == DB_SUCCESS) { + rows_changed++; + } + innodb_srv_conc_exit_innodb(prebuilt->trx); error = convert_error_code_to_mysql(error, user_thd); @@ -2584,6 +2645,10 @@ error = row_update_for_mysql((byte*) record, prebuilt); + if (error == DB_SUCCESS) { + rows_changed++; + } + innodb_srv_conc_exit_innodb(prebuilt->trx); error = convert_error_code_to_mysql(error, user_thd); @@ -2807,6 +2872,9 @@ if (ret == DB_SUCCESS) { error = 0; table->status = 0; + rows_read++; + if (active_index >= 0 && active_index < MAX_KEY) + index_rows_read[active_index]++; } else if (ret == DB_RECORD_NOT_FOUND) { error = HA_ERR_KEY_NOT_FOUND; @@ -2955,6 +3023,9 @@ if (ret == DB_SUCCESS) { error = 0; table->status = 0; + rows_read++; + if (active_index >= 0 && active_index < MAX_KEY) + index_rows_read[active_index]++; } else if (ret == DB_RECORD_NOT_FOUND) { error = HA_ERR_END_OF_FILE; @@ -3513,10 +3584,7 @@ trx_search_latch_release_if_reserved(parent_trx); - trx = trx_allocate_for_mysql(); - - trx->mysql_thd = thd; - trx->mysql_query_str = &((*thd).query); + trx = allocate_trx(thd, &((*thd).query)); if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) { trx->check_foreigns = FALSE; @@ -3699,10 +3767,7 @@ srv_lower_case_table_names = FALSE; } - trx = trx_allocate_for_mysql(); - - trx->mysql_thd = current_thd; - trx->mysql_query_str = &((*current_thd).query); + trx = allocate_trx(current_thd, &((*current_thd).query)); if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) { trx->check_foreigns = FALSE; @@ -3791,9 +3856,7 @@ #ifdef __WIN__ casedn_str(namebuf); #endif - trx = trx_allocate_for_mysql(); - trx->mysql_thd = current_thd; - trx->mysql_query_str = &((*current_thd).query); + trx = ha_innobase::allocate_trx(current_thd, &((*current_thd).query)); if (current_thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) { trx->check_foreigns = FALSE; @@ -3857,9 +3920,7 @@ srv_lower_case_table_names = FALSE; } - trx = trx_allocate_for_mysql(); - trx->mysql_thd = current_thd; - trx->mysql_query_str = &((*current_thd).query); + trx = allocate_trx(current_thd, &((*current_thd).query)); name_len1 = strlen(from); name_len2 = strlen(to); @@ -4800,6 +4861,7 @@ { String* packet = &thd->packet; trx_t* trx; + const int kMaxOutput = 128000; DBUG_ENTER("innodb_show_status"); @@ -4814,7 +4876,7 @@ innobase_release_stat_resources(trx); - /* We let the InnoDB Monitor to output at most 64000 bytes of text. */ + /* Let the InnoDB Monitor output at most kMaxOutput bytes of text. */ long flen; char* str; @@ -4826,8 +4888,8 @@ os_file_set_eof(srv_monitor_file); if (flen < 0) { flen = 0; - } else if (flen > 64000 - 1) { - flen = 64000 - 1; + } else if (flen > kMaxOutput - 1) { + flen = kMaxOutput - 1; } /* allocate buffer for the string, and @@ -4967,8 +5029,46 @@ are not simple SELECTs; note that select_lock_type in this case may get strengthened in ::external_lock() to LOCK_X. */ - prebuilt->select_lock_type = LOCK_S; - prebuilt->stored_select_lock_type = LOCK_S; + if (innodb_no_share_locks_on_dml_select && + !opt_bin_log && + prebuilt->trx->isolation_level != TRX_ISO_SERIALIZABLE && + (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT) && + (thd->lex.sql_command == SQLCOM_INSERT_SELECT || + thd->lex.sql_command == SQLCOM_UPDATE || + thd->lex.sql_command == SQLCOM_DELETE || + thd->lex.sql_command == SQLCOM_REPLACE_SELECT || + thd->lex.sql_command == SQLCOM_CREATE_TABLE)) { + /* TODO(mcallaghan) + Should this be done only for create temp table? + Is this the appropriate set of statements to fix? + + This code is derived from ha_innodb.cc for versions + 5.0.18 and 4.1.16. + + When innodb_no_share_locks_on_dml_select=1 and + log_bin=0, this uses consistent read (no locks) + for tables selected from as part of an insert, + update, create table, delete or replace. Otherwise, + S locks are obtained on those rows. + + If S locks are obtained in that case, the result + is bad for replication slaves when reporting queries + are also run against the slaves. The replication + thread will experience frequent lock timeouts when + long-running create table statements, inserts, + updates and deletes are done by the reporting + queries and get S locks on rows from tables that the + replicaton thread must modify. + + This is only enabled when log_bin=0 to prevent changes + from being replayed out of order on the slave. + */ + prebuilt->select_lock_type = LOCK_NONE; + prebuilt->stored_select_lock_type = LOCK_NONE; + } else { + prebuilt->select_lock_type = LOCK_S; + prebuilt->stored_select_lock_type = LOCK_S; + } } else if (lock_type != TL_IGNORE) { @@ -5141,4 +5241,60 @@ return(nr); } +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::reset_mysql_relay_info() +{ + strmake(trx_sys_mysql_relay_log_name, "", strlen("")); + trx_sys_mysql_relay_log_pos = -1; + + strmake(trx_sys_mysql_master_log_name, "", strlen("")); + trx_sys_mysql_master_log_pos = -1; + + // TODO(wei): we should start a mini-transaction to commit the + // information to disk. +} + +/* allocate an innodb transaction */ +trx_t* ha_innobase::allocate_trx(THD *thd, char **query_str) +{ + trx_t *trx = trx_allocate_for_mysql(); + trx->mysql_thd = thd; + trx->mysql_query_str = query_str; + + /* If we allow replication sql thread to enter innodb without + * ticket limit, set the field to indicate that. + */ + if (thd && thd->slave_thread && rpl_always_enter_innodb) + trx->always_enter_innodb = TRUE; + + return trx; +} + +void ha_innobase::print_mysql_relay_log_pos() { + trx_sys_print_mysql_relay_log_pos(FALSE); +} + #endif /* HAVE_INNOBASE_DB */ diff -ruN base/sql/ha_innodb.h mysql40gpl/sql/ha_innodb.h --- base/sql/ha_innodb.h 2005-09-02 15:38:00.000000000 -0700 +++ mysql40gpl/sql/ha_innodb.h 2007-04-21 09:57:10.000000000 -0700 @@ -32,6 +32,8 @@ uint table_name_length,use_count; } INNOBASE_SHARE; +typedef struct trx_struct trx_t; + /* The class defining a handle to an Innodb table */ class ha_innobase: public handler { @@ -185,8 +187,30 @@ enum thr_lock_type lock_type); void init_table_handle_for_HANDLER(); longlong get_auto_increment(); + + // 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(); + + /* allocate an innodb transaction */ + static trx_t *allocate_trx(THD *thd, char **query_str); }; +extern long innobase_max_merged_io; +extern my_bool innodb_no_share_locks_on_dml_select; extern bool innodb_skip; extern uint innobase_init_flags, innobase_lock_type; extern uint innobase_flush_log_at_trx_commit; @@ -197,6 +221,7 @@ extern long innobase_log_file_size, innobase_log_buffer_size; extern long innobase_buffer_pool_size, innobase_additional_mem_pool_size; extern long innobase_file_io_threads, innobase_lock_wait_timeout; +extern long innobase_read_io_threads, innobase_write_io_threads; extern long innobase_force_recovery, innobase_thread_concurrency; extern char *innobase_data_home_dir, *innobase_data_file_path; extern char *innobase_log_group_home_dir, *innobase_log_arch_dir; @@ -209,6 +234,7 @@ extern ulong srv_max_buf_pool_modified_pct; extern ulong srv_max_purge_lag; extern ulong srv_auto_extend_increment; +extern ulong btr_key_val_estimate_n_pages; } extern TYPELIB innobase_lock_typelib; @@ -242,3 +268,4 @@ my_bool innobase_query_caching_of_table_permitted(THD* thd, char* full_name, uint full_name_len); void innobase_release_temporary_latches(void* innobase_tid); + diff -ruN base/sql/ha_myisam.cc mysql40gpl/sql/ha_myisam.cc --- base/sql/ha_myisam.cc 2005-09-02 15:38:00.000000000 -0700 +++ mysql40gpl/sql/ha_myisam.cc 2007-04-21 09:57:10.000000000 -0700 @@ -248,7 +248,9 @@ */ if (table->next_number_field && buf == table->record[0]) update_auto_increment(); - return mi_write(file,buf); + int error=mi_write(file,buf); + if (!error) rows_changed++; + return error; } int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt) @@ -806,13 +808,17 @@ statistic_increment(ha_update_count,&LOCK_status); if (table->time_stamp) update_timestamp(new_data+table->time_stamp-1); - return mi_update(file,old_data,new_data); + int error=mi_update(file,old_data,new_data); + if (!error) rows_changed++; + return error; } int ha_myisam::delete_row(const byte * buf) { statistic_increment(ha_delete_count,&LOCK_status); - return mi_delete(file,buf); + int error=mi_delete(file,buf); + if (!error) rows_changed++; + return error; } int ha_myisam::index_read(byte * buf, const byte * key, @@ -821,6 +827,13 @@ statistic_increment(ha_read_key_count,&LOCK_status); int error=mi_rkey(file,buf,active_index, key, key_len, find_flag); table->status=error ? STATUS_NOT_FOUND: 0; + if (!error) { + rows_read++; + + int inx = (active_index == -1) ? file->lastinx : active_index; + if (inx >= 0 && inx < MAX_KEY) + index_rows_read[inx]++; + } return error; } @@ -830,6 +843,13 @@ statistic_increment(ha_read_key_count,&LOCK_status); int error=mi_rkey(file,buf,index, key, key_len, find_flag); table->status=error ? STATUS_NOT_FOUND: 0; + if (!error) { + rows_read++; + + int inx = (active_index == -1) ? file->lastinx : active_index; + if (inx >= 0 && inx < MAX_KEY) + index_rows_read[inx]++; + } return error; } @@ -838,6 +858,13 @@ statistic_increment(ha_read_key_count,&LOCK_status); int error=mi_rkey(file,buf,active_index, key, key_len, HA_READ_PREFIX_LAST); table->status=error ? STATUS_NOT_FOUND: 0; + if (!error) { + rows_read++; + + int inx = (active_index == -1) ? file->lastinx : active_index; + if (inx >= 0 && inx < MAX_KEY) + index_rows_read[inx]++; + } return error; } @@ -846,6 +873,13 @@ statistic_increment(ha_read_next_count,&LOCK_status); int error=mi_rnext(file,buf,active_index); table->status=error ? STATUS_NOT_FOUND: 0; + if (!error) { + rows_read++; + + int inx = (active_index == -1) ? file->lastinx : active_index; + if (inx >= 0 && inx < MAX_KEY) + index_rows_read[inx]++; + } return error; } @@ -854,6 +888,13 @@ statistic_increment(ha_read_prev_count,&LOCK_status); int error=mi_rprev(file,buf, active_index); table->status=error ? STATUS_NOT_FOUND: 0; + if (!error) { + rows_read++; + + int inx = (active_index == -1) ? file->lastinx : active_index; + if (inx >= 0 && inx < MAX_KEY) + index_rows_read[inx]++; + } return error; } @@ -862,6 +903,13 @@ statistic_increment(ha_read_first_count,&LOCK_status); int error=mi_rfirst(file, buf, active_index); table->status=error ? STATUS_NOT_FOUND: 0; + if (!error) { + rows_read++; + + int inx = (active_index == -1) ? file->lastinx : active_index; + if (inx >= 0 && inx < MAX_KEY) + index_rows_read[inx]++; + } return error; } @@ -870,6 +918,13 @@ statistic_increment(ha_read_last_count,&LOCK_status); int error=mi_rlast(file, buf, active_index); table->status=error ? STATUS_NOT_FOUND: 0; + if (!error) { + rows_read++; + + int inx = (active_index == -1) ? file->lastinx : active_index; + if (inx >= 0 && inx < MAX_KEY) + index_rows_read[inx]++; + } return error; } @@ -880,6 +935,13 @@ statistic_increment(ha_read_next_count,&LOCK_status); int error=mi_rnext_same(file,buf); table->status=error ? STATUS_NOT_FOUND: 0; + if (!error) { + rows_read++; + + int inx = (active_index == -1) ? file->lastinx : active_index; + if (inx >= 0 && inx < MAX_KEY) + index_rows_read[inx]++; + } return error; } @@ -896,6 +958,7 @@ statistic_increment(ha_read_rnd_next_count,&LOCK_status); int error=mi_scan(file, buf); table->status=error ? STATUS_NOT_FOUND: 0; + if (!error) rows_read++; return error; } @@ -909,6 +972,7 @@ statistic_increment(ha_read_rnd_count,&LOCK_status); int error=mi_rrnd(file, buf, ha_get_ptr(pos,ref_length)); table->status=error ? STATUS_NOT_FOUND: 0; + if (!error) rows_read++; return error; } diff -ruN base/sql/handler.cc mysql40gpl/sql/handler.cc --- base/sql/handler.cc 2005-09-02 15:37:59.000000000 -0700 +++ mysql40gpl/sql/handler.cc 2007-04-21 11:16:31.000000000 -0700 @@ -344,6 +344,7 @@ { bool operation_done= 0, need_start_waiters= 0; bool transaction_commited= 0; + bool auto_commit_done= 0; /* If transaction has done some updates to tables */ if (trans == &thd->transaction.all && my_b_tell(&thd->transaction.trans_log)) @@ -389,6 +390,10 @@ my_error(ER_ERROR_DURING_COMMIT, MYF(0), error); error=1; } + else if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) + { + auto_commit_done= 1; + } trans->innodb_active_trans=0; if (trans == &thd->transaction.all) operation_done= transaction_commited= 1; @@ -401,9 +406,13 @@ if (error && trans == &thd->transaction.all && mysql_bin_log.is_open()) sql_print_error("Error: Got error during commit; Binlog is not up to date!"); thd->variables.tx_isolation=thd->session_tx_isolation; - if (operation_done) + if (operation_done || auto_commit_done) { statistic_increment(ha_commit_count,&LOCK_status); + thd->diff_commit_trans++; + } + if (operation_done) + { thd->transaction.cleanup(); } if (need_start_waiters) @@ -465,8 +474,10 @@ thd->transaction.cleanup(); } thd->variables.tx_isolation=thd->session_tx_isolation; - if (operation_done) + if (operation_done) { statistic_increment(ha_rollback_count,&LOCK_status); + thd->diff_rollback_trans++; + } } #endif /* USING_TRANSACTIONS */ DBUG_RETURN(error); @@ -539,8 +550,10 @@ } operation_done=1; #endif - if (operation_done) + if (operation_done) { statistic_increment(ha_rollback_count,&LOCK_status); + thd->diff_rollback_trans++; + } } #endif /* USING_TRANSACTIONS */ @@ -716,6 +729,8 @@ else dupp_ref=ref+ALIGN_SIZE(ref_length); } + rows_read = rows_changed = 0; + memset(index_rows_read, 0, sizeof(index_rows_read)); DBUG_RETURN(error); } @@ -1054,6 +1069,91 @@ return (my_errno=HA_ERR_WRONG_COMMAND); } +// Updates the global table stats with the TABLE this handler represents. +void handler::update_global_table_stats() { + if (!rows_read && !rows_changed) return; // Nothing to update. + if (!table->table_cache_key || !table->real_name) return; + + TABLE_STATS* table_stats; + char key[NAME_LEN * 2 + 2]; + // [db] + '.' + [table] + sprintf(key, "%s.%s", table->table_cache_key, table->real_name); + + pthread_mutex_lock(&LOCK_global_table_stats); + // Gets the global table stats, creating one if necessary. + if (!(table_stats = (TABLE_STATS*)hash_search(&global_table_stats, + (byte*)key, + strlen(key)))) { + if (!(table_stats = ((TABLE_STATS*) + my_malloc(sizeof(TABLE_STATS), MYF(MY_WME))))) { + // Out of memory. + goto end; + } + strncpy(table_stats->table, key, sizeof(table_stats->table)); + table_stats->rows_read = 0; + table_stats->rows_changed = 0; + table_stats->rows_changed_x_indexes = 0; + + if (hash_insert(&global_table_stats, (byte*)table_stats)) { + // Out of memory. + my_free((char*)table_stats, 0); + goto end; + } + } + // Updates the global table stats. + table_stats->rows_read += rows_read; + table_stats->rows_changed += rows_changed; + table_stats->rows_changed_x_indexes += rows_changed * max(table->keys, 1); + rows_read = rows_changed = 0; +end: + pthread_mutex_unlock(&LOCK_global_table_stats); +} + +// Updates the global index stats with this handler's accumulated index reads. +void handler::update_global_index_stats() { + if (!table->table_cache_key || !table->real_name) return; + + for (int x = 0; x < table->keys; x++) { + if (index_rows_read[x]) { + // Rows were read using this index. + KEY* key_info = &table->key_info[x]; + + if (!key_info->name) continue; + + INDEX_STATS* index_stats; + char key[NAME_LEN * 3 + 3]; + // [db] + '.' + [table] + '.' + [index] + sprintf(key, "%s.%s.%s", table->table_cache_key, table->real_name, + key_info->name); + + pthread_mutex_lock(&LOCK_global_index_stats); + // Gets the global index stats, creating one if necessary. + if (!(index_stats = (INDEX_STATS*)hash_search(&global_index_stats, + (byte*)key, + strlen(key)))) { + if (!(index_stats = ((INDEX_STATS*) + my_malloc(sizeof(INDEX_STATS), MYF(MY_WME))))) { + // Out of memory. + goto end; + } + strncpy(index_stats->index, key, sizeof(index_stats->index)); + index_stats->rows_read = 0; + + if (hash_insert(&global_index_stats, (byte*)index_stats)) { + // Out of memory. + my_free((char*)index_stats, 0); + goto end; + } + } + // Updates the global index stats. + index_stats->rows_read += index_rows_read[x]; + index_rows_read[x] = 0; +end: + pthread_mutex_unlock(&LOCK_global_index_stats); + } + } +} + /**************************************************************************** ** Some general functions that isn't in the handler class ****************************************************************************/ diff -ruN base/sql/handler.h mysql40gpl/sql/handler.h --- base/sql/handler.h 2005-09-02 15:38:07.000000000 -0700 +++ mysql40gpl/sql/handler.h 2007-04-21 11:15:26.000000000 -0700 @@ -31,6 +31,10 @@ #define USING_TRANSACTIONS #endif +#if MAX_KEY > 128 +#error MAX_KEY is too large. Values up to 128 are supported. +#endif + // the following is for checking tables #define HA_ADMIN_ALREADY_DONE 1 @@ -185,10 +189,38 @@ void init(); } HA_CHECK_OPT; +#if DBUG_ON +#undef NDEBUG +#include + +class canary { + public: + static const long kGoodCanary = 0xabcd1234L; + static const long kBadCanary = 1; + + canary() : tag_(kGoodCanary) {} + canary(const canary& rhs) { + rhs.assert_valid(); + tag_ = kGoodCanary; + } + ~canary() { + assert_valid(); + tag_ = kBadCanary; + } + bool valid() const { return tag_ == kGoodCanary; } + void assert_valid() const { assert(valid()); } + private: + long tag_; +}; +#endif + class handler :public Sql_alloc { protected: struct st_table *table; /* The table definition */ +#if DBUG_ON + canary canary_; /* Guard against multiple deletes */ +#endif public: byte *ref; /* Pointer to current row */ @@ -216,6 +248,9 @@ FT_INFO *ft_handler; bool auto_increment_column_changed; bool implicit_emptied; /* Can be !=0 only if HEAP */ + ulonglong rows_read; + ulonglong rows_changed; + ulonglong index_rows_read[MAX_KEY]; handler(TABLE *table_arg) :table(table_arg), ref(0), data_file_length(0), max_data_file_length(0), index_file_length(0), @@ -224,15 +259,22 @@ create_time(0), check_time(0), update_time(0), key_used_on_scan(MAX_KEY), active_index(MAX_REF_PARTS), ref_length(sizeof(my_off_t)), block_size(0), - raid_type(0), ft_handler(0), implicit_emptied(0) - {} + raid_type(0), ft_handler(0), implicit_emptied(0), + rows_read(0), rows_changed(0) + { + memset(index_rows_read, 0, sizeof(index_rows_read)); + } virtual ~handler(void) {} int ha_open(const char *name, int mode, int test_if_locked); void update_timestamp(byte *record); void update_auto_increment(); virtual void print_error(int error, myf errflag); uint get_dup_key(int error); - void change_table_ptr(TABLE *table_arg) { table=table_arg; } + void change_table_ptr(TABLE *table_arg) { + table=table_arg; + rows_read = rows_changed = 0; + memset(index_rows_read, 0, sizeof(index_rows_read)); + } virtual double scan_time() { return ulonglong2double(data_file_length) / IO_SIZE + 2; } virtual double read_time(uint index, uint ranges, ha_rows rows) @@ -352,6 +394,9 @@ virtual THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type)=0; + + void update_global_table_stats(); + void update_global_index_stats(); }; /* Some extern variables used with handlers */ diff -ruN base/sql/hash_64.cc mysql40gpl/sql/hash_64.cc --- base/sql/hash_64.cc 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/sql/hash_64.cc 2007-04-21 09:57:10.000000000 -0700 @@ -0,0 +1,102 @@ +/* + * hash_64 - 64 bit Fowler/Noll/Vo-0 hash code + * + * @(#) $Revision: 1.8 $ + * @(#) $Id: hash_64.c,v 1.8 2003/10/03 20:37:04 chongo Exp $ + * @(#) $Source: /usr/local/src/cmd/fnv/RCS/hash_64.c,v $ + * + *** + * + * Fowler/Noll/Vo hash + * + * The basis of this hash algorithm was taken from an idea sent + * as reviewer comments to the IEEE POSIX P1003.2 committee by: + * + * Phong Vo (http://www.research.att.com/info/kpv/) + * Glenn Fowler (http://www.research.att.com/~gsf/) + * + * In a subsequent ballot round: + * + * Landon Curt Noll (http://www.isthe.com/chongo/) + * + * improved on their algorithm. Some people tried this hash + * and found that it worked rather well. In an EMail message + * to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash. + * + * FNV hashes are designed to be fast while maintaining a low + * collision rate. The FNV speed allows one to quickly hash lots + * of data while maintaining a reasonable collision rate. See: + * + * http://www.isthe.com/chongo/tech/comp/fnv/index.html + * + * for more details as well as other forms of the FNV hash. + * + *** + * + * NOTE: The FNV-0 historic hash is not recommended. One should use + * the FNV-1 hash instead. + * + * To use the 64 bit FNV-0 historic hash, pass FNV0_64_INIT as the + * Fnv64_t hashval argument to fnv_64_buf() or fnv_64_str(). + * + * To use the recommended 64 bit FNV-1 hash, pass FNV1_64_INIT as the + * Fnv64_t hashval argument to fnv_64_buf() or fnv_64_str(). + * + *** + * + * Please do not copyright this code. This code is in the public domain. + * + * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * By: + * chongo /\oo/\ + * http://www.isthe.com/chongo/ + * + * Share and Enjoy! :-) + */ + +#include "hash_64.h" + +/* + * 64 bit magic FNV-0 and FNV-1 prime + */ +static const ulonglong FNV_64_PRIME = 0x100000001b3ULL; + +/* + * hash64 - perform a 64 bit Fowler/Noll/Vo hash on a buffer + * + * input: + * buf - start of buffer to hash + * len - length of buffer in octets + * hval - previous hash value or 0 if first call + * + * returns: + * 64 bit hash + * + * NOTE: To use the recommended 64 bit FNV-1 hash, use HASH_64_INIT as the hval + * argument on the first call to hash64() + */ +ulonglong hash64(const void *buf, size_t len, ulonglong hval) +{ + const unsigned char *bp = (const unsigned char*)buf; + const unsigned char *be = bp + len; + + /* + * FNV-1 hash each octet of the buffer + */ + for (; bp != be; ++bp) { + /* multiply by the 64 bit FNV magic prime mod 2^64 */ + hval *= FNV_64_PRIME; + + /* xor the bottom with the current octet */ + hval ^= (ulonglong)*bp; + } + + return hval; +} diff -ruN base/sql/hash_64.h mysql40gpl/sql/hash_64.h --- base/sql/hash_64.h 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/sql/hash_64.h 2007-04-21 09:57:10.000000000 -0700 @@ -0,0 +1,69 @@ +/* + * hash_64 - 64 bit Fowler/Noll/Vo-0 hash code + * + * @(#) $Revision: 1.8 $ + * @(#) $Id: hash_64.c,v 1.8 2003/10/03 20:37:04 chongo Exp $ + * @(#) $Source: /usr/local/src/cmd/fnv/RCS/hash_64.c,v $ + * + *** + * + * Fowler/Noll/Vo hash + * + * The basis of this hash algorithm was taken from an idea sent + * as reviewer comments to the IEEE POSIX P1003.2 committee by: + * + * Phong Vo (http://www.research.att.com/info/kpv/) + * Glenn Fowler (http://www.research.att.com/~gsf/) + * + * In a subsequent ballot round: + * + * Landon Curt Noll (http://www.isthe.com/chongo/) + * + * improved on their algorithm. Some people tried this hash + * and found that it worked rather well. In an EMail message + * to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash. + * + * FNV hashes are designed to be fast while maintaining a low + * collision rate. The FNV speed allows one to quickly hash lots + * of data while maintaining a reasonable collision rate. See: + * + * http://www.isthe.com/chongo/tech/comp/fnv/index.html + * + * for more details as well as other forms of the FNV hash. + * + *** + * + * NOTE: The FNV-0 historic hash is not recommended. One should use + * the FNV-1 hash instead. + * + * To use the 64 bit FNV-0 historic hash, pass FNV0_64_INIT as the + * Fnv64_t hashval argument to fnv_64_buf() or fnv_64_str(). + * + * To use the recommended 64 bit FNV-1 hash, pass FNV1_64_INIT as the + * Fnv64_t hashval argument to fnv_64_buf() or fnv_64_str(). + * + *** + * + * Please do not copyright this code. This code is in the public domain. + * + * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * By: + * chongo /\oo/\ + * http://www.isthe.com/chongo/ + * + * Share and Enjoy! :-) + */ + +#include "my_global.h" +#define HASH_64_INIT 0x84222325cbf29ce4ULL +/* Return a hash of the data in buf of size len using hval as the intial + * value for the hash function. + */ +ulonglong hash64(const void *buf, size_t len, ulonglong hval); diff -ruN base/sql/item.cc mysql40gpl/sql/item.cc --- base/sql/item.cc 2005-09-02 15:38:05.000000000 -0700 +++ mysql40gpl/sql/item.cc 2007-04-21 09:57:10.000000000 -0700 @@ -22,6 +22,7 @@ #include "mysql_priv.h" #include #include "my_dir.h" +#include "hash_64.h" /***************************************************************************** ** Item functions @@ -803,6 +804,51 @@ return result == field->val_real(); } +ulonglong hash_args(Item **args, + uint arg_count, + const ulonglong initial_value) { + uint null_default = 0x0a0b0c0d; + ulonglong row_hash = initial_value; + for (int a = 0; a < arg_count; ++a) { + // The argument is evaluated to determine when it is null. + switch (args[a]->result_type()) { + case STRING_RESULT: + { + String s; + String *sp = args[a]->val_str(&s); + if (!args[a]->null_value) + row_hash = hash64((const void*)sp->ptr(), sp->length(), row_hash); + else + row_hash = hash64((const void*)&null_default, sizeof(null_default), + row_hash); + } + break; + case REAL_RESULT: + { + double value = args[a]->val(); + if (!args[a]->null_value) + row_hash = hash64((const void*)&value, sizeof(value), row_hash); + else + row_hash = hash64((const void*)&null_default, sizeof(null_default), + row_hash); + } + break; + case INT_RESULT: + { + longlong value = args[a]->val_int(); + if (!args[a]->null_value) + row_hash = hash64((const void*)&value, sizeof(value), row_hash); + else + row_hash = hash64((const void*)&null_default, sizeof(null_default), + row_hash); + } + break; + default: + break; + } + } + return row_hash; +} /***************************************************************************** ** Instantiate templates diff -ruN base/sql/item_create.cc mysql40gpl/sql/item_create.cc --- base/sql/item_create.cc 2005-09-02 15:38:01.000000000 -0700 +++ mysql40gpl/sql/item_create.cc 2007-04-21 09:57:10.000000000 -0700 @@ -456,3 +456,8 @@ { return new Item_func_quote(a); } + +Item *create_func_ieee754_to_string(Item* a) +{ + return new Item_func_ieee754_to_string(a); +} diff -ruN base/sql/item_create.h mysql40gpl/sql/item_create.h --- base/sql/item_create.h 2005-09-02 15:38:00.000000000 -0700 +++ mysql40gpl/sql/item_create.h 2007-04-21 09:57:10.000000000 -0700 @@ -95,3 +95,4 @@ Item *create_load_file(Item* a); Item *create_func_is_free_lock(Item* a); Item *create_func_quote(Item* a); +Item *create_func_ieee754_to_string(Item *a); diff -ruN base/sql/item_func.cc mysql40gpl/sql/item_func.cc --- base/sql/item_func.cc 2005-09-02 15:38:01.000000000 -0700 +++ mysql40gpl/sql/item_func.cc 2007-04-21 09:57:10.000000000 -0700 @@ -27,6 +27,7 @@ #include #include #include "slave.h" // for wait_for_master_pos +#include "hash_64.h" /* return TRUE if item is a constant */ @@ -2477,3 +2478,35 @@ return 1; return 0; } + + +void Item_func_hash::fix_length_and_dec() +{ + decimals=0; + max_length=21; + maybe_null=0; + binary=0; + unsigned_flag = 1; +} + + +String *Item_func_hash::val_str(String *str) +{ + ulonglong nr = (ulonglong) val_int(); + str->set(nr); + return str; +} + + +double Item_func_hash::val() +{ + ulonglong nr = (ulonglong) val_int(); + return (double) nr; +} + + +longlong Item_func_hash::val_int() +{ + null_value = 0; // This always evaluates to a non-null value. + return (longlong) hash_args(args, arg_count, HASH_64_INIT); +} diff -ruN base/sql/item_func.h mysql40gpl/sql/item_func.h --- base/sql/item_func.h 2005-09-02 15:37:59.000000000 -0700 +++ mysql40gpl/sql/item_func.h 2007-04-21 09:57:10.000000000 -0700 @@ -500,6 +500,27 @@ }; +// An N-ary function to compute the hash of its input. +// select hash(col1, col2) from foo +class Item_func_hash :public Item_func +{ +public: + Item_func_hash(List &list) :Item_func(list) {} + // The input to the function exists when the val* functions are called. + // A default value is substituted for null input arguments. + // These also set a variable to indicate that the result is not null. + double val(); + longlong val_int(); + String *val_str(String *); + // Set the maximum length in characters of the result and whether the result + // may be null. By design, the result of this is never null. + void fix_length_and_dec(); + enum Item_result result_type () const { return INT_RESULT; } + unsigned int size_of() { return sizeof(*this);} + const char *func_name() const { return "hash"; } +}; + + class Item_func_min_max :public Item_func { Item_result cmp_type; diff -ruN base/sql/item.h mysql40gpl/sql/item.h --- base/sql/item.h 2005-09-02 15:37:55.000000000 -0700 +++ mysql40gpl/sql/item.h 2007-04-21 09:57:10.000000000 -0700 @@ -582,3 +582,15 @@ extern Item_result item_cmp_type(Item_result a,Item_result b); extern Item *resolve_const_item(Item *item,Item *cmp_item); extern bool field_is_equal_to_item(Field *field,Item *item); + +/* + Compute a hash value from all entries in 'args'. Handles + all datatypes. Use a default value for nulls. + Parameters: + args: values to hash. + arg_count: number of entries in args + initial_value: the initial value for the hash function. +*/ +extern ulonglong hash_args(Item **args, + uint arg_count, + const ulonglong initial_value); diff -ruN base/sql/item_strfunc.cc mysql40gpl/sql/item_strfunc.cc --- base/sql/item_strfunc.cc 2005-09-02 15:38:03.000000000 -0700 +++ mysql40gpl/sql/item_strfunc.cc 2007-04-21 09:57:10.000000000 -0700 @@ -33,6 +33,7 @@ #include "md5.h" #include "sha1.h" #include "my_aes.h" +#include String empty_string(""); @@ -2239,3 +2240,56 @@ null_value= 1; return 0; } + +String* Item_func_ieee754_to_string::val_str(String *str) +{ + null_value= 0; + switch (args[0]->result_type()) + { + case REAL_RESULT: + { + // TODO(mcallaghan): distinguish double from float + double res = args[0]->val(); + if (args[0]->null_value) { + // Null argument, return NULL + null_value= 1; + return (String*) 0; + } else { + // Use 17 digits of precision so that the conversion from + // double -> decimal -> double is lossless. + char buf[30]; + if (isnan(res)) { + str->copy("nan", strlen("nan")); + } else if (isinf(res)) { + if (res < 0) + str->copy("-inf", strlen("-inf")); + else + str->copy("inf", strlen("inf")); + } else { + sprintf(buf, "%-24.17g", res); + str->copy(buf, strlen(buf)); + } + } + return str; + } + case INT_RESULT: + case STRING_RESULT: + default: + { + String *res = args[0]->val_str(str); + if (!res) { + // Null argument, return NULL + null_value= 1; + return (String*) 0; + } else { + // Return a string with <= 24 characters to respect max_length. + if (res->length() > 24) { + char buf[24]; + memcpy(buf, res->c_ptr(), 24); + res->copy(buf, 24); + } + return res; + } + } + } +} diff -ruN base/sql/item_strfunc.h mysql40gpl/sql/item_strfunc.h --- base/sql/item_strfunc.h 2005-09-02 15:37:59.000000000 -0700 +++ mysql40gpl/sql/item_strfunc.h 2007-04-21 09:57:10.000000000 -0700 @@ -542,3 +542,21 @@ String *val_str(String *); void fix_length_and_dec() { max_length= args[0]->max_length * 2 + 2; } }; + +// The conversion from double -> decimal -> double is lossless when the +// conversion from double -> decimal generates 17 digits of precision. +// This function implemented by this class makes that possible. +class Item_func_ieee754_to_string :public Item_str_func +{ + String tmp_str; +public: + Item_func_ieee754_to_string(Item *a) : Item_str_func(a) { } + String *val_str(String *); + void fix_length_and_dec() + { + // 7 chars overhead + 17 digits of precision + max_length= 24; + } + const char *func_name() const { return "ieee754_to_string"; } + unsigned int size_of() { return sizeof(*this);} +}; diff -ruN base/sql/item_sum.cc mysql40gpl/sql/item_sum.cc --- base/sql/item_sum.cc 2005-09-02 15:38:00.000000000 -0700 +++ mysql40gpl/sql/item_sum.cc 2007-04-21 09:57:10.000000000 -0700 @@ -1117,6 +1117,22 @@ return table->file->records; } +bool Item_sum_unordered_checksum::add() +{ + // The hash for each row xor'd to make this row order independent. + bits ^= hash_args(args, arg_count, HASH_64_INIT); + return 0; +} + +bool Item_sum_ordered_checksum::add() +{ + // The hash for each row is the initial hash for the next row to make + // this row order dependent. + bits = hash_args(args, arg_count, bits); + return 0; +} + + /**************************************************************************** ** Functions to handle dynamic loadable aggregates ** Original source by: Alexis Mikhailov diff -ruN base/sql/item_sum.h mysql40gpl/sql/item_sum.h --- base/sql/item_sum.h 2005-09-02 15:38:00.000000000 -0700 +++ mysql40gpl/sql/item_sum.h 2007-04-21 09:57:10.000000000 -0700 @@ -22,6 +22,7 @@ #endif #include +#include "hash_64.h" class Item_sum :public Item_result_field { @@ -371,9 +372,12 @@ class Item_sum_bit :public Item_sum_int { protected: - ulonglong reset_bits,bits; + const ulonglong reset_bits; + ulonglong bits; public: + Item_sum_bit(List &list,ulonglong reset_arg) + :Item_sum_int(list),reset_bits(reset_arg),bits(reset_arg) {} Item_sum_bit(Item *item_par,ulonglong reset_arg) :Item_sum_int(item_par),reset_bits(reset_arg),bits(reset_arg) {} enum Sumfunctype sum_func () const {return SUM_BIT_FUNC;} @@ -406,6 +410,33 @@ unsigned int size_of() { return sizeof(*this);} }; +// Aggregate checksum function that is row order-independent. +// select col1, unordered_checksum(col2, col3) from foo where ... group by col1 +// The checksum functions use a default value for null arguments. The result +// is never null. +class Item_sum_unordered_checksum :public Item_sum_bit +{ +public: + Item_sum_unordered_checksum(List &list) :Item_sum_bit(list, HASH_64_INIT) {} + // Called for each row in a group. reset() is called before the first + // row in a group. + bool add(); + const char *func_name() const { return "unordered_checksum"; } + unsigned int size_of() { return sizeof(*this);} +}; + + +// Aggregate checksum function that is row order-dependent. +// select col1, ordered_checksum(col2, col3) from foo where ... group by col1 +class Item_sum_ordered_checksum :public Item_sum_bit +{ +public: + Item_sum_ordered_checksum(List &list) :Item_sum_bit(list, HASH_64_INIT) {} + bool add(); + const char *func_name() const { return "ordered_checksum"; } + unsigned int size_of() { return sizeof(*this);} +}; + /* ** user defined aggregates */ diff -ruN base/sql/lex.h mysql40gpl/sql/lex.h --- base/sql/lex.h 2005-09-02 15:37:59.000000000 -0700 +++ mysql40gpl/sql/lex.h 2007-04-21 11:10:30.000000000 -0700 @@ -179,6 +179,7 @@ { "IN", SYM(IN_SYM),0,0}, { "INDEX", SYM(INDEX),0,0}, { "INDEXES", SYM(INDEXES),0,0}, + { "INDEX_STATISTICS", SYM(INDEX_STATS_SYM),0,0}, { "INFILE", SYM(INFILE),0,0}, { "INNER", SYM(INNER_SYM),0,0}, { "INNOBASE", SYM(INNOBASE_SYM),0,0}, @@ -222,6 +223,7 @@ { "LONGBLOB", SYM(LONGBLOB),0,0}, { "LONGTEXT", SYM(LONGTEXT),0,0}, { "LOW_PRIORITY", SYM(LOW_PRIORITY),0,0}, + { "MAKE", SYM(MAKE),0,0}, { "MASTER", SYM(MASTER_SYM),0,0}, { "MASTER_CONNECT_RETRY", SYM(MASTER_CONNECT_RETRY_SYM),0,0}, { "MASTER_HOST", SYM(MASTER_HOST_SYM),0,0}, @@ -342,6 +344,7 @@ { "SUPER", SYM(SUPER_SYM),0,0}, { "TABLE", SYM(TABLE_SYM),0,0}, { "TABLES", SYM(TABLES),0,0}, + { "TABLE_STATISTICS", SYM(TABLE_STATS_SYM),0,0}, { "TEMPORARY", SYM(TEMPORARY),0,0}, { "TERMINATED", SYM(TERMINATED),0,0}, { "TEXT", SYM(TEXT_SYM),0,0}, @@ -361,7 +364,9 @@ { "UNIQUE", SYM(UNIQUE_SYM),0,0}, { "UNLOCK", SYM(UNLOCK_SYM),0,0}, { "UNSIGNED", SYM(UNSIGNED),0,0}, + { "UNTIL", SYM(UNTIL_SYM),0,0}, { "USE", SYM(USE_SYM),0,0}, + { "USER_STATISTICS", SYM(USER_STATS_SYM),0,0}, { "USE_FRM", SYM(USE_FRM),0,0}, { "USING", SYM(USING),0,0}, { "UPDATE", SYM(UPDATE_SYM),0,0}, @@ -445,7 +450,9 @@ { "GET_LOCK", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_get_lock)}, { "GREATEST", SYM(GREATEST_SYM),0,0}, { "GROUP_UNIQUE_USERS", SYM(GROUP_UNIQUE_USERS),0,0}, + { "HASH", SYM(HASH_SYM),0,0}, { "HEX", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_hex)}, + { "IEEE754_TO_STRING", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ieee754_to_string)}, { "IFNULL", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_ifnull)}, { "INET_ATON", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_inet_aton)}, { "INET_NTOA", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_inet_ntoa)}, @@ -479,6 +486,7 @@ { "OCT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_oct)}, { "OLD_PASSWORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_password)}, { "ORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ord)}, + { "ORDERED_CHECKSUM", SYM(ORDERED_CHECKSUM_SYM)}, { "PERIOD_ADD", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_period_add)}, { "PERIOD_DIFF", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_period_diff)}, { "PI", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_pi)}, @@ -521,6 +529,7 @@ { "UCASE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)}, { "UNIQUE_USERS", SYM(UNIQUE_USERS),0,0}, { "UNIX_TIMESTAMP", SYM(UNIX_TIMESTAMP),0,0}, + { "UNORDERED_CHECKSUM", SYM(UNORDERED_CHECKSUM_SYM)}, { "UPPER", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)}, { "USER", SYM(USER),0,0}, { "VERSION", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_version)}, diff -ruN base/sql/log.cc mysql40gpl/sql/log.cc --- base/sql/log.cc 2005-09-02 15:38:00.000000000 -0700 +++ mysql40gpl/sql/log.cc 2007-04-21 09:57:11.000000000 -0700 @@ -35,12 +35,35 @@ #include "message.h" #endif -MYSQL_LOG mysql_log,mysql_update_log,mysql_slow_log,mysql_bin_log; +#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_audit_log,mysql_update_log; +MYSQL_LOG mysql_slow_log,mysql_bin_log; extern I_List binlog_do_db, binlog_ignore_db; static bool test_if_number(const char *str, long *res, bool allow_wildcards); +/* 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") } +}; + + #ifdef __NT__ static int eventSource = 0; @@ -118,7 +141,10 @@ my_dirend(dir_info); *end++='.'; - sprintf(end,"%03ld",max_found+1); + if (rpl_long_filename) + sprintf(end,"%06ld",max_found+1); + else + sprintf(end,"%03ld",max_found+1); DBUG_RETURN(0); } @@ -126,7 +152,8 @@ MYSQL_LOG::MYSQL_LOG() :bytes_written(0), last_time(0), query_start(0), name(0), file_id(1), open_count(1), log_type(LOG_CLOSED), write_error(0), inited(0), - need_start_event(1) + need_start_event(1), log_for_root(FALSE), active_mi_(NULL), + mule_binlog(false), mule_binlog_servable(false) { /* We don't want to initialize LOCK_Log here as such initialization depends on @@ -202,6 +229,75 @@ (void) pthread_cond_init(&update_cond, 0); } +const char *MYSQL_LOG::generate_name(const char *log_name, + const char *suffix, + bool strip_ext, char *buff) +{ + if (!log_name || !log_name[0]) + { + /* + TODO: The following should be using fn_format(); We just need to + first change fn_format() to cut the file name if it's too long. + */ + strmake(buff,glob_hostname,FN_REFLEN-5); + strmov(fn_ext(buff),suffix); + return (const char *)buff; + } + // get rid of extension if the log is binary to avoid problems + if (strip_ext) + { + char *p = fn_ext(log_name); + uint length=(uint) (p-log_name); + strmake(buff,log_name,min(length,FN_REFLEN)); + return (const char*)buff; + } + return log_name; +} + +bool MYSQL_LOG::open_index_file(const char *index_file_name_arg, + const char *log_name) { + File index_file_nr= -1; + + /* If the index is already opened, do not open it again. */ + if (my_b_inited(&index_file)) + return TRUE; + + /* + First open of this class instance + Create an index file that will hold all file names uses for logging. + Add new entries to the end of it. + */ + myf opt= MY_UNPACK_FILENAME; + if (!index_file_name_arg) + { + index_file_name_arg= log_name; // Use same basename for index file + opt= MY_UNPACK_FILENAME | MY_REPLACE_EXT; + } + fn_format(index_file_name, index_file_name_arg, mysql_data_home, + ".index", opt); + if ((index_file_nr= my_open(index_file_name, + O_RDWR | O_CREAT | O_BINARY , + MYF(MY_WME))) < 0 || + my_sync(index_file_nr, MYF(MY_WME)) || + init_io_cache(&index_file, index_file_nr, + IO_SIZE, WRITE_CACHE, + my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)), + 0, MYF(MY_WME | MY_WAIT_IF_FULL))) + { + if (index_file_nr >= 0) + my_close(index_file_nr,MYF(0)); + return FALSE; + } + return TRUE; +} + +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; +} /* Open a (new) log file. @@ -224,7 +320,7 @@ ulong max_size) { char buff[512]; - File file= -1, index_file_nr= -1; + File file= -1; int open_flags = O_CREAT | O_APPEND | O_BINARY; DBUG_ENTER("MYSQL_LOG::open"); DBUG_PRINT("enter",("log_type: %d",(int) log_type)); @@ -258,13 +354,30 @@ case LOG_NORMAL: { char *end; - int len=my_snprintf(buff, sizeof(buff), + char time_buff[32]; + struct tm tm_tmp; + time_t skr = time(NULL); + localtime_r(&skr,&tm_tmp); + int len = my_snprintf(time_buff, sizeof(time_buff), + "%02d%02d%02d %2d:%02d:%02d\t", + tm_tmp.tm_year % 100, + tm_tmp.tm_mon+1, + tm_tmp.tm_mday, + tm_tmp.tm_hour, + tm_tmp.tm_min, + tm_tmp.tm_sec); + if (len <= 0) { + // Something bad happened, skip printing time. + strcpy(time_buff, ""); + } + len=my_snprintf(buff, sizeof(buff), #ifdef __NT__ - "%s, Version: %s, started with:\nTCP Port: %d, Named Pipe: %s\n", + "%s %s, Version: %s, started with:\nTCP Port: %d, Named Pipe: %s\n", #else - "%s, Version: %s, started with:\nTcp port: %d Unix socket: %s\n", + "%s %s, Version: %s, started with:\nTcp port: %d Unix socket: %s\n", #endif - my_progname, server_version, mysql_port, mysql_unix_port); + time_buff, my_progname, server_version, + mysql_port, mysql_unix_port); end=strnmov(buff+len,"Time Id Command Argument\n", sizeof(buff)-len); if (my_b_write(&log_file, (byte*) buff,(uint) (end-buff)) || @@ -297,13 +410,6 @@ { bool write_file_name_to_index_file=0; - myf opt= MY_UNPACK_FILENAME; - if (!index_file_name_arg) - { - index_file_name_arg= name; // Use same basename for index file - opt= MY_UNPACK_FILENAME | MY_REPLACE_EXT; - } - if (!my_b_filelength(&log_file)) { /* @@ -321,20 +427,7 @@ if (!my_b_inited(&index_file)) { - /* - First open of this class instance - Create an index file that will hold all file names uses for logging. - Add new entries to the end of it. - */ - fn_format(index_file_name, index_file_name_arg, mysql_data_home, - ".index", opt); - if ((index_file_nr= my_open(index_file_name, - O_RDWR | O_CREAT | O_BINARY , - MYF(MY_WME))) < 0 || - init_io_cache(&index_file, index_file_nr, - IO_SIZE, WRITE_CACHE, - my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)), - 0, MYF(MY_WME))) + if (!open_index_file(index_file_name_arg, log_name)) goto err; } else @@ -350,6 +443,37 @@ s.set_log_pos(this); s.write(&log_file); } + 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) { + // Master_info_log_event should be removed + Rotate_log_event + mi_event(current_thd, mi->master_log_name, + strlen(mi->master_log_name), mi->master_log_pos); + 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.get_event_len(); + } + } + if (flush_io_cache(&log_file)) goto err; @@ -378,10 +502,8 @@ shutdown the MySQL server and restart it.", log_name, errno); if (file >= 0) my_close(file,MYF(0)); - if (index_file_nr >= 0) - my_close(index_file_nr,MYF(0)); end_io_cache(&log_file); - end_io_cache(&index_file); + close_index_file(); safeFree(name); log_type= LOG_CLOSED; DBUG_RETURN(1); @@ -392,7 +514,10 @@ { pthread_mutex_lock(&LOCK_log); strmake(linfo->log_file_name, log_file_name, sizeof(linfo->log_file_name)-1); - linfo->pos = my_b_tell(&log_file); + if (!mule_binlog) + linfo->pos = my_b_tell(&log_file); + else + linfo->pos = my_b_filelength(&log_file); pthread_mutex_unlock(&LOCK_log); return 0; } @@ -491,6 +616,11 @@ pthread_mutex_lock(&LOCK_index); safe_mutex_assert_owner(&LOCK_index); + if (!open_index_file(index_file_name, NULL)) { + error = -1; + goto l_err; + } + /* As the file is flushed, we can't get an error here */ (void) reinit_io_cache(&index_file, READ_CACHE, (my_off_t) 0, 0, 0); @@ -520,6 +650,7 @@ } } + l_err: if (need_lock) pthread_mutex_unlock(&LOCK_index); DBUG_RETURN(error); @@ -587,6 +718,7 @@ SYNOPSIS reset_logs() thd Thread + create_new_file Whether to create a new log file NOTE If not called from slave thread, write start event to new log @@ -597,7 +729,7 @@ 1 error */ -bool MYSQL_LOG::reset_logs(THD* thd) +bool MYSQL_LOG::reset_logs(THD* thd, bool create_new_file) { LOG_INFO linfo; bool error=0; @@ -636,10 +768,16 @@ /* Start logging with a new file */ close(LOG_CLOSE_INDEX); my_delete(index_file_name, MYF(MY_WME)); // Reset (open will update) - if (!thd->slave_thread) - need_start_event=1; - open(save_name, save_log_type, 0, index_file_name, - io_cache_type, no_auto_events, max_size); + + if (create_new_file) { + /* If we need to create a new file after reset all log files, do it. We + * do not need to create a new file when we clean up mirror binlog files. + */ + if (!thd->slave_thread) + need_start_event=1; + open(save_name, save_log_type, 0, index_file_name, + io_cache_type, no_auto_events, max_size); + } my_free((gptr) save_name, MYF(0)); err: @@ -847,18 +985,19 @@ new_file() need_lock Set to 1 (default) if caller has not locked LOCK_log and LOCK_index + logfile_name the specified log filename. NOTE The new file name is stored last in the index file */ -void MYSQL_LOG::new_file(bool need_lock) +void MYSQL_LOG::new_file(bool need_lock, const char* log_filename) { char new_name[FN_REFLEN], *new_name_ptr, *old_name; enum_log_type save_log_type; DBUG_ENTER("MYSQL_LOG::new_file"); - if (!is_open()) + if (!is_log_open()) { DBUG_PRINT("info",("log is closed")); DBUG_VOID_RETURN; @@ -880,12 +1019,18 @@ We have to do this here and not in open as we want to store the new file name in the current binary log file. */ - if (generate_new_name(new_name, name)) + if (log_filename) { + fn_format(new_name,log_filename,mysql_data_home,"",4); + } else if (generate_new_name(new_name, name)) goto end; new_name_ptr=new_name; if (log_type == LOG_BIN) { + // The largest event written to this binlog. Reset when a new binlog file + // is started. + binlog_largest_event = 0; + if (!no_auto_events) { /* @@ -977,7 +1122,7 @@ DBUG_ASSERT(log_file.type == SEQ_READ_APPEND); - pthread_mutex_lock(&LOCK_log); + safe_mutex_assert_owner(&LOCK_log); do { if (my_b_append(&log_file,(byte*) buf,len)) @@ -988,7 +1133,12 @@ bytes_written += len; } while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint))); DBUG_PRINT("info",("max_size: %lu",max_size)); - if ((uint) my_b_append_tell(&log_file) > max_size) + + /* If max_size is BINLOG_NOSWITCH_SIZE, binlog would not switch because + * of file size limit. + */ + if (max_size != BINLOG_NOSWITCH_SIZE && + (uint) my_b_append_tell(&log_file) > max_size) { pthread_mutex_lock(&LOCK_index); new_file(0); @@ -996,13 +1146,11 @@ } err: - pthread_mutex_unlock(&LOCK_log); if (!error) signal_update(); DBUG_RETURN(error); } - /* Write to normal (not rotable) log This is the format for the 'normal', 'slow' and 'update' logs. @@ -1087,6 +1235,12 @@ return 0; } +inline bool sync_binlog(IO_CACHE *cache) +{ + return (sync_binlog_period && + (sync_binlog_period == ++sync_binlog_counter) && + (sync_binlog_counter= 0, my_sync(cache->file, MYF(MY_WME)))); +} /* Write an event to the binary log @@ -1264,7 +1418,7 @@ if (file == &log_file) // we are writing to the real log (disk) { - if (flush_io_cache(file)) + if (flush_io_cache(file) || sync_binlog(file)) goto err; if (opt_using_transactions && @@ -1291,6 +1445,11 @@ } error=0; + // Update binlog varz to be exported. Protected by LOCK_log. + binlog_events++; + if (event_info->get_event_len() > binlog_largest_event) + binlog_largest_event = event_info->get_event_len(); + err: if (error) { @@ -1426,7 +1585,8 @@ TRUE); qinfo.error_code= 0; qinfo.set_log_pos(this); - if (qinfo.write(&log_file) || flush_io_cache(&log_file)) + if (qinfo.write(&log_file) || flush_io_cache(&log_file) || + sync_binlog(&log_file)) goto err; } if (cache->error) // Error on read @@ -1476,6 +1636,9 @@ - This code should be deleted in MySQL 5,0 as the binary log is a full replacement for the update log. + - This has been modified to use the update log as an audit log for changes + (DML, DDL) made by root. + */ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length, @@ -1491,13 +1654,18 @@ int tmp_errno=0; char buff[80],*end; end=buff; - if (!(thd->options & OPTION_UPDATE_LOG) && - (thd->master_access & SUPER_ACL)) + // Do not log if + // * request to not log, root and not logging dml for root or + // * not root and logging dml for root or + // * this is the replication thread + if ((!(thd->options & OPTION_UPDATE_LOG) && (thd->master_access & SUPER_ACL) && !log_for_root) || + (!(thd->master_access & SUPER_ACL) && log_for_root) || + thd->slave_thread) { VOID(pthread_mutex_unlock(&LOCK_log)); return 0; } - if ((specialflag & SPECIAL_LONG_LOG_FORMAT) || query_start_arg) + if ((specialflag & SPECIAL_LONG_LOG_FORMAT) || query_start_arg || log_for_root) { current_time=time(NULL); if (current_time != last_time) @@ -1556,7 +1724,7 @@ end=longlong10_to_str((longlong) thd->last_insert_id,end,-10); } } - if (thd->query_start_used) + if (thd->query_start_used && !log_for_root) { if (query_start_arg != thd->query_start()) { @@ -1616,14 +1784,10 @@ */ -void MYSQL_LOG:: wait_for_update(THD* thd, bool master_or_slave) +void MYSQL_LOG:: wait_for_update(THD* thd, const char *new_msg) { const char* old_msg = thd->enter_cond(&update_cond, &LOCK_log, - master_or_slave ? - "Has read all relay log; waiting for \ -the I/O slave thread to update it" : - "Has sent all binlog to slave; \ -waiting for binlog to be updated"); + new_msg); pthread_cond_wait(&update_cond, &LOCK_log); thd->exit_cond(old_msg); } @@ -1704,6 +1868,293 @@ 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: + 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; + } + 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); + + if (file_id < 0) { + *relay_file_error = true; + DBUG_RETURN(false); + } + + for (;;) { + Log_event* ev = Log_event::read_log_event(&log_file, NULL, (bool)0); + 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 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; + } + 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); + + 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); +} + +int MYSQL_LOG::flush_log_file() { + return flush_io_cache(&log_file); +} /* Check if a string is a valid number diff -ruN base/sql/log_event.cc mysql40gpl/sql/log_event.cc --- base/sql/log_event.cc 2005-09-02 15:37:56.000000000 -0700 +++ mysql40gpl/sql/log_event.cc 2007-04-21 09:57:11.000000000 -0700 @@ -26,6 +26,10 @@ #include +/* How many times binlog truncation error happens. */ +ulong binlog_trunc_errors = 0; + + #ifdef MYSQL_CLIENT static void pretty_print_str(FILE* file, char* str, int len) { @@ -468,6 +472,40 @@ #ifndef MYSQL_CLIENT +// Log the replication master IO partial read error: +// it is still a mysterious to us that my_read() can partially read the +// content we requested; if this really happens, then it is a serious +// replication bug; log it for future investigation +static void print_partial_read_error( + const char *errmsg, my_off_t pos_in_file, + int result, ulong data_len, int seek_not_done, + byte *read_pos, byte *read_end, + IO_CACHE* file, String* packet) { + char llbuff1[22], llbuff2[22]; + + sql_print_error("%s: error(%d) for reading %d bytes, " + "actually read %d bytes, result(%d), end_of_file(%s), " + "buffer(%x):", + errmsg, file->error, data_len, packet->length(), + result, llstr(file->end_of_file, llbuff1), file->buffer); + sql_print_error("\t old position(%s, %d, %x, %x, %d)", + llstr(pos_in_file, llbuff1), seek_not_done, + read_pos, read_end, read_end - read_pos); + sql_print_error("\t new position(%s, %d, %x, %x, %d, %s)", + llstr(file->pos_in_file, llbuff1), file->seek_not_done, + file->read_pos, file->read_end, + file->read_end - file->read_pos, + llstr(my_b_tell(file), llbuff2)); + + // print the file status through system calls + MY_STAT file_stat; + my_fstat(file->file, &file_stat, MYF(0)); + my_off_t file_pos = my_tell(file->file, MYF(0)); + sql_print_error("\t file status: size(%s), pos(%s)", + llstr(file_stat.st_size, llbuff1), + llstr(file_pos, llbuff2)); +} + int Log_event::read_log_event(IO_CACHE* file, String* packet, pthread_mutex_t* log_lock) { @@ -478,19 +516,37 @@ if (log_lock) pthread_mutex_lock(log_lock); - if (my_b_read(file, (byte*) buf, sizeof(buf))) + { - /* - If the read hits eof, we must report it as eof so the caller - will know it can go into cond_wait to be woken up on the next - update to the log. - */ - DBUG_PRINT("error",("file->error: %d", file->error)); - if (!file->error) - result= LOG_READ_EOF; - else - result= (file->error > 0 ? LOG_READ_TRUNC : LOG_READ_IO); - goto end; + // Record all possible information in case the mysterious + // LOG_READ_TRUNC might happen. + my_off_t pos_in_file; + int seek_not_done; + byte *read_pos, *read_end; + pos_in_file = file->pos_in_file; + seek_not_done = file->seek_not_done; + read_pos = file->read_pos; + read_end = file->read_end; + + if (my_b_read(file, (byte*) buf, sizeof(buf))) { + /* + If the read hits eof, we must report it as eof so the caller + will know it can go into cond_wait to be woken up on the next + update to the log. + */ + DBUG_PRINT("error",("file->error: %d", file->error)); + if (!file->error) { + result= LOG_READ_EOF; + } else { + result= (file->error > 0 ? LOG_READ_TRUNC : LOG_READ_IO); + + // log all information for the error + print_partial_read_error("read_log_event1", pos_in_file, result, + 0, seek_not_done, read_pos, read_end, + file, packet); + } + goto end; + } } data_len= uint4korr(buf + EVENT_LEN_OFFSET); if (data_len < LOG_EVENT_HEADER_LEN || @@ -505,6 +561,16 @@ data_len-= LOG_EVENT_HEADER_LEN; if (data_len) { + // Record all possible information in case the mysterious + // LOG_READ_TRUNC might happen. + my_off_t pos_in_file; + int seek_not_done; + byte *read_pos, *read_end; + pos_in_file = file->pos_in_file; + seek_not_done = file->seek_not_done; + read_pos = file->read_pos; + read_end = file->read_end; + if (packet->append(file, data_len)) { /* @@ -512,7 +578,21 @@ EOF means we are reading the event partially, which should never happen. */ - result= file->error >= 0 ? LOG_READ_TRUNC: LOG_READ_IO; + if (file->error == 0) + result = LOG_READ_MEM; + else if (file->error > 0) + result = LOG_READ_TRUNC; + else + result = LOG_READ_IO; + + if (result == LOG_READ_TRUNC) + binlog_trunc_errors++; + + // log all information for the error + print_partial_read_error("read_log_event2", pos_in_file, result, + data_len, seek_not_done, + read_pos, read_end, file, packet); + /* Implicit goto end; */ } } @@ -559,7 +639,11 @@ const char *error= 0; Log_event *res= 0; +#ifndef MYSQL_CLIENT + if (current_thd && data_len > max_allowed_packet) +#else if (data_len > max_allowed_packet) +#endif { error = "Event too big"; goto err; diff -ruN base/sql/log_event.h mysql40gpl/sql/log_event.h --- base/sql/log_event.h 2005-09-02 15:38:03.000000000 -0700 +++ mysql40gpl/sql/log_event.h 2007-04-21 09:57:11.000000000 -0700 @@ -54,6 +54,14 @@ #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 + struct old_sql_ex { char field_term; @@ -301,6 +309,9 @@ static Log_event* read_log_event(const char* buf, int event_len, const char **error, bool old_format); const char* get_type_str(); + inline void set_server_id(uint32 id) { + server_id = id; + } }; @@ -597,7 +608,6 @@ bool is_valid() { return 1; } }; - class Rotate_log_event: public Log_event { public: diff -ruN base/sql/Makefile.am mysql40gpl/sql/Makefile.am --- base/sql/Makefile.am 2005-09-02 15:37:59.000000000 -0700 +++ mysql40gpl/sql/Makefile.am 2007-04-21 11:01:31.000000000 -0700 @@ -56,7 +56,8 @@ sql_select.h structs.h table.h sql_udf.h hash_filo.h\ lex.h lex_symbol.h sql_acl.h sql_crypt.h \ log_event.h mini_client.h sql_repl.h slave.h \ - stacktrace.h sql_sort.h sql_cache.h set_var.h + stacktrace.h sql_sort.h sql_cache.h set_var.h \ + repl_mule.h repl_semi_sync.h hash_64.h mysqld_SOURCES = sql_lex.cc sql_handler.cc \ item.cc item_sum.cc item_buff.cc item_func.cc \ item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \ @@ -81,7 +82,8 @@ sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \ slave.cc sql_repl.cc sql_union.cc \ mini_client.cc mini_client_errors.c \ - stacktrace.c repl_failsafe.h repl_failsafe.cc + stacktrace.c repl_failsafe.h repl_failsafe.cc \ + repl_mule.cc repl_semi_sync.cc hash_64.cc gen_lex_hash_SOURCES = gen_lex_hash.cc gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS) diff -ruN base/sql/Makefile.in mysql40gpl/sql/Makefile.in --- base/sql/Makefile.in 2005-09-02 15:38:37.000000000 -0700 +++ mysql40gpl/sql/Makefile.in 2007-04-21 11:00:48.000000000 -0700 @@ -111,7 +111,8 @@ sql_analyse.$(OBJEXT) sql_cache.$(OBJEXT) slave.$(OBJEXT) \ sql_repl.$(OBJEXT) sql_union.$(OBJEXT) mini_client.$(OBJEXT) \ mini_client_errors.$(OBJEXT) stacktrace.$(OBJEXT) \ - repl_failsafe.$(OBJEXT) + repl_failsafe.$(OBJEXT) \ + repl_mule.$(OBJEXT) repl_semi_sync.$(OBJEXT) hash_64.$(OBJEXT) mysqld_OBJECTS = $(am_mysqld_OBJECTS) mysqld_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \ $(am__DEPENDENCIES_2) @@ -126,6 +127,7 @@ @AMDEP_TRUE@ ./$(DEPDIR)/ha_innodb.Po ./$(DEPDIR)/ha_isam.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/ha_isammrg.Po ./$(DEPDIR)/ha_myisam.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/ha_myisammrg.Po ./$(DEPDIR)/handler.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/hash_64.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/hash_filo.Po ./$(DEPDIR)/hostname.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/init.Po ./$(DEPDIR)/item.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/item_buff.Po \ @@ -146,6 +148,8 @@ @AMDEP_TRUE@ ./$(DEPDIR)/opt_sum.Po ./$(DEPDIR)/password.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/procedure.Po ./$(DEPDIR)/records.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/repl_failsafe.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/repl_mule.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/repl_semi_sync.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/set_var.Po ./$(DEPDIR)/slave.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/sql_acl.Po ./$(DEPDIR)/sql_analyse.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/sql_base.Po ./$(DEPDIR)/sql_cache.Po \ @@ -459,7 +463,8 @@ sql_select.h structs.h table.h sql_udf.h hash_filo.h\ lex.h lex_symbol.h sql_acl.h sql_crypt.h \ log_event.h mini_client.h sql_repl.h slave.h \ - stacktrace.h sql_sort.h sql_cache.h set_var.h + stacktrace.h sql_sort.h sql_cache.h set_var.h \ + repl_mule.h repl_semi_sync.h hash_64.h mysqld_SOURCES = sql_lex.cc sql_handler.cc \ item.cc item_sum.cc item_buff.cc item_func.cc \ @@ -485,7 +490,8 @@ sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \ slave.cc sql_repl.cc sql_union.cc \ mini_client.cc mini_client_errors.c \ - stacktrace.c repl_failsafe.h repl_failsafe.cc + stacktrace.c repl_failsafe.h repl_failsafe.cc \ + repl_mule.cc repl_semi_sync.cc hash_64.cc gen_lex_hash_SOURCES = gen_lex_hash.cc gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS) @@ -590,6 +596,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ha_myisam.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ha_myisammrg.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/handler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash_64.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash_filo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hostname.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/init.Po@am__quote@ @@ -620,6 +627,8 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/procedure.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/records.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repl_failsafe.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repl_mule.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repl_semi_sync.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/set_var.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/slave.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sql_acl.Po@am__quote@ diff -ruN base/sql/mysqld.cc mysql40gpl/sql/mysqld.cc --- base/sql/mysqld.cc 2005-09-02 15:37:56.000000000 -0700 +++ mysql40gpl/sql/mysqld.cc 2007-04-21 11:21:13.000000000 -0700 @@ -34,6 +34,8 @@ #include #include #include +#include +#include "repl_semi_sync.h" #ifndef DBUG_OFF #define ONE_THREAD @@ -144,6 +146,7 @@ void getvolumeID(BYTE *volumeName); #endif /* __NETWARE__ */ +ReplSemiSync semi_sync_replicator; #ifdef _AIX41 int initgroups(const char *,unsigned int); @@ -283,7 +286,8 @@ ulong back_log, connect_timeout, concurrency; char mysql_home[FN_REFLEN], pidfile_name[FN_REFLEN], time_zone[30]; char log_error_file[FN_REFLEN]; -bool opt_log, opt_update_log, opt_bin_log, opt_slow_log; +bool opt_log, opt_audit_log, opt_update_log, opt_bin_log; +bool opt_slow_log, opt_dml_log; bool opt_error_log= IF_WIN(1,0); bool opt_disable_networking=0, opt_skip_show_db=0; bool lower_case_table_names_used= 0; @@ -299,7 +303,22 @@ static ulong opt_myisam_block_size; static my_socket unix_sock= INVALID_SOCKET,ip_sock= INVALID_SOCKET; static my_string opt_logname=0,opt_update_logname=0, - opt_binlog_index_name = 0,opt_slow_logname=0; + opt_slow_logname=0, opt_dml_logname=0; +/* + * If --log_queries_on_tables=xxxxx,yyyy we log the query to the log if table + * xxxxx or yyy is one of the tables opened. + */ +my_string opt_log_queries_on_tables=0; +/* We break out the tables into a hash */ +HASH log_tables; +static my_string opt_audit_logname=0; + +my_string opt_binlog_index_name = 0; + +/* If the variable is set, we are inside a failover slave and will deny all + * non-super user access. + */ +bool failover_deny_access = 0; static char* mysql_home_ptr= mysql_home; static char* pidfile_name_ptr= pidfile_name; @@ -310,6 +329,47 @@ my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0; my_bool opt_log_slave_updates= 0, opt_console= 0, opt_allow_suspicious_udfs; my_bool opt_readonly = 0, opt_sync_bdb_logs, opt_sync_frm; +my_bool rpl_transaction_enabled, rpl_always_enter_innodb, rpl_mirror_binlog_enabled; +my_bool rpl_long_filename, rpl_mirror_binlog_no_replicate; + +/* The fixed size for replication event buffer. Replication event can exceed + * the size. + */ +ulong rpl_event_buffer_size; + +/* This is a mirror binlog status variable on the primary to indicate how many + * mirror binlog servers are connecting. + */ +ulong rpl_mirror_binlog_clients = 0; + +/* This indicates whether mirror binlog is working on a replica database. It + * requires: + * . rpl_mirror_binlog_enabled = 1 + * . the slave I/O thread is running and mirror binlog is also dumped + */ +ulong rpl_mirror_binlog_status = 0; + +/* This indicates whether semi-synchronous replication is enabled. */ +ulong rpl_semi_sync_enabled; +ulong rpl_semi_sync_slave_enabled; +ulong rpl_semi_sync_timeout; +ulong rpl_semi_sync_trace_level; +ulong rpl_semi_sync_status = 0; +ulong rpl_semi_sync_slave_status = 0; +ulong rpl_semi_sync_yes_transactions = 0; +ulong rpl_semi_sync_no_transactions = 0; +ulong rpl_semi_sync_off_times = 0; +ulong rpl_semi_sync_timefunc_fails = 0; +ulong rpl_semi_sync_num_timeouts = 0; +ulong rpl_semi_sync_wait_sessions = 0; +ulong rpl_semi_sync_back_wait_pos = 0; +ulong rpl_semi_sync_trx_wait_time = 0; +ulonglong rpl_semi_sync_trx_wait_num = 0; +ulong rpl_semi_sync_net_wait_time = 0; +ulonglong rpl_semi_sync_net_wait_num = 0; +ulong rpl_semi_sync_clients = 0; +ulonglong rpl_semi_sync_net_wait_total_time = 0; +ulonglong rpl_semi_sync_trx_wait_total_time = 0; volatile bool mqh_used = 0; FILE *bootstrap_file=0; @@ -361,6 +421,7 @@ ulong com_stat[(uint) SQLCOM_END], com_other; ulong slave_net_timeout; ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0; +ulong long_query_time=0; ulong query_cache_size=0; #ifdef HAVE_QUERY_CACHE ulong query_cache_limit=0; @@ -394,6 +455,7 @@ aborted_connects,delayed_insert_timeout,delayed_insert_limit, delayed_queue_size,delayed_insert_threads,delayed_insert_writes, delayed_rows_in_use,delayed_insert_errors,flush_time, thread_created; +ulong denied_connections; ulong filesort_rows, filesort_range_count, filesort_scan_count; ulong filesort_merge_passes; ulong select_range_check_count, select_range_count, select_scan_count; @@ -402,9 +464,13 @@ created_tmp_disk_tables=0; ulong max_connections, max_used_connections, max_connect_errors, max_user_connections = 0; +ulong reserved_super_connections = 0; ulong thread_id=1L,current_pid; ulong slow_launch_threads = 0; - +ulong sync_binlog_period, sync_binlog_counter = 0; +ulong sync_mirror_binlog_period; +ulong gettimeofday_errors = 0; + char mysql_real_data_home[FN_REFLEN], language[LIBLEN],reg_ext[FN_EXTLEN], mysql_charsets_dir[FN_REFLEN], *charsets_list, @@ -458,7 +524,9 @@ LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received, LOCK_global_system_variables, - LOCK_user_conn, LOCK_slave_list, LOCK_active_mi; + LOCK_user_conn, LOCK_slave_list, LOCK_active_mi, + LOCK_stats, LOCK_failover_master, LOCK_global_user_stats, + LOCK_global_table_stats, LOCK_global_index_stats; pthread_cond_t COND_refresh,COND_thread_count, COND_slave_stopped, COND_slave_start; @@ -901,6 +969,7 @@ mysql_slow_log.cleanup(); mysql_update_log.cleanup(); mysql_bin_log.cleanup(); + mysql_audit_log.cleanup(); if (use_slave_mask) bitmap_free(&slave_error_mask); @@ -931,6 +1000,9 @@ x_free(opt_relay_logname); bitmap_free(&temp_pool); free_max_user_conn(); + free_global_user_stats(); + free_global_table_stats(); + free_global_index_stats(); end_slave_list(); free_list(&replicate_do_db); free_list(&replicate_ignore_db); @@ -991,6 +1063,11 @@ (void) pthread_mutex_destroy(&LOCK_rpl_status); (void) pthread_mutex_destroy(&LOCK_active_mi); (void) pthread_mutex_destroy(&LOCK_global_system_variables); + (void) pthread_mutex_destroy(&LOCK_stats); + (void) pthread_mutex_destroy(&LOCK_failover_master); + (void) pthread_mutex_destroy(&LOCK_global_user_stats); + (void) pthread_mutex_destroy(&LOCK_global_table_stats); + (void) pthread_mutex_destroy(&LOCK_global_index_stats); (void) pthread_cond_destroy(&COND_thread_count); (void) pthread_cond_destroy(&COND_refresh); (void) pthread_cond_destroy(&COND_thread_cache); @@ -2223,6 +2300,12 @@ { DEBUGGER_OFF; + // Enable malloc tracing if MALLOC_TRACE is set in the environment. + // mtrace() also uses this variable as the output file for its + // tracing. + if (getenv("MALLOC_TRACE")) + mtrace(); + my_umask=0660; // Default umask for new files my_umask_dir=0700; // Default umask for new directories MAIN_THD; @@ -2261,6 +2344,7 @@ before MY_INIT(). So we do it here. */ mysql_log.init_pthread_objects(); + mysql_audit_log.init_pthread_objects(); mysql_update_log.init_pthread_objects(); mysql_slow_log.init_pthread_objects(); mysql_bin_log.init_pthread_objects(); @@ -2302,6 +2386,10 @@ DBUG_PRINT("info",("%s Ver %s for %s on %s\n",my_progname, server_version, SYSTEM_TYPE,MACHINE_TYPE)); + /* Must be called after set_options() and MY_INIT(). */ + if (semi_sync_replicator.initObject() != 0) + unireg_abort(1); + /* These must be set early */ (void) pthread_mutex_init(&LOCK_mysql_create_db,MY_MUTEX_INIT_SLOW); @@ -2322,6 +2410,11 @@ (void) pthread_mutex_init(&LOCK_rpl_status, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_global_system_variables, MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_stats, MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_failover_master, MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_global_user_stats, MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_global_table_stats, MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_global_index_stats, MY_MUTEX_INIT_FAST); (void) pthread_cond_init(&COND_thread_count,NULL); (void) pthread_cond_init(&COND_refresh,NULL); (void) pthread_cond_init(&COND_thread_cache,NULL); @@ -2475,11 +2568,17 @@ if (opt_log) open_log(&mysql_log, glob_hostname, opt_logname, ".log", NullS, LOG_NORMAL, 0, 0, 0); - if (opt_update_log) - { - open_log(&mysql_update_log, glob_hostname, opt_update_logname, "", + if (opt_audit_log) { + open_log(&mysql_audit_log, glob_hostname, opt_audit_logname, + "-audit.log", NullS, LOG_NORMAL, 0, 0, 0); + } + if (opt_dml_log) + { + // When using_update_log is set, rows read as part of an + // insert/update/delete might get locked in share mode. + open_log(&mysql_update_log, glob_hostname, opt_dml_logname, "", NullS, LOG_NEW, 0, 0, 0); - using_update_log=1; + mysql_update_log.set_log_for_root(TRUE); } if (opt_slow_log) @@ -2501,6 +2600,10 @@ freopen(log_error_file, "a+", stderr); } } + + init_global_table_stats(); + init_global_index_stats(); + if (ha_init()) { sql_print_error("Can't init databases"); @@ -2569,10 +2672,12 @@ unlink(mysql_unix_port); unireg_abort(1); } + if (!opt_noacl) (void) grant_init((THD*) 0); init_max_user_conn(); init_update_queries(); + init_global_user_stats(); DBUG_ASSERT(current_thd == 0); #ifdef HAVE_DLOPEN @@ -2604,11 +2709,15 @@ break; } } + if (server_id == MASTER_INFO_SERVER_ID) { + sql_print_error("[mysqld] variable server-id can not be %d", + MASTER_INFO_SERVER_ID); + unireg_abort(1); + } + if (opt_bin_log) { - open_log(&mysql_bin_log, glob_hostname, opt_bin_logname, "-bin", - opt_binlog_index_name, LOG_BIN, 0, 0, max_binlog_size); - using_update_log=1; + make_master(NULL, opt_bin_logname, opt_binlog_index_name, NULL); } else if (opt_log_slave_updates) { @@ -3025,6 +3134,7 @@ { DBUG_PRINT("error",("Too many connections")); close_connection(net,ER_CON_COUNT_ERROR); + statistic_increment(denied_connections, &LOCK_status); delete thd; DBUG_VOID_RETURN; } @@ -3471,6 +3581,8 @@ OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT, OPT_INNODB_FLUSH_METHOD, OPT_INNODB_FAST_SHUTDOWN, + OPT_INNODB_NO_SHARE_LOCKS_ON_DML_SELECT, + OPT_INNODB_MAX_MERGED_IO, OPT_SAFE_SHOW_DB, OPT_INNODB_SKIP, OPT_SKIP_SAFEMALLOC, OPT_TEMP_POOL, OPT_TX_ISOLATION, @@ -3524,6 +3636,8 @@ OPT_INNODB_ADDITIONAL_MEM_POOL_SIZE, OPT_INNODB_MAX_PURGE_LAG, OPT_INNODB_FILE_IO_THREADS, + OPT_INNODB_READ_IO_THREADS, + OPT_INNODB_WRITE_IO_THREADS, OPT_INNODB_LOCK_WAIT_TIMEOUT, OPT_INNODB_THREAD_CONCURRENCY, OPT_INNODB_FORCE_RECOVERY, @@ -3531,6 +3645,7 @@ OPT_INNODB_MAX_DIRTY_PAGES_PCT, OPT_INNODB_AUTOEXTEND_INCREMENT, OPT_INNODB_TABLE_LOCKS, + OPT_INNODB_BTR_ESTIMATE_N_PAGES, OPT_BDB_CACHE_SIZE, OPT_BDB_LOG_BUFFER_SIZE, OPT_BDB_MAX_LOCK, @@ -3539,10 +3654,15 @@ OPT_RANGE_ALLOC_BLOCK_SIZE, OPT_ALLOW_SUSPICIOUS_UDFS, OPT_QUERY_ALLOC_BLOCK_SIZE, OPT_QUERY_PREALLOC_SIZE, OPT_TRANS_ALLOC_BLOCK_SIZE, OPT_TRANS_PREALLOC_SIZE, - OPT_SYNC_FRM, OPT_BDB_NOSYNC + OPT_SYNC_FRM, OPT_BDB_NOSYNC, OPT_RPL_TRANX_ENABLED, OPT_RPL_ENTER_INNODB, + OPT_SYNC_BINLOG, OPT_SYNC_MIRROR_BINLOG, OPT_RESERVED_SUPER_CONNECTIONS, + OPT_INNODB_CLEAR_REPLICATION_STATUS, OPT_RPL_MIRROR_BINLOG, + OPT_RPL_SEMI_SYNC, OPT_RPL_SEMI_SYNC_SLAVE, + OPT_RPL_SEMI_SYNC_TIMEOUT, OPT_RPL_SEMI_SYNC_TRACE, + OPT_RPL_LONG_FILENAME, OPT_RPL_MIRROR_BINLOG_NO_REPLICATE, + OPT_LOG_QUERIES_ON_TABLES, OPT_AUDIT_LOG, OPT_RPL_EVENT_BUFFER_SIZE }; - #define LONG_TIMEOUT ((ulong) 3600L*24L*365L) struct my_option my_long_options[] = @@ -3683,6 +3803,17 @@ (gptr*) &srv_auto_extend_increment, (gptr*) &srv_auto_extend_increment, 0, GET_LONG, REQUIRED_ARG, 8L, 1L, 1000L, 0, 1L, 0}, + {"innodb_btr_estimate_n_pages", OPT_INNODB_BTR_ESTIMATE_N_PAGES, + "Number of index leaf pages to sample to estimate different key values", + (gptr*) &btr_key_val_estimate_n_pages, + (gptr*) &btr_key_val_estimate_n_pages, + 0, GET_ULONG, REQUIRED_ARG, 8, 1, 2048, 0, 1, 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}, {"innodb_data_home_dir", OPT_INNODB_DATA_HOME_DIR, "The common part for Innodb table spaces", (gptr*) &innobase_data_home_dir, (gptr*) &innobase_data_home_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, @@ -3726,14 +3857,32 @@ (gptr*) &global_system_variables.innodb_table_locks, (gptr*) &global_system_variables.innodb_table_locks, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, + {"innodb_no_share_locks_on_dml_select", OPT_INNODB_NO_SHARE_LOCKS_ON_DML_SELECT, + "Force InnoDB not to lock selected rows in share mode during DML when binary logging is off.", + (gptr*) &innodb_no_share_locks_on_dml_select, + (gptr*) &innodb_no_share_locks_on_dml_select, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"innodb_max_merged_io", OPT_INNODB_MAX_MERGED_IO, + "Max number of IO requests merged to issue large IO from background IO threads.", + (gptr*) &innobase_max_merged_io, + (gptr*) &innobase_max_merged_io, 0, GET_LONG, REQUIRED_ARG, 64, 1, 64, 0, 0, 0}, #endif /* End HAVE_INNOBASE_DB */ - {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, + + {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"init-file", OPT_INIT_FILE, "Read SQL commands from this file at startup", (gptr*) &opt_init_file, (gptr*) &opt_init_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"log", 'l', "Log connections and queries to file", (gptr*) &opt_logname, (gptr*) &opt_logname, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"audit_log", OPT_AUDIT_LOG, + "Log logins, queries against specified tables, and startup", + (gptr*) &opt_audit_logname, + (gptr*) &opt_audit_logname, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"log_tables", OPT_LOG_QUERIES_ON_TABLES, + "Log queries that use these table to the audit log (comma seperated)", + (gptr*) &opt_log_queries_on_tables, + (gptr*) &opt_log_queries_on_tables, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, {"language", 'L', "Client error messages in given language. May be given as a full path", (gptr*) &language_ptr, (gptr*) &language_ptr, 0, GET_STR, REQUIRED_ARG, @@ -3755,8 +3904,8 @@ (gptr*) &myisam_log_filename, (gptr*) &myisam_log_filename, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"log-update", OPT_UPDATE_LOG, - "Log updates to file.# where # is a unique number if not given.", - (gptr*) &opt_update_logname, (gptr*) &opt_update_logname, 0, GET_STR, + "Log updates for root to file.# where # is a unique number if not given.", + (gptr*) &opt_dml_logname, (gptr*) &opt_dml_logname, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"log-slow-queries", OPT_SLOW_QUERY_LOG, "Log slow queries to this log file. Defaults logging to hostname-slow.log", @@ -3920,9 +4069,66 @@ "Port for connecting to slave reported to the master during slave registration. Set it only if the slave is listening on a non-default port or if you have a special tunnel from the master or other clients to the slave. If not sure, leave this option unset.", (gptr*) &report_port, (gptr*) &report_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0}, + {"rpl_always_enter_innodb", OPT_RPL_ENTER_INNODB, + "1 = sql thread always enter innodb. 0 = sql thread still wait for ticket limit", + (gptr*) &rpl_always_enter_innodb, + (gptr*) &rpl_always_enter_innodb, 0, GET_BOOL, NO_ARG, + 0, 0, 1, 0, 1, 0}, + {"rpl_long_filename", OPT_RPL_LONG_FILENAME, + "1 = use 6 digit filename, like mysql5. 0 = use 3 digit filename", + (gptr*) &rpl_long_filename, + (gptr*) &rpl_long_filename, 0, GET_BOOL, NO_ARG, + 0, 0, 1, 0, 1, 0}, + {"rpl_event_buffer_size", OPT_RPL_EVENT_BUFFER_SIZE, + "The fixed event buffer during replication: actual event can exceed it; " + " avoids need to malloc/free memory for events smaller than this", + (gptr*) &rpl_event_buffer_size, + (gptr*) &rpl_event_buffer_size, + 0, GET_ULONG, REQUIRED_ARG, + 1024*1024, /* the default size */ + 16*1024, /* the minimum size */ + 8*1024*1024, /* the maximum size */ 0, 1, 0}, {"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_mirror_binlog_enabled", OPT_RPL_MIRROR_BINLOG, + "1 = support mirroring binlogs. 0 = disable mirroring binlogs", + (gptr*) &rpl_mirror_binlog_enabled, + (gptr*) &rpl_mirror_binlog_enabled, 0, GET_BOOL, NO_ARG, + 0, 0, 1, 0, 1, 0}, + {"rpl_mirror_binlog_no_replicate", OPT_RPL_MIRROR_BINLOG_NO_REPLICATE, + "1 = Do not replicate from this mirror binlog server. 0 = Ok to replicate.", + (gptr*) &rpl_mirror_binlog_no_replicate, + (gptr*) &rpl_mirror_binlog_no_replicate, 0, GET_BOOL, NO_ARG, + 0, 0, 1, 0, 1, 0}, + {"rpl_semi_sync_enabled", OPT_RPL_SEMI_SYNC, + "1 = Enable semi-synchronous replication. 0 = Disable it", + (gptr*) &rpl_semi_sync_enabled, + (gptr*) &rpl_semi_sync_enabled, 0, GET_ULONG, REQUIRED_ARG, + 0, 0, 1, 0, 1, 0}, + {"rpl_semi_sync_slave_enabled", OPT_RPL_SEMI_SYNC_SLAVE, + "1 = Enable semi-synchronous in the slave database. The slave will be " + "the semi-sync replication target", + (gptr*) &rpl_semi_sync_slave_enabled, + (gptr*) &rpl_semi_sync_slave_enabled, 0, GET_ULONG, REQUIRED_ARG, + 0, 0, 1, 0, 1, 0}, + {"rpl_semi_sync_timeout", OPT_RPL_SEMI_SYNC_TIMEOUT, + "The timeout value (in ms) for semi-synchronous replication in the master", + (gptr*) &rpl_semi_sync_timeout, + (gptr*) &rpl_semi_sync_timeout, + 0, GET_ULONG, REQUIRED_ARG, 10, 0, ~0L, 0, 1, 0}, + {"rpl_semi_sync_trace_level", OPT_RPL_SEMI_SYNC_TRACE, + "The tracing level for semi-sync replication.", + (gptr*) &rpl_semi_sync_trace_level, + (gptr*) &rpl_semi_sync_trace_level, + 0, GET_ULONG, REQUIRED_ARG, + 32, /* By default, we trace the network waiting time. */ + 0, ~0L, 0, 1, 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}, {"relay-log", OPT_RELAY_LOG, "The location and name to use for relay logs", (gptr*) &opt_relay_logname, (gptr*) &opt_relay_logname, 0, @@ -4015,6 +4221,16 @@ "Syntax: sql-mode=option[,option[,option...]] where option can be one of: REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, SERIALIZE, ONLY_FULL_GROUP_BY, NO_UNSIGNED_SUBTRACTION.", (gptr*) &sql_mode_str, (gptr*) &sql_mode_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"sync-binlog", OPT_SYNC_BINLOG, + "Sync the binlog to disk after every #th event. \ +#=0 (the default) does no sync. Syncing slows MySQL down", + (gptr*) &sync_binlog_period, + (gptr*) &sync_binlog_period, 0, GET_ULONG, REQUIRED_ARG, 0, 0, ~0L, 0, 1, 0}, + {"sync-mirror-binlog", OPT_SYNC_MIRROR_BINLOG, + "Sync the mirrored binlog to disk after every #th event. " + "#=0 (the default) does no sync. Syncing slows MySQL down", + (gptr*) &sync_mirror_binlog_period, + (gptr*) &sync_mirror_binlog_period, 0, GET_ULONG, REQUIRED_ARG, 0, 0, ~0L, 0, 1, 0}, #ifdef HAVE_OPENSSL #include "sslopt-longopts.h" #endif @@ -4143,6 +4359,14 @@ "Number of file I/O threads in InnoDB.", (gptr*) &innobase_file_io_threads, (gptr*) &innobase_file_io_threads, 0, GET_LONG, REQUIRED_ARG, 4, 4, 64, 0, 1, 0}, + {"innodb_read_io_threads", OPT_INNODB_READ_IO_THREADS, + "Number of background read I/O threads in InnoDB.", (gptr*) &innobase_read_io_threads, + (gptr*) &innobase_read_io_threads, 0, GET_LONG, REQUIRED_ARG, 1, 1, 64, 0, + 1, 0}, + {"innodb_write_io_threads", OPT_INNODB_WRITE_IO_THREADS, + "Number of background write I/O threads in InnoDB.", (gptr*) &innobase_write_io_threads, + (gptr*) &innobase_write_io_threads, 0, GET_LONG, REQUIRED_ARG, 1, 1, 64, 0, + 1, 0}, {"innodb_lock_wait_timeout", OPT_INNODB_LOCK_WAIT_TIMEOUT, "Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back.", (gptr*) &innobase_lock_wait_timeout, (gptr*) &innobase_lock_wait_timeout, @@ -4173,10 +4397,10 @@ REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, UINT_MAX32, MALLOC_OVERHEAD, IO_SIZE, 0}, {"long_query_time", OPT_LONG_QUERY_TIME, - "Log all queries that have taken more than long_query_time seconds to execute to file.", - (gptr*) &global_system_variables.long_query_time, - (gptr*) &max_system_variables.long_query_time, 0, GET_ULONG, - REQUIRED_ARG, 10, 1, LONG_TIMEOUT, 0, 1, 0}, + "Log all queries that have taken at least long_query_time seconds to execute to file.", + (gptr*) &long_query_time, + (gptr*) &long_query_time, 0, GET_ULONG, + REQUIRED_ARG, 10, 0, LONG_TIMEOUT, 0, 1, 0}, {"lower_case_table_names", OPT_LOWER_CASE_TABLE_NAMES, "If set to 1 table names are stored in lowercase on disk and table names will be case-insensitive. Should be set to 2 if you are using a case insensitive file system", (gptr*) &lower_case_table_names, @@ -4364,6 +4588,10 @@ (gptr*) &relay_log_space_limit, (gptr*) &relay_log_space_limit, 0, GET_ULL, REQUIRED_ARG, 0L, 0L, (longlong) ULONG_MAX, 0, 1, 0}, + {"reserved_super_connections", OPT_RESERVED_SUPER_CONNECTIONS, + "The number of reserved connections for users with SUPER privileges.", + (gptr*) &reserved_super_connections, (gptr*) &reserved_super_connections, + 0, GET_ULONG, REQUIRED_ARG, 10, 1, 50, 0, 1, 0}, {"slave_compressed_protocol", OPT_SLAVE_COMPRESSED_PROTOCOL, "Use compression on master/slave protocol", (gptr*) &opt_slave_compressed_protocol, @@ -4442,6 +4670,9 @@ struct show_var_st status_vars[]= { {"Aborted_clients", (char*) &aborted_threads, SHOW_LONG}, {"Aborted_connects", (char*) &aborted_connects, SHOW_LONG}, + {"Binlog_events", (char*) &binlog_events, SHOW_LONGLONG}, + {"Binlog_largest_event", (char*) &binlog_largest_event, SHOW_LONG}, + {"Binlog_trunc_errors", (char*) &binlog_trunc_errors , SHOW_LONG}, {"Bytes_received", (char*) &bytes_received, SHOW_LONG}, {"Bytes_sent", (char*) &bytes_sent, SHOW_LONG}, {"Com_admin_commands", (char*) &com_other, SHOW_LONG}, @@ -4519,7 +4750,10 @@ {"Delayed_errors", (char*) &delayed_insert_errors, SHOW_LONG}, {"Delayed_insert_threads", (char*) &delayed_insert_threads, SHOW_LONG_CONST}, {"Delayed_writes", (char*) &delayed_insert_writes, SHOW_LONG}, + {"Denied_connections", (char*) &denied_connections, SHOW_LONG}, + {"Failover_deny_access", (char*) &failover_deny_access, SHOW_LONG}, {"Flush_commands", (char*) &refresh_version, SHOW_LONG_CONST}, + {"Gettimeofday_errors", (char*) &gettimeofday_errors, SHOW_LONG}, {"Handler_commit", (char*) &ha_commit_count, SHOW_LONG}, {"Handler_delete", (char*) &ha_delete_count, SHOW_LONG}, {"Handler_read_first", (char*) &ha_read_first_count, SHOW_LONG}, @@ -4536,6 +4770,12 @@ {"Key_reads", (char*) &_my_cache_read, SHOW_LONG}, {"Key_write_requests", (char*) &_my_cache_w_requests, SHOW_LONG}, {"Key_writes", (char*) &_my_cache_write, SHOW_LONG}, + {"Malloc_sbrk_bytes_alloc", (char*) &malloc_sbrk_bytes_alloc, SHOW_LONGLONG}, + {"Malloc_chunks_free", (char*) &malloc_chunks_free, SHOW_LONG}, + {"Malloc_mmap_chunks_alloc", (char*) &malloc_mmap_chunks_alloc, SHOW_LONG}, + {"Malloc_mmap_bytes_alloc", (char*) &malloc_mmap_bytes_alloc, SHOW_LONGLONG}, + {"Malloc_bytes_used", (char*) &malloc_bytes_used, SHOW_LONGLONG}, + {"Malloc_bytes_free", (char*) &malloc_bytes_free, SHOW_LONGLONG}, {"Max_used_connections", (char*) &max_used_connections, SHOW_LONG}, {"Not_flushed_delayed_rows", (char*) &delayed_rows_in_use, SHOW_LONG_CONST}, {"Not_flushed_key_blocks", (char*) &_my_blocks_changed, SHOW_LONG_CONST}, @@ -4557,6 +4797,38 @@ SHOW_LONG_CONST}, #endif /*HAVE_QUERY_CACHE*/ {"Questions", (char*) 0, SHOW_QUESTION}, + {"Replication_fail_io_connections", (char*) &rpl_fail_io_connections, SHOW_LONG}, + {"Replication_last_event_buffered", (char*) &rpl_last_event_buffered, SHOW_LONG}, + {"Replication_last_event_diff", (char*) &rpl_last_event_diff, SHOW_LONG}, + {"Replication_last_event_done", (char*) &rpl_last_event_done, SHOW_LONG}, + {"Replication_max_delay", (char*) &rpl_max_delay, SHOW_LONG}, + {"Replication_slowest_event", (char*) &rpl_slowest_event, SHOW_LONG}, + {"Replication_slowest_event", (char*) &rpl_slowest_event, SHOW_LONG}, + {"Rpl_mirror_binlog_clients",(char*) &rpl_mirror_binlog_clients, SHOW_LONG}, + {"Rpl_mirror_binlog_status", (char*) &rpl_mirror_binlog_status, SHOW_LONG}, + {"Rpl_semi_sync_clients", (char*) &rpl_semi_sync_clients, SHOW_LONG}, + {"Rpl_semi_sync_net_avg_wait_time(us)", + (char*) &rpl_semi_sync_net_wait_time, SHOW_LONG}, + {"Rpl_semi_sync_net_wait_time", + (char*) &rpl_semi_sync_net_wait_total_time, SHOW_LONGLONG}, + {"Rpl_semi_sync_net_waits", (char*) &rpl_semi_sync_net_wait_num, SHOW_LONGLONG}, + {"Rpl_semi_sync_no_times", (char*) &rpl_semi_sync_off_times, SHOW_LONG}, + {"Rpl_semi_sync_no_tx", (char*) &rpl_semi_sync_no_transactions, SHOW_LONG}, + {"Rpl_semi_sync_status", (char*) &rpl_semi_sync_status, SHOW_LONG}, + {"Rpl_semi_sync_slave_status", (char*) &rpl_semi_sync_slave_status, SHOW_LONG}, + {"Rpl_semi_sync_timefunc_failures", + (char*) &rpl_semi_sync_timefunc_fails, SHOW_LONG}, + {"Rpl_semi_sync_tx_avg_wait_time(us)", + (char*) &rpl_semi_sync_trx_wait_time, SHOW_LONG}, + {"Rpl_semi_sync_tx_wait_time", + (char*) &rpl_semi_sync_trx_wait_total_time, SHOW_LONGLONG}, + {"Rpl_semi_sync_tx_waits", (char*) &rpl_semi_sync_trx_wait_num, SHOW_LONGLONG}, + {"Rpl_semi_sync_wait_pos_backtraverse", + (char*) &rpl_semi_sync_back_wait_pos, SHOW_LONG}, + {"Rpl_semi_sync_wait_sessions", + (char*) &rpl_semi_sync_wait_sessions, SHOW_LONG}, + {"Rpl_semi_sync_yes_tx", (char*) &rpl_semi_sync_yes_transactions, SHOW_LONG}, + {"Rpl_transaction_support", (char*) &rpl_transaction_enabled, SHOW_LONG}, {"Rpl_status", (char*) 0, SHOW_RPL_STATUS}, {"Select_full_join", (char*) &select_full_join_count, SHOW_LONG}, {"Select_full_range_join", (char*) &select_full_range_join_count, SHOW_LONG}, @@ -4603,6 +4875,9 @@ {"Threads_created", (char*) &thread_created, SHOW_LONG_CONST}, {"Threads_running", (char*) &thread_running, SHOW_INT_CONST}, {"Uptime", (char*) 0, SHOW_STARTTIME}, + {"Vm_size", (char*) &vm_size, SHOW_LONGLONG}, + {"Vm_data", (char*) &vm_data, SHOW_LONGLONG}, + {"Vm_rss", (char*) &vm_rss, SHOW_LONGLONG}, {NullS, NullS, SHOW_LONG} }; @@ -4781,7 +5056,7 @@ opt_myisam_log=1; break; case (int) OPT_UPDATE_LOG: - opt_update_log=1; + opt_dml_log=1; break; case (int) OPT_BIN_LOG: opt_bin_log=1; @@ -5183,6 +5458,12 @@ lower_case_table_names= argument ? atoi(argument) : 1; lower_case_table_names_used= 1; break; + case OPT_LOG_QUERIES_ON_TABLES: + init_log_tables(argument); + break; + case (int) OPT_AUDIT_LOG: + opt_audit_log = 1; + break; } return 0; } @@ -5264,7 +5545,7 @@ if (!strstr(MYSQL_SERVER_SUFFIX_STR, "-debug")) end= strmov(end, "-debug"); #endif - if (opt_log || opt_update_log || opt_slow_log || opt_bin_log) + if (opt_log || opt_update_log || opt_slow_log || opt_bin_log || opt_dml_log) strmov(end, "-log"); // This may slow down system } diff -ruN base/sql/mysql_priv.h mysql40gpl/sql/mysql_priv.h --- base/sql/mysql_priv.h 2005-09-02 15:38:00.000000000 -0700 +++ mysql40gpl/sql/mysql_priv.h 2007-04-21 12:39:25.000000000 -0700 @@ -234,7 +234,9 @@ /* BINLOG_DUMP options */ -#define BINLOG_DUMP_NON_BLOCK 1 +#define BINLOG_DUMP_NON_BLOCK 0x0001 +#define BINLOG_SEMI_SYNC 0x0002 +#define BINLOG_MIRROR_CLIENT 0x0004 /* sql_show.cc:show_log_files() */ #define SHOW_LOG_STATUS_FREE "FREE" @@ -360,7 +362,14 @@ void mysql_init_multi_delete(LEX *lex); void init_max_user_conn(void); void init_update_queries(void); +void init_global_user_stats(void); +void init_global_table_stats(void); +void init_global_index_stats(void); +void init_log_tables(my_string string); void free_max_user_conn(void); +void free_global_user_stats(void); +void free_global_table_stats(void); +void free_global_index_stats(void); extern "C" pthread_handler_decl(handle_one_connection,arg); extern "C" pthread_handler_decl(handle_bootstrap,arg); void end_thread(THD *thd,bool put_in_cache); @@ -539,6 +548,9 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, enum enum_var_type value_type, pthread_mutex_t *mutex); +int mysqld_show_user_stats(THD *thd, const char *wild); +int mysqld_show_table_stats(THD *thd, const char *wild); +int mysqld_show_index_stats(THD *thd, const char *wild); int mysql_find_files(THD *thd,List *files, const char *db, const char *path, const char *wild, bool dir); @@ -681,6 +693,7 @@ extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH], max_sort_char, mysql_real_data_home[], *charsets_list; extern my_string mysql_tmpdir; +extern my_string opt_binlog_index_name; extern const char *command_name[]; extern const char *first_keyword, *localhost, *delayed_user; extern const char **errmesg; /* Error messages */ @@ -699,6 +712,7 @@ extern ulong delayed_insert_limit, delayed_queue_size; extern ulong delayed_insert_threads, delayed_insert_writes; extern ulong delayed_rows_in_use,delayed_insert_errors; +extern ulong denied_connections; extern ulong filesort_rows, filesort_range_count, filesort_scan_count; extern ulong filesort_merge_passes; extern ulong select_range_check_count, select_range_count, select_scan_count; @@ -713,21 +727,43 @@ extern ulong ha_commit_count, ha_rollback_count,table_cache_size; extern ulong max_connections,max_connect_errors, connect_timeout; extern ulong max_user_connections; +extern ulong reserved_super_connections; extern ulong long_query_count, what_to_log,flush_time,opt_sql_mode; extern ulong query_buff_size, thread_stack,thread_stack_min; extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit; extern ulong max_binlog_size, max_relay_log_size; -extern ulong rpl_recovery_rank, thread_cache_size; +extern ulong rpl_recovery_rank, thread_cache_size, long_query_time; extern ulong com_stat[(uint) SQLCOM_END], com_other, back_log; extern ulong specialflag, current_pid; +// The following export malloc stats from struct mallinfo and mallinfo(). +// They are displayed by 'show status' +extern ulonglong malloc_sbrk_bytes_alloc; // Bytes allocated by sbrk +extern ulong malloc_chunks_free; // Allocated chunks that are free +extern ulong malloc_mmap_chunks_alloc; // Chunks allocated by mmap +extern ulonglong malloc_mmap_bytes_alloc; // Bytes allocated by mmap +extern ulonglong malloc_bytes_used; // Bytes in use by malloc callers +extern ulonglong malloc_bytes_free; // Bytes allocated by malloc, but free +// The following export VM stats from /proc/self/status. +extern ulonglong vm_size; // Size of process address space in bytes +extern ulonglong vm_data; // Size of address space for data in bytes +extern ulonglong vm_rss; // Size of address space resident in memory in bytes +// binlog_* variables are protected by LOCK_log. +// The number of events written to the binlog. +extern ulonglong binlog_events; +// The largest event written to the binlog. Reset when log is rotated. +extern ulong binlog_largest_event; + +// Tables that we want to force a log of queries on +extern HASH log_tables; extern uint test_flags,select_errors,ha_open_options; extern uint protocol_version,dropping_tables; extern uint delay_key_write_options, lower_case_table_names; extern bool opt_endinfo, using_udf_functions, locked_in_memory; extern bool opt_using_transactions, mysql_embedded; -extern bool using_update_log, opt_large_files, server_id_supplied; -extern bool opt_log, opt_update_log, opt_bin_log, opt_slow_log, opt_error_log; +extern bool using_update_log, opt_large_files, server_id_supplied, using_dml_log; +extern bool opt_log, opt_update_log, opt_bin_log, opt_slow_log, opt_error_log, + opt_dml_log; extern bool opt_disable_networking, opt_skip_show_db; extern bool volatile abort_loop, shutdown_in_progress, grant_option; extern uint volatile thread_count, thread_running, global_read_lock; @@ -738,6 +774,7 @@ extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs; extern MYSQL_LOG mysql_log,mysql_update_log,mysql_slow_log,mysql_bin_log; +extern MYSQL_LOG mysql_audit_log; extern FILE *bootstrap_file; extern pthread_key(MEM_ROOT*,THR_MALLOC); extern pthread_key(NET*, THR_NET); @@ -757,6 +794,76 @@ extern struct system_variables global_system_variables; extern struct system_variables max_system_variables; extern struct rand_struct sql_rand; +extern HASH global_user_stats; +extern pthread_mutex_t LOCK_global_user_stats; +extern char uc_update_queries[]; +extern HASH global_table_stats; +extern pthread_mutex_t LOCK_global_table_stats; +extern HASH global_index_stats; +extern pthread_mutex_t LOCK_global_index_stats; +extern pthread_mutex_t LOCK_stats; +extern ulong sync_binlog_period, sync_binlog_counter; +extern ulong sync_mirror_binlog_period; +extern ulong gettimeofday_errors; +extern ulong rpl_mirror_binlog_clients, rpl_mirror_binlog_status; + +/* The variable indicating whether the transaction support in replication + * is enabled. + */ +extern my_bool rpl_transaction_enabled, rpl_always_enter_innodb; +extern my_bool rpl_long_filename; + +/* Replication I/O thread's failing connection tries to the master. */ +extern ulong rpl_fail_io_connections; + +/* How many times binlog truncation error happens. */ +extern ulong binlog_trunc_errors; + +/* Time on slave at which last replication event was copied from the master */ +extern ulong rpl_last_event_buffered; + +/* Time from master of last event executed on the slave */ +extern ulong rpl_last_event_done; + +/* Diff between rpl_last_event_done and rpl_last_event_buffered */ +extern ulong rpl_last_event_diff; + +/* Max time to run replication event for last N events */ +extern ulong rpl_slowest_event; + +/* Max replication delay from the last N events */ +extern ulong rpl_max_delay; + +/* The fixed size for replication event buffer. Replication event can exceed + * the fixed size. + */ +extern ulong rpl_event_buffer_size; + +/* The variable indicating whether we relay binlog from a primary database. + */ +extern my_bool rpl_mirror_binlog_enabled; +extern my_bool rpl_mirror_binlog_no_replicate; + +extern ulong rpl_semi_sync_enabled; +extern ulong rpl_semi_sync_slave_enabled; +extern ulong rpl_semi_sync_timeout; +extern ulong rpl_semi_sync_trace_level; +extern ulong rpl_semi_sync_status; +extern ulong rpl_semi_sync_slave_status; +extern ulong rpl_semi_sync_yes_transactions; +extern ulong rpl_semi_sync_no_transactions; +extern ulong rpl_semi_sync_off_times; +extern ulong rpl_semi_sync_timefunc_fails; +extern ulong rpl_semi_sync_num_timeouts; +extern ulong rpl_semi_sync_wait_sessions; +extern ulong rpl_semi_sync_back_wait_pos; +extern ulong rpl_semi_sync_trx_wait_time; +extern ulong rpl_semi_sync_net_wait_time; +extern ulonglong rpl_semi_sync_net_wait_num; +extern ulonglong rpl_semi_sync_trx_wait_num; +extern ulonglong rpl_semi_sync_net_wait_total_time; +extern ulonglong rpl_semi_sync_trx_wait_total_time; +extern ulong rpl_semi_sync_clients; /* optional things, have_* variables */ diff -ruN base/sql/opt_sum.cc mysql40gpl/sql/opt_sum.cc --- base/sql/opt_sum.cc 2005-09-02 15:37:55.000000000 -0700 +++ mysql40gpl/sql/opt_sum.cc 2007-04-21 12:40:55.000000000 -0700 @@ -174,6 +174,8 @@ { if (error == HA_ERR_KEY_NOT_FOUND || error == HA_ERR_END_OF_FILE) return -1; // No rows matching WHERE + else if (error == -1) + error = HA_ERR_WRONG_COMMAND; // Return -1 means no rows matched table->file->print_error(error, MYF(0)); return(error); // HA_ERR_LOCK_DEADLOCK or @@ -241,6 +243,8 @@ { if (error == HA_ERR_KEY_NOT_FOUND || error == HA_ERR_END_OF_FILE) return -1; // Impossible query + else if (error == -1) + error = HA_ERR_WRONG_COMMAND; // Return -1 means no rows matched table->file->print_error(error, MYF(0)); return error; // Deadlock or some other error diff -ruN base/sql/repl_failsafe.cc mysql40gpl/sql/repl_failsafe.cc --- base/sql/repl_failsafe.cc 2005-09-02 15:38:07.000000000 -0700 +++ mysql40gpl/sql/repl_failsafe.cc 2007-04-21 09:57:11.000000000 -0700 @@ -928,6 +928,12 @@ active_mi->rli.master_log_pos = active_mi->master_log_pos; strmake(active_mi->rli.master_log_name,active_mi->master_log_name, sizeof(active_mi->rli.master_log_name)-1); + /* + * Cancel the previous START SLAVE UNTIL, as the fact to download + * a new copy logically makes UNTIL irrelevant. + */ + clear_until_condition(&active_mi->rli); + flush_relay_log_info(&active_mi->rli); pthread_cond_broadcast(&active_mi->rli.data_cond); pthread_mutex_unlock(&active_mi->rli.data_lock); diff -ruN base/sql/repl_mule.cc mysql40gpl/sql/repl_mule.cc --- base/sql/repl_mule.cc 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/sql/repl_mule.cc 2007-04-21 11:19:15.000000000 -0700 @@ -0,0 +1,585 @@ +/* Copyright (C) 2007 Google Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "mysql_priv.h" +#include +#include "slave.h" +#include "repl_mule.h" + +/* max log size: 2GB */ +#define MAX_LOG_SIZE BINLOG_NOSWITCH_SIZE + +ReplMule::ReplMule(THD* thd, MASTER_INFO *mi, RelayStatus status, + const char *curr_log_filename, + my_off_t file_size, const char *binlog_indexname, + MYSQL_LOG *binlog, ulong sync_period) + : io_thd_(thd), mi_(mi), status_(status), dump_position_(0L), + file_size_(file_size), mule_log_(binlog), + mule_log_sync_period_(sync_period), mule_log_event_counter_(0) { + char llbuf1[22], llbuf2[22]; + + DBUG_ENTER("ReplMule::ReplMule"); + + strmake(mule_indexname_, binlog_indexname, sizeof(mule_indexname_)-1); + + /* Open the mule log file */ + if (!mule_log_->is_log_open()) { + /* Do not open binlog file when master_log_name is not specified. We + * are at the I/O thread initialization time and we do not know what + * filename we are going to dump. + * We wait for the next rotation event to indicate the filename. + */ + if (strlen(curr_log_filename) > 0 && + mule_log_->open(curr_log_filename, LOG_BIN, NULL, mule_indexname_, + SEQ_READ_APPEND, true, MAX_LOG_SIZE) != 0) { + sql_print_error("ReplMule: open binlog failed: %s", + curr_log_filename); + status_ = MULE_ERROR; + DBUG_VOID_RETURN; + } + } + + /* Store the original master position in case we need to restore them. */ + strmake(dump_filename_, mi->master_log_name, sizeof(dump_filename_)-1); + dump_position_ = mi->master_log_pos; + + strmake(verify_filename_, "", sizeof(verify_filename_)-1); + switch (status_) { + case MULE_BEHIND: + mi->master_log_pos = file_size_; + + if (strcmp(mi->master_log_name, dump_filename_) < 0) { + strmake(mi->master_log_name, curr_log_filename, + sizeof(mi->master_log_name)-1); + seekToPosition(file_size_); + + /* When mule binlog catches up, it will be a different file. So, + * file_size_ is not useful anymore. + */ + file_size_ = 0; + } + + sql_print_information( + "ReplicationMule: MULE_BEHIND - new(%s, %s), old(%s, %s)", + mi->master_log_name, llstr(mi->master_log_pos, llbuf1), + dump_filename_, llstr(dump_position_, llbuf2)); + break; + case RELAY_MATCH_MULE: + sql_print_information("ReplicationMule: RELAY_MATCH_MULE (%s, %s)", + mi->master_log_name, + llstr(mi->master_log_pos, llbuf1)); + break; + case MULE_VERIFY: + case MULE_VERIFY_RELAY_BEHIND: + strmake(verify_filename_, curr_log_filename, sizeof(verify_filename_)-1); + if (strcmp(verify_filename_, mi->master_log_name) < 0) { + strmake(mi->master_log_name, verify_filename_, + sizeof(mi->master_log_name)-1); + } + mi->master_log_pos = BIN_LOG_HEADER_SIZE; + sql_print_information( + "ReplicationMule: MULE_VERIFY - old(%s, %s), new(%s, %s)", + dump_filename_, llstr(dump_position_, llbuf1), + curr_log_filename, llstr(file_size_, llbuf2)); + + /* seek to the beginning of the file for verification */ + seekToPosition(BIN_LOG_HEADER_SIZE); + break; + default: + sql_print_error("ReplMule: unrecognized status %d", status_); + status_ = MULE_ERROR; + DBUG_VOID_RETURN; + } + + /* Indicate that we are in replication mule mode. Also, the mule log is + * only servable when relay match mule because we finished all verification. + */ + mule_log_->set_mule_mode(status_ == RELAY_MATCH_MULE); + + DBUG_VOID_RETURN; +} + +ReplMule::~ReplMule() { + DBUG_ENTER("ReplMule::~ReplMule"); + + if (mule_log_->is_log_open()) + mule_log_->close(LOG_CLOSE_INDEX); + mule_log_->clear_mule_mode(); + + /* If we are still in MULE_BEHIND or MULE_VERIFY state and we exit from + * I/O thread, it means we encountered some errors. + * mi->master_log_pos might be used by later slave start. It is being + * changed here to do event dumping or event verification. So, we should + * restore it to its original value. + */ + switch (status_) { + case MULE_BEHIND: + case MULE_VERIFY: + case MULE_VERIFY_RELAY_BEHIND: + if (mi_->master_log_pos < dump_position_) + mi_->master_log_pos = dump_position_; + if (strcmp(mi_->master_log_name, dump_filename_) != 0) + strmake(mi_->master_log_name, dump_filename_, + sizeof(dump_filename_)-1); + break; + } + + DBUG_VOID_RETURN; +} + +ReplMule::WriteStatus ReplMule::writeEvent(const char* buf, ulong event_len) { + WriteStatus dump_status = WRITE_RELAY; + char llbuf1[22], llbuf2[22], llbuf3[22]; + char *verify_event; + bool verified = false; + bool skip_event = false; + int cmp; + + DBUG_ENTER("ReplMule::writeEvent"); + switch (status_) { + case MULE_VERIFY: + case MULE_VERIFY_RELAY_BEHIND: + if (buf[EVENT_TYPE_OFFSET] == ROTATE_EVENT && + IsFakeRotation(buf, event_len)) { + /* Do not verify the faked rotate event */ + if (status_ == MULE_VERIFY) + dump_status = SKIP_RELAY; + break; + } + verify_event = new char[event_len]; + if (verify_event == NULL) { + sql_print_error( + "ReplMule::writeEvent - insufficient memory in verification, " + "position(%s), event_len(%d).", + llstr(mi_->master_log_pos, llbuf1), event_len); + dump_status = WRITE_ERROR; + break; + } + if (my_b_read(mule_log_->get_log_file(), (byte*) verify_event, + event_len) != 0) { + sql_print_error( + "ReplMule::writeEvent - read log error in verification, " + "position(%s), event_len(%d).", + llstr(mi_->master_log_pos, llbuf1), event_len); + dump_status = WRITE_ERROR; + delete verify_event; + break; + } + verified = (memcmp(buf, verify_event, event_len) == 0); + delete verify_event; + if (!verified) { + sql_print_error( + "ReplMule::writeEvent - event not match at position(%s, %s)", + mi_->master_log_name, llstr(mi_->master_log_pos, llbuf1)); + dump_status = WRITE_ERROR; + break; + } + /* fall through */ + case MULE_BEHIND: + dump_status = SKIP_RELAY; + if (status_ == MULE_BEHIND && + queueEvent(buf, event_len, &skip_event) != 0) { + dump_status = WRITE_ERROR; + break; + } + + /* Skip faked rotation event */ + if (!skip_event) + mi_->master_log_pos += event_len; + + cmp = strcmp(mi_->master_log_name, dump_filename_); + if (cmp != 0) { + if (cmp > 0) { + sql_print_error( + "ReplMule::writeEvent - mule position(%s, %s) is ahead " + "relay-log position(%, %s). impossible!", + mi_->master_log_name, llstr(mi_->master_log_pos, llbuf1), + dump_filename_, llstr(dump_position_, llbuf2)); + dump_status = WRITE_ERROR; + } else if (status_ == MULE_VERIFY) { + if (strcmp(verify_filename_, mi_->master_log_name) == 0) { + /* We are verifying the last old mirror binlog. */ + if (mi_->master_log_pos == file_size_) { + /* We verfied all events in the last old mirror binlog. + * The status is behined, instead of verify now. + */ + status_ = MULE_BEHIND; + sql_print_information( + "ReplMule::writeEvent - new status(%d), verify(%s, %s) " + "dump(%s, %s).", + status_, verify_filename_, llstr(file_size_, llbuf3), + dump_filename_, llstr(dump_position_, llbuf2)); + + /* Reset the verify position. */ + strmake(verify_filename_, "", sizeof(verify_filename_)-1); + file_size_ = 0; + } else if (mi_->master_log_pos > file_size_) { + dump_status = WRITE_ERROR; + + sql_print_error( + "ReplMule::writeEvent - verify(%s, %s), mule(%s, %s)", + verify_filename_, llstr(file_size_, llbuf3), + mi_->master_log_name, llstr(mi_->master_log_pos, llbuf1)); + } + } + } + break; + } + if (mi_->master_log_pos == dump_position_) { + if (dump_position_ < file_size_) { + status_ = MULE_VERIFY_RELAY_BEHIND; + } else { + status_ = RELAY_MATCH_MULE; + + /* Set replication mule mode and the log is servable. */ + mule_log_->set_mule_mode(true); + } + sql_print_information( + "ReplMule::writeEvent =d - new status(%d), file(%s) " + "master_log_pos(%s), dump_pos(%s), file_size(%s)", + status_, dump_filename_, + llstr(mi_->master_log_pos, llbuf1), llstr(dump_position_, llbuf2), + llstr(file_size_, llbuf3)); + } else if (mi_->master_log_pos == file_size_) { + if (dump_position_ > file_size_) { + status_ = MULE_BEHIND; + } else { + status_ = RELAY_MATCH_MULE; + + /* Set replication mule mode and the log is servable. */ + mule_log_->set_mule_mode(true); + } + sql_print_information( + "ReplMule::writeEvent =f - new status(%d), file(%s) " + "master_log_pos(%s), dump_pos(%s), file_size(%s)", + status_, dump_filename_, + llstr(mi_->master_log_pos, llbuf1), llstr(dump_position_, llbuf2), + llstr(file_size_, llbuf3)); + } else if (status_ != MULE_VERIFY_RELAY_BEHIND && + mi_->master_log_pos > dump_position_) { + sql_print_error( + "ReplMule::writeEvent - mule position(%s) does not match " + "relay-log position(%s), file(%s).", + llstr(mi_->master_log_pos, llbuf1), llstr(dump_position_, llbuf2), + dump_filename_); + dump_status = WRITE_ERROR; + } + break; + case RELAY_MATCH_MULE: + if (queueEvent(buf, event_len, &skip_event) != 0) + dump_status = WRITE_ERROR; + break; + } + + DBUG_RETURN(dump_status); +} + +int ReplMule::appendEvent(const char* buf, ulong event_len) { + char llbuf1[22]; + int error; + + DBUG_ENTER("ReplMule::appendEvent"); + + error = mule_log_->appendv(buf,event_len,0); + if (error != 0) { + sql_print_error("ReplMule::appendEvent - append error at %s(%s)", + mi_->master_log_name, + llstr(mi_->master_log_pos, llbuf1)); + } else if (mule_log_->flush_log_file() != 0) { + sql_print_error("ReplMule::appendEvent - flush error at %s(%s)", + mi_->master_log_name, + llstr(mi_->master_log_pos, llbuf1)); + error = -1; + } else if (mule_log_sync_period_ > 0) { + mule_log_event_counter_++; + if (mule_log_event_counter_ >= mule_log_sync_period_) { + mule_log_event_counter_ = 0; + error = my_sync(mule_log_->get_log_file()->file, MYF(MY_WME)); + if (error != 0) + sql_print_error("ReplMule::appendEvent - sync error at %s(%s)", + mi_->master_log_name, + llstr(mi_->master_log_pos, llbuf1)); + } + } + + DBUG_RETURN(error); +} + +int ReplMule::queueEvent(const char* buf, ulong event_len, bool *skip_event) { + int error = 0; + + DBUG_ENTER("ReplMule::queueEvent"); + + *skip_event = false; + + mule_log_->lock_log(); + if (buf[EVENT_TYPE_OFFSET] == ROTATE_EVENT) { + Rotate_log_event rev(buf, event_len, false); + + /* If this is a faked rotate event and the specified filename is + * the same as the current binlog filename, ignore the event. + */ + if (IsFakeRotation(rev)) { + *skip_event = true; + DBUG_PRINT("info",("skipped faked rotation event")); + } else { + /* Only append real events. */ + if (rev.when != 0) + error = appendEvent(buf, event_len); + + /* Only rotate file when append succeeds. */ + if (error == 0) { + char new_name[FN_REFLEN]; + + /* Create a new file: lock both index and log. */ + mule_log_->lock_index(); + + /* We check whether the new mirror binlog already exists. Indicate an + * error if it is so. This is a sanity check to make sure we would not + * overwrite mirrored files. + * Because we use SEQ_READ_APPEND mode, the consequence will be worse + * if the next file is already in the directory. + */ + fn_format(new_name, rev.new_log_ident, mysql_data_home, "", 4); + if (access(new_name, F_OK) != 0) { + /* The file does not exist. */ + if (strlen(mi_->master_log_name) == 0) { + /* If mi_->master_log_name is not specified, then this is the first + * valid rotation event to indicate the filename. + */ + error = mule_log_->open(rev.new_log_ident, LOG_BIN, NULL, + mule_indexname_, SEQ_READ_APPEND, + true, MAX_LOG_SIZE); + } else { + mule_log_->new_file(0, rev.new_log_ident); + } + + strmake(mi_->master_log_name, rev.new_log_ident, + strlen(rev.new_log_ident)); + mi_->master_log_pos = BIN_LOG_HEADER_SIZE; + + /* After a new file, do not add the event size to the position. */ + *skip_event = true; + } else { + sql_print_error("ReplMule::queueEvent - next %s binlog exists.", + new_name); + error = -1; + } + + mule_log_->unlock_index(); + + DBUG_PRINT("info",("rotate file: %s", rev.new_log_ident)); + } + } + } else { + error = appendEvent(buf, event_len); + } + mule_log_->unlock_log(); + + DBUG_RETURN(error); +} + +void ReplMule::seekToPosition(my_off_t pos) { + DBUG_ENTER("ReplMule::seekToPosition"); + DBUG_PRINT("enter",("seek_pos: %ld", (ulong) pos)); + + my_b_seek(mule_log_->get_log_file(), pos); + DBUG_VOID_RETURN; +} + +bool ReplMule::IsFakeRotation(const char* buf, ulong event_len) { + DBUG_ENTER("ReplMule::IsFakeRotation"); + + Rotate_log_event rev(buf, event_len, false); + DBUG_RETURN(IsFakeRotation(rev)); +} + +bool ReplMule::IsFakeRotation(const Rotate_log_event& rev) { + DBUG_ENTER("ReplMule::IsFakeRotation"); + DBUG_RETURN(rev.when == 0 && + rev.ident_len == strlen(mi_->master_log_name) && + strcmp(rev.new_log_ident, mi_->master_log_name) == 0); +} + +/* createReplicationMule: + * Create a mule that relays master's replication binlog and + * generate an exact same copy on the local filesystem. + * + * Code flow: + * last_mulelog = scan the existing mule log index to find it + * if (mulelog index is not created or there is no mule log inside it) + * old_mule_log <- requested dumping position + * requested dumping position <- 0 in the file + * else + * check whether the mule log matches the requested dump + * (whether the last mule log name/size matches) + * if the mule log name does not match + * exit with an error + * if (the mule log size does not match the requested dump position) + * request the dump from position 0 and read all events + * verify all events with the corresponding events in mule log + * if (the verification succeeds) + * continue the dump + * else + * exit with an error + */ +ReplMule* ReplMule::createReplicationMule( + THD* thd, MASTER_INFO *mi, const char *binlog_indexname, + MYSQL_LOG *binlog) { + ReplMule *mule = NULL; + LOG_INFO linfo; + bool index_opened = false; + + DBUG_ENTER("ReplMule::createReplicationMule"); + + /* binlog_indexname must be set to some real value. */ + DBUG_ASSERT(binlog_indexname); + + /* Lock binlog index for all binlog operations */ + binlog->lock_index(); + index_opened = binlog->open_index_file(binlog_indexname, NULL); + DBUG_PRINT("info",("open index file succeed: %d", index_opened)); + + /* Scan the existing binlog index to find the last relayed binlog */ + if (!index_opened || + binlog->find_log_pos(&linfo, NullS, false) != 0) { + /* binlog index is not created or has no log file inside: + * . old_relay_binlog <- requested dumping position + * . requested dumping position <- 0 in the file + */ + if (mi->master_log_pos == BIN_LOG_HEADER_SIZE) { + mule = new ReplMule(thd, mi, RELAY_MATCH_MULE, + mi->master_log_name, BIN_LOG_HEADER_SIZE, + binlog_indexname, binlog, sync_mirror_binlog_period); + } else { + mule = new ReplMule(thd, mi, MULE_BEHIND, + mi->master_log_name, BIN_LOG_HEADER_SIZE, + binlog_indexname, binlog, sync_mirror_binlog_period); + } + + if (mule == NULL) { + sql_print_error("Mule malloc operation failed."); + } + } else { + IO_CACHE* log_file; + MY_STAT stat; + char last_binlog_name[FN_REFLEN]; + + /* Find the last log file from the binlog index. + * Check whether the last binlog matches the requested dump for both + * binlog name and binlog size. + */ + for (;;) { + strmake(last_binlog_name, linfo.log_file_name, FN_REFLEN); + last_binlog_name[FN_REFLEN - 1] = '\0'; + if (binlog->find_next_log(&linfo, false)) + break; + } + DBUG_PRINT("info",("the last binlog: %s", last_binlog_name)); + + /* if the new binlog filename is behind the last mirrorred binlog filename, + * exit with an error. + */ + if (strcmp(last_binlog_name+dirname_length(last_binlog_name), + mi->master_log_name) > 0) { + sql_print_error("Mule binlog(%s) does not match new relay-binlog(%s)", + last_binlog_name, mi->master_log_name); + } /* Open the last binlog. */ + else if (binlog->open(last_binlog_name, LOG_BIN, NULL, binlog_indexname, + SEQ_READ_APPEND, true, MAX_LOG_SIZE) != 0) { + sql_print_error("Mule open last binlog failed: %s", last_binlog_name); + } else { + bool valid_file_size = true; + + /* Get the binlog size. */ + log_file = binlog->get_log_file(); + my_fstat(log_file->file, &stat, MYF(0)); + + /* If the binlog size does not match the requested dump position, then + * request the dump from position 0 and verify all events, we need to + * verify events because the mule log might be used for serving during + * anytime. We must be sure that they are correct. + */ + if (strcmp(last_binlog_name+dirname_length(last_binlog_name), + mi->master_log_name) < 0) { + char llbuf1[22], llbuf2[22]; + + /* This situation can only happen in two situations: + * . the new master is using mirror binlogs to failover + * . mirror binlog is turnned off, while I/O thread is running + * + * We verify the last binlog we mirrored and mirror all binlogs after + * that. This leaves the small possibility that the old binlog not + * verified might be incorrect. + */ + mule = new ReplMule(thd, mi, + ((stat.st_size == BIN_LOG_HEADER_SIZE) ? + MULE_BEHIND : MULE_VERIFY), + last_binlog_name+dirname_length(last_binlog_name), + stat.st_size, binlog_indexname, binlog, + sync_mirror_binlog_period); + + sql_print_information( + "Mule file(%s) size(%s) is behind of (%s, %s), need verify.", + last_binlog_name+dirname_length(last_binlog_name), + llstr(stat.st_size, llbuf1), + mi->master_log_name, llstr(mi->master_log_pos, llbuf2)); + } else if (stat.st_size == mi->master_log_pos) { + mule = new ReplMule(thd, mi, RELAY_MATCH_MULE, + mi->master_log_name, stat.st_size, + binlog_indexname, binlog, + sync_mirror_binlog_period); + } else if (stat.st_size > BIN_LOG_HEADER_SIZE) { + mule = new ReplMule(thd, mi, MULE_VERIFY, + mi->master_log_name, stat.st_size, + binlog_indexname, binlog, + sync_mirror_binlog_period); + } else if (stat.st_size == BIN_LOG_HEADER_SIZE) { + mule = new ReplMule(thd, mi, MULE_BEHIND, + mi->master_log_name, BIN_LOG_HEADER_SIZE, + binlog_indexname, binlog, + sync_mirror_binlog_period); + } else { + char llbuf[22]; + valid_file_size = false; + sql_print_error("Mule binlog file(%s) invalid size: %s", + last_binlog_name, llstr(stat.st_size, llbuf)); + } + + if (valid_file_size) { + if (mule == NULL) { + sql_print_error("Mule malloc operation failed."); + } else if (mule->status_ == MULE_ERROR) { + /* If mule creation fails, indicate the error. */ + delete mule; + mule = NULL; + } + } + } + } + + /* Clear the mule binlog mode if there are errors. */ + if (mule == NULL) { + binlog->clear_mule_mode(); + binlog->close_index_file(); + } + + /* Unlock binlog index */ + binlog->unlock_index(); + + DBUG_RETURN(mule); +} diff -ruN base/sql/repl_mule.h mysql40gpl/sql/repl_mule.h --- base/sql/repl_mule.h 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/sql/repl_mule.h 2007-04-21 11:19:06.000000000 -0700 @@ -0,0 +1,159 @@ +/* Copyright (C) 2007 Google Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef SQL_REPL_MULE_H__ +#define SQL_REPL_MULE_H__ + +/* Replication Mule is the class that is responsible for generate + * an exact copy of binlog from a master database. We call this feature + * mirror binlog and it can be enabled by setting rpl_mirror_binlog. We + * need to keep the same copy for the following purposes: + * . The replica can serve the binlog transparently as if they are the + * master database. This can relieve master connection overhead. + * . During failover, the replica can become the new master and serve + * old binlogs transparently. + * (The Mule name comes from the popular P2P software eMule.) + * + * Internally, we call the mirrored binlog mule log. + */ + +class THD; +class Rotate_log_event; +typedef struct st_master_info MASTER_INFO; + +class ReplMule { + public: + /* Because I/O thread also creates relay-binlog, instead of an exact + * copy of the original master's binlog, we have two resources that + * might get out of sync. + * This enum indicates the status: + * MULE_BEHIND - the mule's header is behind: + * (mule is activated for the first time) + * RELAY_MATCH_MULE - mule matches relay-log + * MULE_VERIFY - mule has more events than the relay-log and needs + * verification; we can not verify based on relay-log + * events because events might get changed a little + * MULE_VERIFY_RELAY_BEHIND - mule has more events than the relay-log + * and relay-log needs to write events + * MULE_ERROR - mule detects errors in event duplicate + */ + enum RelayStatus { + MULE_BEHIND = 1, + RELAY_MATCH_MULE = 2, + MULE_VERIFY = 3, + MULE_VERIFY_RELAY_BEHIND = 4, + MULE_ERROR = 5, + }; + + enum WriteStatus { + WRITE_RELAY = 1, + WRITE_ERROR = 2, + SKIP_RELAY = 3, + }; + + private: + THD *io_thd_; + MASTER_INFO *mi_; + + /* + * I/O thread will write both mule log for mirror binlog and relay log + * for SQL thread. + * The variable indicates whether the two are in sync. + */ + RelayStatus status_; + + /* The starting event writing filename and position. */ + char dump_filename_[FN_REFLEN]; + my_off_t dump_position_; + + /* The current being verified filename if mirror binlog is behind and is + * of different file as the I/O thread. + */ + char verify_filename_[FN_REFLEN]; + + /* During the initial setup, the last mule log's file size. */ + my_off_t file_size_; + + /* Internally, we call the mirrored binlog mule log. */ + MYSQL_LOG *mule_log_; + + /* Sync the mule log to disk for every #N events. */ + ulong mule_log_sync_period_; + ulong mule_log_event_counter_; + + /* mule log's index filename */ + char mule_indexname_[FN_REFLEN]; + + ReplMule(THD* thd, MASTER_INFO *mi, RelayStatus status, + const char *curr_log_filename, + my_off_t file_size, const char *binlog_indexname, + MYSQL_LOG *binlog, ulong sync_period); + + /* + * Queue the event into the current mule log. If it is a rotation + * event, generate a new mule log file. + * Indicate whether the event is skipped because it is an fake event. + * A fake event is generated by the master to indicate the current + * reading position. + */ + int queueEvent(const char* buf, ulong event_len, bool *skip_event); + + /* Append the event to the current mule log. */ + int appendEvent(const char* buf, ulong event_len); + + bool IsFakeRotation(const char* buf, ulong event_len); + bool IsFakeRotation(const Rotate_log_event& rev); + + /* Seek to the specified position in the current open mule log. */ + void seekToPosition(my_off_t pos); + + public: + + ~ReplMule(); + + /* Dump the event into mule binlog. + * Input: + * buf (IN) - replication event buffer + * event_len (IN) - the event length + * + * Return: + * . WRITE_RELAY: the relay log needs to writing the event + * . WRITE_ERROR: the writing encountered errors + * . SKIP_RELAY: the relay log should skip the event + */ + WriteStatus writeEvent(const char* buf, ulong event_len); + + /* createReplicationMule: + * Create a mule that relays master's replication binlog and + * generate an exact same copy on the local filesystem. + * + * Input: + * thd (IN) - replication I/O thread + * mi (IN) - master info struct for I/O thread's progress + * binlog_indexname (IN) - filename for binlog's index + * binlog (IN) - replication binlog + * + * Return: + * . a replication mule if success + * . NULL if there are any errors + */ + static ReplMule *createReplicationMule(THD* thd, MASTER_INFO *mi, + const char *binlog_indexname, + MYSQL_LOG *binlog); +}; + +#endif /* SQL_REPL_MULE_H__ */ diff -ruN base/sql/repl_semi_sync.cc mysql40gpl/sql/repl_semi_sync.cc --- base/sql/repl_semi_sync.cc 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/sql/repl_semi_sync.cc 2007-04-21 11:18:54.000000000 -0700 @@ -0,0 +1,1188 @@ +/* Copyright (C) 2007 Google Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/* + * The file defines two classes that implement semi-sync replication based on + * MySQL's asynchronous replication: + * . ReplSemiSync::ActiveTranx: manage all active transaction nodes + * . ReplSemiSync: the code flow for semi-sync replication + * + * By default in semi-sync replication, a transaction waits for 10ms to see + * whether the slave has got the transaction. 10ms is based on the assumption + * that roundtrip time in one datacenter is less than 1ms and machine + * configurations should make the master database and the semi-sync slave + * database colocate in one date center. Otherwise, "rpl_semi_sync_timeout" + * should be used to adjust timeout value. + * + */ + +#include "mysql_priv.h" +#include +#include "repl_semi_sync.h" + +#define TIME_THOUSAND 1000 +#define TIME_MILLION 1000000 +#define TIME_BILLION 1000000000 + +const unsigned char ReplSemiSync::kPacketMagicNum = 0xef; +const unsigned char ReplSemiSync::kPacketFlagSync = 0x01; + +const ulong ReplSemiSync::kTraceGeneral = 0x0001; +const ulong ReplSemiSync::kTraceDetail = 0x0010; +const ulong ReplSemiSync::kTraceNetWait = 0x0020; +const ulong ReplSemiSync::kTraceFunction = 0x0040; + +const char ReplSemiSync::kSyncHeader[3] = + {0, ReplSemiSync::kPacketMagicNum, 0}; + +static int getWaitTime(const struct timeval& start_tv); + +/******************************************************************************* + * + * class : manage all active transaction nodes + * + ******************************************************************************/ + +ReplSemiSync::ActiveTranx::ActiveTranx(int max_connections, + pthread_mutex_t *lock, + ulong *trace_level) + : num_transactions_(max_connections), + num_entries_(max_connections << 1), + lock_(lock), trace_level_(trace_level) { + /* Allocate the memory for the array */ + node_array_ = new TranxNode[num_transactions_]; + for (int idx = 0; idx < num_transactions_; ++idx) { + node_array_[idx].log_pos_ = 0; + node_array_[idx].hash_next_ = NULL; + node_array_[idx].next_ = node_array_ + idx + 1; + + node_array_[idx].log_name_ = new char[FN_REFLEN]; + node_array_[idx].log_name_[0] = '\x0'; + } + node_array_[num_transactions_-1].next_ = NULL; + + /* All nodes in the array go to the pool initially. */ + free_pool_ = node_array_; + + /* No transactions are in the list initially. */ + trx_front_ = NULL; + trx_rear_ = NULL; + + /* Create the hash table to find a transaction's ending event. */ + trx_htb_ = new TranxNode *[num_entries_]; + for (int idx = 0; idx < num_entries_; ++idx) + trx_htb_[idx] = NULL; + + sql_print_information("Semi-sync replication initialized for %d " + "transactions.", num_transactions_); +} + +ReplSemiSync::ActiveTranx::~ActiveTranx() { + for (int idx = 0; idx < num_transactions_; ++idx) { + delete node_array_[idx].log_name_; + node_array_[idx].log_name_ = NULL; + } + + delete [] node_array_; + delete [] trx_htb_; + + node_array_ = NULL; + trx_htb_ = NULL; + num_transactions_ = 0; + num_entries_ = 0; +} + +void ReplSemiSync::ActiveTranx::assert_lock_owner() { + safe_mutex_assert_owner(lock_); +} + +void ReplSemiSync::ActiveTranx::function_enter(const char *func_name) { + if ((*trace_level_) & kTraceFunction) + sql_print_information("---> %s enter", func_name); +} + +int ReplSemiSync::ActiveTranx::function_exit(const char *func_name, + int exit_code) { + if ((*trace_level_) & kTraceFunction) + sql_print_information("<--- %s exit (%d)", func_name, exit_code); + return exit_code; +} + +uint ReplSemiSync::ActiveTranx::calc_hash(const byte *key, uint length) { + uint nr = 1, nr2 = 4; + + /* The hash implementation comes from calc_hashnr() in mysys/hash.c. */ + while (length--) { + nr ^= (((nr & 63)+nr2)*((uint) (uchar) *key++))+ (nr << 8); + nr2 += 3; + } + return((uint) nr); +} + +uint ReplSemiSync::ActiveTranx::get_hash_value(const char *log_file_name, + my_off_t log_file_pos) { + uint hash1 = calc_hash((const byte *)log_file_name, + strlen(log_file_name)); + uint hash2 = calc_hash((const byte *)(&log_file_pos), + sizeof(log_file_pos)); + + return (hash1 + hash2) % num_entries_; +} + +ReplSemiSync::ActiveTranx::TranxNode* +ReplSemiSync::ActiveTranx::alloc_tranx_node() { + TranxNode *ptr = free_pool_; + + if (free_pool_) { + free_pool_ = free_pool_->next_; + ptr->next_ = NULL; + ptr->hash_next_ = NULL; + } + + return ptr; +} + +int ReplSemiSync::ActiveTranx::compare( + const char *log_file_name1, my_off_t log_file_pos1, + const char *log_file_name2, my_off_t log_file_pos2) { + int cmp = strcmp(log_file_name1, log_file_name2); + + if (cmp != 0) + return cmp; + + if (log_file_pos1 > log_file_pos2) + return 1; + else if (log_file_pos1 < log_file_pos2) + return -1; + return 0; +} + +int ReplSemiSync::ActiveTranx::insert_tranx_node( + const char *log_file_name, my_off_t log_file_pos) { + const char *kWho = "ActiveTranx:insert_tranx_node"; + TranxNode *ins_node; + int result = 0; + uint hash_val; + + function_enter(kWho); + assert_lock_owner(); + + ins_node = alloc_tranx_node(); + if (!ins_node) { + sql_print_error("%s: transaction node allocation failed for: (%s, %lu)", + kWho, log_file_name, (ulong)log_file_pos); + result = -1; + goto l_end; + } + + /* insert the binlog position in the active transaction list. */ + strcpy(ins_node->log_name_, log_file_name); + ins_node->log_pos_ = log_file_pos; + + if (!trx_front_) { + /* The list is empty. */ + trx_front_ = trx_rear_ = ins_node; + } else { + int cmp = compare(ins_node, trx_rear_); + if (cmp > 0) { + /* Compare with the tail first. If the transaction happens later in + * binlog, then make it the new tail. + */ + trx_rear_->next_ = ins_node; + trx_rear_ = ins_node; + } else { + /* Otherwise, it is an error because the transaction should hold the + * mysql_bin_log.LOCK_log when appending events. + */ + sql_print_error("%s: binlog write out-of-order, tail (%s, %llu), " + "new node (%s, %llu)", + trx_rear_->log_name_, (ulong)trx_rear_->log_pos_, + ins_node->log_name_, (ulong)ins_node->log_pos_); + result = -1; + goto l_end; + } + } + + hash_val = get_hash_value(ins_node->log_name_, ins_node->log_pos_); + ins_node->hash_next_ = trx_htb_[hash_val]; + trx_htb_[hash_val] = ins_node; + + if ((*trace_level_) & kTraceDetail) + sql_print_information("%s: insert (%s, %lu) in entry(%u)", kWho, + ins_node->log_name_, (ulong)ins_node->log_pos_, + hash_val); + + l_end: + return function_exit(kWho, result); +} + +bool ReplSemiSync::ActiveTranx::is_tranx_end_pos(const char *log_file_name, + my_off_t log_file_pos) { + const char *kWho = "ReplSemiSync::is_tranx_end_pos"; + function_enter(kWho); + + uint hash_val = get_hash_value(log_file_name, log_file_pos); + TranxNode *entry = trx_htb_[hash_val]; + + assert_lock_owner(); + while (entry != NULL) { + if (compare(entry, log_file_name, log_file_pos) == 0) { + break; + } + entry = entry->hash_next_; + } + + if ((*trace_level_) & kTraceDetail) + sql_print_information("%s: probe (%s, %lu) in entry(%u)", kWho, + log_file_name, (ulong)log_file_pos, hash_val); + + function_exit(kWho, (entry != NULL)); + return (entry != NULL); +} + +int ReplSemiSync::ActiveTranx::clear_active_tranx_nodes( + const char *log_file_name, my_off_t log_file_pos) { + const char *kWho = "ActiveTranx::::clear_active_tranx_nodes"; + TranxNode *new_front; + + function_enter(kWho); + + /* Must hold the lock during the call. */ + assert_lock_owner(); + + if (log_file_name != NULL) { + new_front = trx_front_; + + while (new_front) { + if (compare(new_front, log_file_name, log_file_pos) > 0) + break; + new_front = new_front->next_; + } + } else { + /* If log_file_name is NULL, clear everything. */ + new_front = NULL; + } + + if (new_front == NULL) { + /* No active transaction nodes after the call. */ + + /* Clear the hash table. */ + memset(trx_htb_, 0, num_entries_ * sizeof(TranxNode *)); + + /* Clear the active transaction list. */ + if (trx_front_ != NULL) { + trx_rear_->next_ = free_pool_; + free_pool_ = trx_front_; + trx_front_ = NULL; + trx_rear_ = NULL; + } + + if ((*trace_level_) & kTraceDetail) + sql_print_information("%s: free all nodes back to free list", kWho); + } else if (new_front != trx_front_) { + TranxNode *curr_node, *next_node; + + /* Delete all transaction nodes before the confirmation point. */ + int n_frees = 0; + curr_node = trx_front_; + while (curr_node != new_front) { + next_node = curr_node->next_; + + /* Put the node in the memory pool. */ + curr_node->next_ = free_pool_; + free_pool_ = curr_node; + n_frees++; + + /* Remove the node from the hash table. */ + uint hash_val = get_hash_value(curr_node->log_name_, curr_node->log_pos_); + TranxNode **hash_ptr = &(trx_htb_[hash_val]); + while ((*hash_ptr) != NULL) { + if ((*hash_ptr) == curr_node) { + (*hash_ptr) = curr_node->hash_next_; + break; + } + hash_ptr = &((*hash_ptr)->hash_next_); + } + + curr_node = next_node; + } + + trx_front_ = new_front; + + if ((*trace_level_) & kTraceDetail) + sql_print_information("%s: free %d nodes back until pos (%s, %llu)", + kWho, n_frees, + trx_front_->log_name_, (ulong)trx_front_->log_pos_); + } + + return function_exit(kWho, 0); +} + + +/******************************************************************************* + * + * class: the basic code layer for sync-replication. + * + * The most important functions during semi-syn replication listed: + * + * Master: + * . reportReplyBinlog(): called by the binlog dump thread when it receives + * the slave's status information. + * . updateSyncHeader(): based on transaction waiting information, decide + * whether to request the slave to reply. + * . readSlaveReply(): read the slave's sync reply and decide how to + * resume the waiting transaction threads. + * . writeTraxInBinlog(): called by the transaction thread when it finishes + * writing all transaction events in binlog. + * . commitTrx(): transaction thread wait for the slave reply. + * + * Slave: + * . slaveReadSyncHeader(): read the semi-sync header from the master, get the + * sync status and get the payload for events. + * . slaveReply(): reply to the master about the replication progress. + * + ******************************************************************************/ + +ReplSemiSync::ReplSemiSync() + : active_tranxs_(NULL), + reply_file_name_inited_(false), + reply_file_pos_(0L), + wait_file_name_inited_(false), + wait_file_pos_(0), + master_enabled_(false), + slave_enabled_(false), + wait_timeout_(0L), + trace_level_(0L), + state_(0), + enabled_transactions_(0), + disabled_transactions_(0), + timefunc_fails_(0), + switched_off_times_(0), + wait_sessions_(0), + wait_backtraverse_(0), + total_trx_wait_num_(0), + total_trx_wait_time_(0), + total_net_wait_num_(0), + total_net_wait_time_(0), + max_transactions_(0L) { + strcpy(reply_file_name_, ""); + strcpy(wait_file_name_, ""); +} + +int ReplSemiSync::initObject() { + int result; + const char *kWho = "ReplSemiSync::initObject"; + + /* References to the parameter works after set_options(). */ + setSlaveEnabled(rpl_semi_sync_slave_enabled); + setWaitTimeout(rpl_semi_sync_timeout); + setTraceLevel(rpl_semi_sync_trace_level); + max_transactions_ = (int)max_connections; + + /* Mutex initialization can only be done after MY_INIT(). */ + pthread_mutex_init(&LOCK_binlog_, MY_MUTEX_INIT_FAST); + pthread_cond_init(&COND_binlog_send_, NULL); + + if (rpl_semi_sync_enabled) + result = enableMaster(); + else + result = disableMaster(); + + return result; +} + +int ReplSemiSync::enableMaster() { + int result = 0; + + /* Must have the lock when we do enable of disable. */ + lock(); + + if (!getMasterEnabled()) { + DBUG_ASSERT(active_tranxs_ == NULL); + active_tranxs_ = new ReplSemiSync::ActiveTranx(max_connections, + &LOCK_binlog_, + &trace_level_); + if (active_tranxs_ != NULL) { + reply_file_name_inited_ = false; + wait_file_name_inited_ = false; + commit_file_name_inited_ = false; + + set_master_enabled(true); + } else { + sql_print_error("Semi-sync replication not able to allocate memory."); + result = -1; + } + } + + unlock(); + + return result; +} + +int ReplSemiSync::disableMaster() { + /* Must have the lock when we do enable of disable. */ + lock(); + + if (getMasterEnabled()) { + /* Switch off the semi-sync first so that waiting transaction will be + * waken up. + */ + switch_off(); + + DBUG_ASSERT(active_tranxs_ != NULL); + delete active_tranxs_; + active_tranxs_ = NULL; + + reply_file_name_inited_ = false; + wait_file_name_inited_ = false; + commit_file_name_inited_ = false; + + set_master_enabled(false); + } + + unlock(); + + return 0; +} + +ReplSemiSync::~ReplSemiSync() { + pthread_mutex_destroy(&LOCK_binlog_); + pthread_cond_destroy(&COND_binlog_send_); + + delete active_tranxs_; +} + +void ReplSemiSync::lock() { + pthread_mutex_lock(&LOCK_binlog_); +} + +void ReplSemiSync::unlock() { + pthread_mutex_unlock(&LOCK_binlog_); +} + +void ReplSemiSync::cond_broadcast() { + pthread_cond_broadcast(&COND_binlog_send_); +} + +int ReplSemiSync::cond_timewait(struct timespec *wait_time) { + const char *kWho = "ReplSemiSync::cond_timewait()"; + int wait_res; + + function_enter(kWho); + wait_res = pthread_cond_timedwait(&COND_binlog_send_, + &LOCK_binlog_, wait_time); + return function_exit(kWho, wait_res); +} + +void ReplSemiSync::function_enter(const char *func_name) { + if (trace_level_ & kTraceFunction) + sql_print_information("---> %s enter", func_name); +} + +int ReplSemiSync::function_exit(const char *func_name, int exit_code) { + if (trace_level_ & kTraceFunction) + sql_print_information("<--- %s exit (%d)", func_name, exit_code); + return exit_code; +} + +int ReplSemiSync::reportReplyBinlog(THD *thd, + char *log_file_name, + my_off_t log_file_pos) { + const char *kWho = "ReplSemiSync::reportReplyBinlog"; + int cmp; + bool can_release_threads = false; + bool need_copy_send_pos = true; + + /* If semi-sync replication is not enabled, or this thd is + * sending binlog to a slave where we do not need synchronous replication, + * then return immediately */ + if (!(getMasterEnabled() && thd->semi_sync_slave)) { + return 0; + } + + function_enter(kWho); + + lock(); + + /* This is the real check inside the mutex. */ + if (!getMasterEnabled()) + goto l_end; + + if (!is_on()) { + /* We check to see whether we can switch semi-sync ON. */ + try_switch_on(thd->server_id, log_file_name, log_file_pos); + } + + /* The position should increase monotonically, if there is only one + * thread sending the binlog to the slave. + * In reality, to improve the transaction availability, we allow multiple + * sync replication slaves. So, if any one of them get the transaction, + * the transaction session in the primary can move forward. + */ + if (reply_file_name_inited_) { + cmp = ActiveTranx::compare(log_file_name, log_file_pos, + reply_file_name_, reply_file_pos_); + + /* If the requested position is behind the sending binlog position, + * would not adjust sending binlog position. + * We based on the assumption that there are multiple semi-sync slave, + * and at least one of them shou/ld be up to date. + * If all semi-sync slaves are behind, at least initially, the primary + * can find the situation after the waiting timeout. After that, some + * slaves should catch up quickly. + */ + if (cmp < 0) { + /* If the position is behind, do not copy it. */ + need_copy_send_pos = false; + } + } + + if (need_copy_send_pos) { + strcpy(reply_file_name_, log_file_name); + reply_file_pos_ = log_file_pos; + reply_file_name_inited_ = true; + + /* Remove all active transaction nodes before this point. */ + DBUG_ASSERT(active_tranxs_ != NULL); + active_tranxs_->clear_active_tranx_nodes(log_file_name, log_file_pos); + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: Got reply at (%s, %lu)", kWho, + log_file_name, (ulong)log_file_pos); + } + + if (wait_sessions_ > 0) { + /* Let us check if some of the waiting threads doing a trx + * commit can now proceed. + */ + cmp = ActiveTranx::compare(reply_file_name_, reply_file_pos_, + wait_file_name_, wait_file_pos_); + if (cmp >= 0) { + /* Yes, at least one waiting thread can now proceed: + * let us release all waiting threads with a broadcast + */ + can_release_threads = true; + wait_file_name_inited_ = false; + } + } + + l_end: + unlock(); + + if (can_release_threads) { + if (trace_level_ & kTraceDetail) + sql_print_information("%s: signal all waiting threads."); + + cond_broadcast(); + } + + return function_exit(kWho, 0); +} + +int ReplSemiSync::commitTrx(const char* trx_wait_binlog_name, + my_off_t trx_wait_binlog_pos) { + const char *kWho = "ReplSemiSync::commitTrx"; + + function_enter(kWho); + + if (getMasterEnabled() && trx_wait_binlog_name) { + struct timeval start_tv; + struct timespec abstime; + int wait_result, start_time_err; + + start_time_err = gettimeofday(&start_tv, 0); + + /* Acquire the mutex. */ + lock(); + + /* This is the real check inside the mutex. */ + if (!getMasterEnabled()) + goto l_end; + + if (trace_level_ & kTraceDetail) { + sql_print_information("%s: wait pos (%s, %lu), repl(%d)\n", kWho, + trx_wait_binlog_name, (ulong)trx_wait_binlog_pos, + (int)is_on()); + } + + while (is_on()) { + int cmp = ActiveTranx::compare(reply_file_name_, reply_file_pos_, + trx_wait_binlog_name, trx_wait_binlog_pos); + if (cmp >= 0) { + /* We have already sent the relevant binlog to the slave: no need to + * wait here. + */ + if (trace_level_ & kTraceDetail) + sql_print_information("%s: Binlog reply is ahead (%s, %lu),", + kWho, reply_file_name_, (ulong)reply_file_pos_); + break; + } + + /* Let us update the info about the minimum binlog position of waiting + * threads. + */ + if (wait_file_name_inited_) { + cmp = ActiveTranx::compare(trx_wait_binlog_name, trx_wait_binlog_pos, + wait_file_name_, wait_file_pos_); + if (cmp <= 0) { + /* This thd has a lower position, let's update the minimum info. */ + strcpy(wait_file_name_, trx_wait_binlog_name); + wait_file_pos_ = trx_wait_binlog_pos; + + wait_backtraverse_++; + if (trace_level_ & kTraceDetail) + sql_print_information("%s: move back wait position (%s, %lu),", + kWho, wait_file_name_, (ulong)wait_file_pos_); + } + } else { + strcpy(wait_file_name_, trx_wait_binlog_name); + wait_file_pos_ = trx_wait_binlog_pos; + wait_file_name_inited_ = true; + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: init wait position (%s, %lu),", + kWho, wait_file_name_, (ulong)wait_file_pos_); + } + + if (start_time_err == 0) { + int diff_usecs = start_tv.tv_usec + wait_timeout_ * TIME_THOUSAND; + + /* Calcuate the waiting period. */ + abstime.tv_sec = start_tv.tv_sec; + if (diff_usecs < TIME_MILLION) { + abstime.tv_nsec = diff_usecs * TIME_THOUSAND; + } else { + while (diff_usecs >= TIME_MILLION) { + abstime.tv_sec++; + diff_usecs -= TIME_MILLION; + } + abstime.tv_nsec = diff_usecs * TIME_THOUSAND; + } + + /* In semi-synchronous replication, we wait until the binlog-dump + * thread has received the reply on the relevant binlog segment from the + * replication slave. + * + * Let us suspend this thread to wait on the condition; + * when replication has progressed far enough, we will release + * these waiting threads. + */ + wait_sessions_++; + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: wait %lu ms for binlog sent (%s, %lu)", + kWho, wait_timeout_, + wait_file_name_, (ulong)wait_file_pos_); + + DBUG_PRINT("info", ("Waiting for binlog to be sent")); + wait_result = cond_timewait(&abstime); + wait_sessions_--; + + if (wait_result != 0) { + if (trace_level_ & kTraceGeneral) { + /* This is a real wait timeout. */ + sql_print_error("Replication semi-sync not sent binlog to " + "slave within the timeout %lu ms - OFF.", + wait_timeout_); + sql_print_error(" semi-sync up to file %s, position %lu", + reply_file_name_, (ulong)reply_file_pos_); + sql_print_error(" transaction needs file %s, position %lu", + trx_wait_binlog_name, (uint)trx_wait_binlog_pos); + } + total_wait_timeouts_++; + + /* switch semi-sync off */ + switch_off(); + } else { + int wait_time; + + wait_time = getWaitTime(start_tv); + if (wait_time < 0) { + if (trace_level_ & kTraceGeneral) { + /* This is a time/gettimeofday function call error. */ + sql_print_error("Replication semi-sync gettimeofday fail1 at " + "wait position (%s, %d)", + trx_wait_binlog_name, (uint)trx_wait_binlog_pos); + } + timefunc_fails_++; + } else { + total_trx_wait_num_++; + total_trx_wait_time_ += wait_time; + } + } + } else { + if (trace_level_ & kTraceGeneral) { + /* This is a gettimeofday function call error. */ + sql_print_error("Replication semi-sync gettimeofday fail2 at " + "wait position (%s, %d)", + trx_wait_binlog_name, (uint)trx_wait_binlog_pos); + } + timefunc_fails_++; + + /* switch semi-sync off */ + switch_off(); + } + } + + l_end: + /* Update the status counter. */ + if (is_on()) + enabled_transactions_++; + else + disabled_transactions_++; + + unlock(); + } + + return function_exit(kWho, 0); +} + +/* Indicate that semi-sync replication is OFF now. + * + * What should we do when it is disabled? The problem is that we want + * the semi-sync replication enabled again when the slave catches up + * later. But, it is not that easy to detect that the slave has caught + * up. This is caused by the fact that MySQL's replication protocol is + * asynchronous, meaning that if the master does not use the semi-sync + * protocol, the slave would not send anything to the master. + * Still, if the master is sending (N+1)-th event, we assume that it is + * an indicator that the slave has received N-th event and earlier ones. + * + * If semi-sync is disabled, all transactions still update the wait + * position with the last position in binlog. But no transactions will + * wait for confirmations and the active transaction list would not be + * maintained. In binlog dump thread, updateSyncHeader() checks whether + * the current sending event catches up with last wait position. If it + * does match, semi-sync will be switched on again. + */ +int ReplSemiSync::switch_off() { + const char *kWho = "ReplSemiSync::switch_off"; + int result; + + function_enter(kWho); + state_ = false; + + /* Clear the active transaction list. */ + DBUG_ASSERT(active_tranxs_ != NULL); + result = active_tranxs_->clear_active_tranx_nodes(NULL, 0); + + switched_off_times_++; + wait_file_name_inited_ = false; + cond_broadcast(); /* wake up all waiting threads */ + + return function_exit(kWho, result); +} + +int ReplSemiSync::try_switch_on(int server_id, const char *log_file_name, + my_off_t log_file_pos) { + const char *kWho = "ReplSemiSync::try_switch_on"; + bool semi_sync_on = false; + + function_enter(kWho); + + /* If the current sending event's position is larger than or equal to the + * 'largest' commit transaction binlog position, the slave is already + * catching up now and we can switch semi-sync on here. + * If commit_file_name_inited_ indicates there are no recent transactions, + * we can enable semi-sync immediately. + */ + if (commit_file_name_inited_) { + int cmp = ActiveTranx::compare(log_file_name, log_file_pos, + commit_file_name_, commit_file_pos_); + semi_sync_on = (cmp >= 0); + } else { + semi_sync_on = true; + } + + if (semi_sync_on) { + /* Switch semi-sync replication on. */ + state_ = true; + + if (trace_level_ & kTraceGeneral) + sql_print_information("%s switch semi-sync ON with server(%d) " + "at (%s, %lu), repl(%d)", + kWho, server_id, log_file_name, + (ulong)log_file_pos, (int)is_on()); + } + + return function_exit(kWho, 0); +} + +void ReplSemiSync::reserveSyncHeader( + String *packet, THD *thd, + char *packet_buffer, ulong packet_buffer_size) { + const char *kWho = "ReplSemiSync::reserveSyncHeader"; + function_enter(kWho); + + packet->set(packet_buffer, (uint32)packet_buffer_size); + packet->length(0); + if (!thd->semi_sync_slave) { + packet->append("\0", 1); + } else { + /* Set the magic number and the sync status. By default, no sync + * is required. + */ + packet->append(kSyncHeader, sizeof(kSyncHeader)); + } + function_exit(kWho, 0); +} + +int ReplSemiSync::updateSyncHeader(String *packet, + const char *log_file_name, + my_off_t log_file_pos, + THD *thd, + bool *sync, + Log_event_type *event_type) { + const char *kWho = "ReplSemiSync::updateSyncHeader"; + int cmp = 0; + + /* If the semi-sync master is not enabled, or the slave is not a semi-sync + * target, do not request replies from the slave. + */ + if (!getMasterEnabled() || !thd->semi_sync_slave) { + *sync = false; + *event_type = (Log_event_type)((*packet)[LOG_EVENT_OFFSET+1]); + return 0; + } + + function_enter(kWho); + + lock(); + + /* This is the real check inside the mutex. */ + if (!getMasterEnabled()) { + *sync = false; + goto l_end; + } + + if (is_on()) { /* semi-sync is ON */ + *sync = false; /* No sync unless a transaction is involved. */ + + if (reply_file_name_inited_) { + cmp = ActiveTranx::compare(log_file_name, log_file_pos, + reply_file_name_, reply_file_pos_); + if (cmp <= 0) { + /* If we have already got the reply for the event, then we do + * not need to sync the transaction again. + */ + cmp = -1; + } + } + + if (cmp >= 0) { + if (wait_file_name_inited_) { + cmp = ActiveTranx::compare(log_file_name, log_file_pos, + wait_file_name_, wait_file_pos_); + } else { + cmp = 1; + } + + if (cmp >= 0) { + /* We are going to send an event which has not reached the final + * commit point inside InnoDB. + * We need the reply from the slave because soon the transaction + * should wait for the reply when it reaches the end of the + * commit. + * + * We only wait if the event is a transaction's ending event. + */ + DBUG_ASSERT(active_tranxs_ != NULL); + *sync = active_tranxs_->is_tranx_end_pos(log_file_name, + log_file_pos); + } else { + /* If we are already waiting for some transaction replies which + * are later in binlog, do not wait for this one event. + */ + } + } + } else { /* semi-sync is OFF */ + /* Check to see whether we can switch semi-sync ON. */ + try_switch_on(thd->server_id, log_file_name, log_file_pos); + + /* We must request sync reply for the current event no matter whether it + * is the end of a transaction. + * Here is the problematic situation: + * . writeTranxInBinlog(): update commit_file_* base on transaction-A + * . updateSyncHeader(): switch on semi-sync replication + * . commitTrx(): we would wait until timeout for transaction-A for + * which binlog_dump thread never requests replies + * + * Also, it is advantageous that we update commit_file_* inside function + * writeTranxInBinlog(). Because commit_file_* indicates the last + * transaction in binlog and the current event must be equal or behind + * the last transaction, a reply to the current event from the slave + * can clear all older transactions' syncness. + */ + *sync = is_on(); + } + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: server(%d), (%s, %lu) sync(%d), repl(%d)", + kWho, thd->server_id, log_file_name, + (ulong)log_file_pos, *sync, (int)is_on()); + + l_end: + unlock(); + + /* We do not need to clear sync flag because we set it to 0 when we + * reserve the packet header. + */ + if (*sync) + (packet->c_ptr())[2] = kPacketFlagSync; + + *event_type = (Log_event_type)((*packet)[LOG_EVENT_OFFSET+3]); + return function_exit(kWho, 0); +} + +int ReplSemiSync::readSlaveReply(THD *thd, NET *net, + const char **read_errmsg, + int *read_errno) { + const char *kWho = "ReplSemiSync::readSlaveReply"; + const unsigned char *packet; + char log_file_name[FN_REFLEN]; + my_off_t log_file_pos; + ulong packet_len; + int result = -1; + + struct timeval start_tv; + int start_time_err; + ulong trc_level = trace_level_; + + function_enter(kWho); + + if (trc_level & kTraceNetWait) + start_time_err = gettimeofday(&start_tv, 0); + + /* We flush to make sure that the current event is sent to the network, + * instead of being buffered in the TCP/IP stack. + */ + if (net_flush(net)) { + *read_errmsg = "failed on net_flush()"; + *read_errno = ER_UNKNOWN_ERROR; + goto l_end; + } + + if (trc_level & kTraceDetail) + sql_print_information("%s: Wait for replica's reply", kWho); + + /* Wait for the network here. Though binlog dump thread can indefinitely wait + * here, transactions would not wait indefintely. + * Transactions wait on binlog replies detected by binlog dump threads. If + * binlog dump threads wait too long, transactions will timeout and continue. + */ + packet_len = my_net_read(net); + + if (trc_level & kTraceNetWait) { + if (start_time_err != 0) { + sql_print_error("Network wait gettimeofday fail1"); + timefunc_fails_++; + } else { + int wait_time; + + wait_time = getWaitTime(start_tv); + if (wait_time < 0) { + sql_print_error("Network wait gettimeofday fail2"); + timefunc_fails_++; + } else { + total_net_wait_num_++; + total_net_wait_time_ += wait_time; + } + } + } + + if (packet_len == packet_error || packet_len < 10) { + if (packet_len == packet_error) + *read_errmsg = "Read semi-sync reply network error"; + else + *read_errmsg = "Read semi-sync reply length error"; + *read_errno = ER_UNKNOWN_ERROR; + goto l_end; + } + + packet = net->read_pos; + if (packet[0] != ReplSemiSync::kPacketMagicNum || + packet[9] != ReplSemiSync::kPacketMagicNum) { + *read_errmsg = "Read semi-sync reply magic number error"; + *read_errno = ER_UNKNOWN_ERROR; + goto l_end; + } + + log_file_pos = uint8korr(packet + 1); + strcpy(log_file_name, (const char*)packet + 10); + + if (trc_level & kTraceDetail) + sql_print_information("%s: Got reply (%s, %lu)", + kWho, log_file_name, (ulong)log_file_pos); + + result = reportReplyBinlog(thd, log_file_name, log_file_pos); + + l_end: + return function_exit(kWho, result); +} + +int ReplSemiSync::writeTranxInBinlog(const char* log_file_name, + my_off_t log_file_pos) { + const char *kWho = "ReplSemiSync::writeTranxInBinlog"; + int result = 0; + + function_enter(kWho); + + lock(); + + /* This is the real check inside the mutex. */ + if (!getMasterEnabled()) + goto l_end; + + /* Update the 'largest' transaction commit position seen so far even + * though semi-sync is switched off. + * It is much better that we update commit_file_* here, instead of + * inside commitTrx(). This is mostly because updateSyncHeader() + * will watch for commit_file_* to decide whether to switch semi-sync + * on. The detailed reason is explained in function updateSyncHeader(). + */ + if (commit_file_name_inited_) { + int cmp = ActiveTranx::compare(log_file_name, log_file_pos, + commit_file_name_, commit_file_pos_); + if (cmp > 0) { + /* This is a larger position, let's update the maximum info. */ + strcpy(commit_file_name_, log_file_name); + commit_file_pos_ = log_file_pos; + } + } else { + strcpy(commit_file_name_, log_file_name); + commit_file_pos_ = log_file_pos; + commit_file_name_inited_ = true; + } + + if (is_on()) { + DBUG_ASSERT(active_tranxs_ != NULL); + result = active_tranxs_->insert_tranx_node(log_file_name, log_file_pos); + } + + l_end: + unlock(); + + return function_exit(kWho, result); +} + +int ReplSemiSync::slaveReadSyncHeader(const char *header, + ulong total_len, + bool *need_reply, + const char **payload, + ulong *payload_len) { + const char *kWho = "ReplSemiSync::slaveReadSyncHeader"; + int read_res = 0; + function_enter(kWho); + + if ((unsigned char)(header[0]) == kPacketMagicNum) { + *need_reply = (header[1] & kPacketFlagSync); + *payload_len = total_len - 2; + *payload = header + 2; + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: reply - %d", kWho, *need_reply); + } else { + sql_print_error("Missing magic number for semi-sync packet, packet " + "len: %d", total_len); + read_res = -1; + } + + return function_exit(kWho, read_res); +} + +int ReplSemiSync::slaveReply(NET *net, + const char *binlog_filename, + my_off_t binlog_filepos) { + const char *kWho = "ReplSemiSync::slaveReply"; + char reply_buffer[1+8+1+FN_REFLEN]; + int reply_res, name_len = strlen(binlog_filename); + + function_enter(kWho); + + /* Prepare the buffer of the reply. */ + reply_buffer[0] = kPacketMagicNum; + int8store(reply_buffer + 1, binlog_filepos); + reply_buffer[9] = kPacketMagicNum; + memcpy(reply_buffer + 10, binlog_filename, name_len); + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: reply (%s, %lu)", kWho, + binlog_filename, (ulong)binlog_filepos); + + /* Send the reply. */ + reply_res = my_net_write(net, reply_buffer, name_len + 10); + if (reply_res == 0) + reply_res = net_flush(net); + + return function_exit(kWho, reply_res); +} + +void ReplSemiSync::setExportStats() { + VOID(pthread_mutex_lock(&LOCK_status)); + lock(); + + rpl_semi_sync_status = state_ ? 1 : 0; + rpl_semi_sync_yes_transactions = enabled_transactions_; + rpl_semi_sync_no_transactions = disabled_transactions_; + rpl_semi_sync_off_times = switched_off_times_; + rpl_semi_sync_timefunc_fails = timefunc_fails_; + rpl_semi_sync_num_timeouts = total_wait_timeouts_; + rpl_semi_sync_wait_sessions = wait_sessions_; + rpl_semi_sync_back_wait_pos = wait_backtraverse_; + rpl_semi_sync_trx_wait_num = total_trx_wait_num_; + rpl_semi_sync_trx_wait_time = + ((total_trx_wait_num_) ? + (ulong)((double)total_trx_wait_time_ / + ((double)total_trx_wait_num_)) : 0); + rpl_semi_sync_net_wait_num = total_net_wait_num_; + rpl_semi_sync_net_wait_time = + ((total_net_wait_num_) ? + (ulong)((double)total_net_wait_time_ / + ((double)total_net_wait_num_)) : 0); + + rpl_semi_sync_net_wait_total_time = total_net_wait_time_; + rpl_semi_sync_trx_wait_total_time = total_trx_wait_time_; + + unlock(); + VOID(pthread_mutex_unlock(&LOCK_status)); +} + +/* Get the waiting time given the wait's staring time. + * + * Return: + * >= 0: the waiting time in microsecons(us) + * < 0: error in gettimeofday or time back traverse + */ +static int getWaitTime(const struct timeval& start_tv) { + ulonglong start_usecs, end_usecs; + struct timeval end_tv; + int end_time_err; + + /* Starting time in microseconds(us). */ + start_usecs = start_tv.tv_sec * TIME_MILLION + start_tv.tv_usec; + + /* Get the wait time interval. */ + end_time_err = gettimeofday(&end_tv, 0); + + /* Ending time in microseconds(us). */ + end_usecs = end_tv.tv_sec * TIME_MILLION + end_tv.tv_usec; + + if (end_time_err != 0 || end_usecs < start_usecs) + return -1; + + return (int)(end_usecs - start_usecs); +} diff -ruN base/sql/repl_semi_sync.h mysql40gpl/sql/repl_semi_sync.h --- base/sql/repl_semi_sync.h 1969-12-31 16:00:00.000000000 -0800 +++ mysql40gpl/sql/repl_semi_sync.h 2007-04-21 11:18:39.000000000 -0700 @@ -0,0 +1,446 @@ +/* Copyright (C) 2007 Google Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/* + * ReplSemiSync class is reponsible for semi synchronous replication. The + * general idea of semi-sync replication is the master database need to make + * sure that the slave database receives its replication events before telling + * the client that a transaction has been committed. The difference between + * semi-sync and full-sync is that full-sync replication requires that the + * slave database finish replicated transaction before replying the master. + * + * The current semi-sync implementation defines a transaction wait timeout. + * In this way, the master would not wait for the slave/replica indefinitely; + * instead after a configurable timeout, the master will continue the current + * transaction. At the same time, semi-sync will be disabled so that no + * transactions will wait after this. Later, semi-sync can be enabled again + * when the slave catches up in replication. The timeout design is to prevent + * the master from halting for update, in case of the slave machine issues or + * network issues. + * + * We export three status variables to track the semi-sync on the master: + * . "Replication_semi_sync_status": rpl_semi_sync_status + * . "Replication_semi_sync_yes_transactions": rpl_semi_sync_yes_transactions + * . "Replication_semi_sync_no_transactions": rpl_semi_sync_no_transactions + * + * This class has codes for both the master and the slave/replica side. + * However, the slave/replica side is relatively lightweight because the slave + * is mostly stateless reply of binlog events sent from the master. + * + * The master side code flow: + * . session/thread with a commit transaction: + * - write all events for the current transaction to binlog + * - call writeTraxInBinlog() + * - call commitTrx() during InnoDB's final commit action + * - InnoDB commits and returns 'ok' to the client + * . binlog-dump session/thread - + * - connection from slave to dump binlog events + * - call reportReplyBinlog() to report the slave's position + * - while (true): + * - call reserveSyncHeader() to create header for the next event + * - read the event from binlog + * - call updateSyncHeader() to indicate whether slave should reply + * - call readSlaveReply() to wait for slave's reply + * + * The slave side code flow - : + * - sync_status = call readSyncHeader() + * - if (sync_status): + * - call slaveReply() + */ + +#ifndef REPL_SEMI_SYNC_H__ +#define REPL_SEMI_SYNC_H__ + +class THD; +class String; +typedef struct st_net NET; +enum Log_event_type; + +class ReplSemiSync { + private: + + /* This class manages memory for active transaction list. We record each + * active transaction with a TranxNode. Because each session can only have + * only one open transaction, the total active transaction nodes can not + * exceed the maximum sessions. Currently in MySQL, sessions are the same + * as connections. + */ + class ActiveTranx { + private: + struct TranxNode { + char *log_name_; + my_off_t log_pos_; + struct TranxNode *next_; /* the next node in the sorted list */ + struct TranxNode *hash_next_; /* the next node during hash collision */ + }; + + /* The following data structure maintains an active transaction list. */ + TranxNode *node_array_; + TranxNode *free_pool_; + + /* These two record the active transaction list in sort order. */ + TranxNode *trx_front_, *trx_rear_; + + TranxNode **trx_htb_; /* A hash table on active transactions. */ + + int num_transactions_; /* maximum transactions */ + int num_entries_; /* maximum hash table entries */ + pthread_mutex_t *lock_; /* mutex lock */ + ulong *trace_level_; /* trace level */ + + inline void assert_lock_owner(); + inline void function_enter(const char *func_name); + inline int function_exit(const char *func_name, int exit_code); + + inline TranxNode* alloc_tranx_node(); + + inline uint calc_hash(const byte *key,uint length); + uint get_hash_value(const char *log_file_name, my_off_t log_file_pos); + + int compare(const char *log_file_name1, my_off_t log_file_pos1, + const TranxNode *node2) { + return compare(log_file_name1, log_file_pos1, + node2->log_name_, node2->log_pos_); + } + int compare(const TranxNode *node1, + const char *log_file_name2, my_off_t log_file_pos2) { + return compare(node1->log_name_, node1->log_pos_, + log_file_name2, log_file_pos2); + } + int compare(const TranxNode *node1, const TranxNode *node2) { + return compare(node1->log_name_, node1->log_pos_, + node2->log_name_, node2->log_pos_); + } + + public: + ActiveTranx(int max_connections, pthread_mutex_t *lock, + ulong *trace_level); + ~ActiveTranx(); + + /* Insert an active transaction node with the specified position. + * + * Return: + * 0: success; -1 or otherwise: error + */ + int insert_tranx_node(const char *log_file_name, my_off_t log_file_pos); + + /* Clear the active transaction nodes until(inclusive) the specified + * position. + * If log_file_name is NULL, everything will be cleared: the sorted + * list and the hash table will be reset to empty. + * + * Return: + * 0: success; -1 or otherwise: error + */ + int clear_active_tranx_nodes(const char *log_file_name, + my_off_t log_file_pos); + + /* Given a position, check to see whether the position is an active + * transaction's ending position by probing the hash table. + */ + bool is_tranx_end_pos(const char *log_file_name, my_off_t log_file_pos); + + /* Given two binlog positions, compare which one is bigger based on + * (file_name, file_position). + */ + static int compare(const char *log_file_name1, my_off_t log_file_pos1, + const char *log_file_name2, my_off_t log_file_pos2); + + }; + + ActiveTranx *active_tranxs_; /* active transaction list: the list will + be cleared when semi-sync switches off. */ + + /* This cond variable is signaled when enough binlog has been sent to slave, + * so that a waiting trx can return the 'ok' to the client for a commit. + */ + pthread_cond_t COND_binlog_send_; + + /* Mutex that protects the following state variables and the active + * transaction list. + * Under no cirumstances we can acquire mysql_bin_log.LOCK_log if we are + * already holding LOCK_binlog_ because it can cause deadlocks. + */ + pthread_mutex_t LOCK_binlog_; + + /* This is set to true when reply_file_name_ contains meaningful data. */ + bool reply_file_name_inited_; + + /* The binlog name up to which we have received replies from any slaves. */ + char reply_file_name_[FN_REFLEN]; + + /* The position in that file up to which we have the reply from any slaves. */ + my_off_t reply_file_pos_; + + /* This is set to true when we know the 'smallest' wait position. */ + bool wait_file_name_inited_; + + /* NULL, or the 'smallest' filename that a transaction is waiting for + * slave replies. + */ + char wait_file_name_[FN_REFLEN]; + + /* The smallest position in that file that a trx is waiting for: the trx + * can proceed and send an 'ok' to the client when the master has got the + * reply from the slave indicating that it already got the binlog events. + */ + my_off_t wait_file_pos_; + + /* This is set to true when we know the 'largest' transaction commit + * position in the binlog file. + * We always maintain the position no matter whether semi-sync is switched + * on switched off. When a transaction wait timeout occurs, semi-sync will + * switch off. Binlog-dump thread can use the three fields to detect when + * slaves catch up on replication so that semi-sync can switch on again. + */ + bool commit_file_name_inited_; + + /* The 'largest' binlog filename that a commit transaction is seeing. */ + char commit_file_name_[FN_REFLEN]; + + /* The 'largest' position in that file that a commit transaction is seeing. */ + my_off_t commit_file_pos_; + + /* All global variables which can be set by parameters. */ + bool master_enabled_; /* semi-sync is enabled on the master */ + bool slave_enabled_; /* semi-sycn is enabled on the slave */ + ulong wait_timeout_; /* timeout period(ms) during tranx wait */ + ulong trace_level_; /* the level for tracing */ + + /* All status variables. */ + bool state_; /* whether semi-sync is switched */ + ulong enabled_transactions_; /* semi-sync'ed tansactions */ + ulong disabled_transactions_; /* non-semi-sync'ed tansactions */ + ulong switched_off_times_; /* how many times are switched off? */ + ulong timefunc_fails_; /* how many time function fails? */ + ulong total_wait_timeouts_; /* total number of wait timeouts */ + ulong wait_sessions_; /* how many sessions wait for replies? */ + ulong wait_backtraverse_; /* wait position back traverses */ + ulonglong total_trx_wait_num_; /* total trx waits: non-timeout ones */ + ulonglong total_trx_wait_time_; /* total trx wait time: in us */ + ulonglong total_net_wait_num_; /* total network waits */ + ulonglong total_net_wait_time_; /* total network wait time */ + + /* The number of maximum active transactions. This should be the same as + * maximum connections because MySQL does not do connection sharing now. + */ + int max_transactions_; + + static const ulong kTraceFunction; + static const ulong kTraceGeneral; + static const ulong kTraceDetail; + static const ulong kTraceNetWait; + + static const char kSyncHeader[3]; /* three byte packet header */ + + void lock(); + void unlock(); + void cond_broadcast(); + int cond_timewait(struct timespec *wait_time); + + inline void function_enter(const char *func_name); + inline int function_exit(const char *func_name, int exit_code); + + /* Is semi-sync replication on? */ + bool is_on() { + return (state_); + } + + void set_master_enabled(bool enabled) { + master_enabled_ = enabled; + } + + /* Switch semi-sync off because of timeout in transaction waiting. */ + int switch_off(); + + /* Switch semi-sync on when slaves catch up. */ + int try_switch_on(int server_id, + const char *log_file_name, my_off_t log_file_pos); + + public: + ReplSemiSync(); + ~ReplSemiSync(); + + /* Constants in network packet header. */ + static const unsigned char kPacketMagicNum; + static const unsigned char kPacketFlagSync; + + bool getMasterEnabled() { + return master_enabled_; + } + bool getSlaveEnabled() { + return slave_enabled_; + } + void setSlaveEnabled(bool enabled) { + slave_enabled_ = enabled; + } + + void setTraceLevel(ulong trace_level) { + trace_level_ = trace_level; + } + + /* Set the transaction wait timeout period, in milliseconds. */ + void setWaitTimeout(ulong wait_timeout) { + wait_timeout_ = wait_timeout; + } + + /* Initialize this class after MySQL parameters are initialized. this + * function should be called once at bootstrap time. + */ + int initObject(); + + /* Enable the object to enable semi-sync replication inside the master. */ + int enableMaster(); + + /* Enable the object to enable semi-sync replication inside the master. */ + int disableMaster(); + + /* In semi-sync replication, reports up to which binlog position we have + * received replies from the slave indicating that it already get the events. + * + * Input: + * thd - (IN) binlog-dump thread doing the binlog communication + * to the slave + * log_file_name - (IN) binlog file name + * end_offset - (IN) the offset in the binlog file up to which we have + * the replies from the slave + * + * Return: + * 0: success; -1 or otherwise: error + */ + int reportReplyBinlog(THD* thd, char* log_file_name, + my_off_t end_offset); + + /* Commit a transaction in the final step. This function is called from + * InnoDB before returning from the low commit. If semi-sync is switch on, + * the function will wait to see whether binlog-dump thread get the reply for + * the events of the transaction. Remember that this is not a direct wait, + * instead, it waits to see whether the binlog-dump thread has reached the + * point. If the wait times out, semi-sync status will be switched off and + * all other transaction would not wait either. + * + * Input: (the transaction events' ending binlog position) + * trx_wait_binlog_name - (IN) ending position's file name + * trx_wait_binlog_pos - (IN) ending position's file offset + * + * Return: + * 0: success; -1 or otherwise: error + */ + int commitTrx(const char* trx_wait_binlog_name, + my_off_t trx_wait_binlog_pos); + + /* Reserve spaces in the replication event packet header: + * . slave semi-sync off: 1 byte - (0) + * . slave semi-sync on: 3 byte - (0, 0xef, 0/1} + * + * Input: + * packet - (IN) the packet containing the replication event + * thd - (IN) the binlog dump thread + * packet_buffer - (IN) the packet's initial buffer + * packet_buffer_size - (IN) the size of the initial buffer + * + * Return: + * 0: success; -1 or otherwise: error + */ + void reserveSyncHeader(String *packet, THD *thd, + char *packet_buffer, ulong packet_buffer_size); + + /* Update the sync bit in the packet header to indicate to the slave whether + * the master will wait for the reply of the event. If semi-sync is switched + * off and we detect that the slave is catching up, we switch semi-sync on. + * + * Input: + * packet - (IN) the packet containing the replication event + * log_file_name - (IN) the event ending position's file name + * log_file_pos - (IN) the event ending position's file offset + * thd - (IN) the binlog dump thread + * sync - (OUT) whether the sync bit is set + * event_type - (OUT) the sending event's type + * + * Return: + * 0: success; -1 or otherwise: error + */ + int updateSyncHeader(String *packet, + const char *log_file_name, my_off_t log_file_pos, + THD *thd, bool *sync, Log_event_type *event_type); + + /* Read the slave's reply so that we know how much progress the slave makes + * on receive replication events. + * + * Input: + * thd - (IN) binlog dump replication thread + * net - (IN) the network socket + * read_errmsg - (OUT) error message if an error occurs + * read_errno - (OUT) error number if an error occurs + * + * Return: + * 0: success; -1 or otherwise: error + */ + int readSlaveReply(THD *thd, NET *net, const char **read_errmsg, + int *read_errno); + + /* Called when a transaction finished writing binlog events. + * . update the 'largest' transactions' binlog event position + * . insert the ending position in the active transaction list if + * semi-sync is on + * + * Input: (the transaction events' ending binlog position) + * log_file_name - (IN) transaction ending position's file name + * log_file_pos - (IN) transaction ending position's file offset + * + * Return: + * 0: success; -1 or otherwise: error + */ + int writeTranxInBinlog(const char* log_file_name, my_off_t log_file_pos); + + /* A slave reads the semi-sync packet header and separate the metadata + * from the payload data. + * + * Input: + * header - (IN) packet header pointer + * total_len - (IN) total packet length: metadata + payload + * need_reply - (IN) whether the master is waiting for the reply + * payload - (IN) payload: the replication event + * payload_len - (IN) payload length + * + * Return: + * 0: success; -1 or otherwise: error + */ + int slaveReadSyncHeader(const char *header, ulong total_len, bool *need_reply, + const char **payload, ulong *payload_len); + + /* A slave replies to the master indicating its replication process. It + * indicates that the slave has received all events before the specified + * binlog position. + * + * Input: + * net - (IN) the network socket + * binlog_filename - (IN) the reply point's binlog file name + * binlog_filepos - (IN) the reply point's binlog file offset + * + * Return: + * 0: success; -1 or otherwise: error + */ + int slaveReply(NET *net, const char *binlog_filename, + my_off_t binlog_filepos); + + /* Export internal statistics for semi-sync replication. */ + void setExportStats(); + +}; + +#endif /* REPL_SEMI_SYNC_H__ */ diff -ruN base/sql/set_var.cc mysql40gpl/sql/set_var.cc --- base/sql/set_var.cc 2005-09-02 15:37:56.000000000 -0700 +++ mysql40gpl/sql/set_var.cc 2007-04-21 11:07:21.000000000 -0700 @@ -55,6 +55,10 @@ #ifdef HAVE_INNOBASE_DB #include "ha_innodb.h" #endif +#include "repl_semi_sync.h" + +extern ReplSemiSync semi_sync_replicator; +extern my_bool rpl_mirror_binlog_no_replicate; static HASH system_variable_hash; const char *bool_type_names[]= { "OFF", "ON", NullS }; @@ -76,6 +80,7 @@ static bool set_option_autocommit(THD *thd, set_var *var); static bool set_log_update(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 void fix_net_read_timeout(THD *thd, enum_var_type type); static void fix_net_write_timeout(THD *thd, enum_var_type type); @@ -86,6 +91,9 @@ static void fix_myisam_max_extra_sort_file_size(THD *thd, enum_var_type type); static void fix_myisam_max_sort_file_size(THD *thd, enum_var_type type); static void fix_max_binlog_size(THD *thd, enum_var_type type); +static void fix_rpl_semi_sync_trace_level(THD *thd, enum_var_type type); +static void fix_rpl_semi_sync_enabled(THD *thd, enum_var_type type); +static void fix_rpl_semi_sync_slave_enabled(THD *thd, enum_var_type type); static void fix_max_relay_log_size(THD *thd, enum_var_type type); static void fix_max_connections(THD *thd, enum_var_type type); static void fix_thd_mem_root(THD *thd, enum_var_type type); @@ -134,8 +142,8 @@ sys_var_bool_ptr sys_local_infile("local_infile", &opt_local_infile); sys_var_thd_ulong sys_log_warnings("log_warnings", &SV::log_warnings); -sys_var_thd_ulong sys_long_query_time("long_query_time", - &SV::long_query_time); +sys_var_long_ptr sys_long_query_time("long_query_time", + &long_query_time); sys_var_thd_bool sys_low_priority_updates("low_priority_updates", &SV::low_priority_updates, fix_low_priority_updates); @@ -205,14 +213,40 @@ sys_var_bool_ptr sys_readonly("read_only", &opt_readonly); sys_var_thd_ulong sys_read_rnd_buff_size("read_rnd_buffer_size", &SV::read_rnd_buff_size); +sys_var_bool_ptr sys_rpl_always_enter_innodb("rpl_always_enter_innodb", + &rpl_always_enter_innodb); sys_var_long_ptr sys_rpl_recovery_rank("rpl_recovery_rank", &rpl_recovery_rank); +sys_var_bool_ptr sys_rpl_mirror_binlog_enabled( + "rpl_mirror_binlog_enabled", + &rpl_mirror_binlog_enabled); +sys_var_bool_ptr sys_rpl_mirror_binlog_no_replicate( + "rpl_mirror_binlog_no_replicate", + &rpl_mirror_binlog_no_replicate); +sys_var_long_ptr sys_rpl_semi_sync_enabled("rpl_semi_sync_enabled", + &rpl_semi_sync_enabled, + fix_rpl_semi_sync_enabled); +sys_var_long_ptr sys_rpl_semi_sync_slave_enabled( + "rpl_semi_sync_slave_enabled", + &rpl_semi_sync_slave_enabled, + fix_rpl_semi_sync_slave_enabled); +sys_var_long_ptr sys_rpl_semi_sync_timeout( + "rpl_semi_sync_timeout", + &rpl_semi_sync_timeout); +sys_var_long_ptr sys_rpl_semi_sync_trace_level( + "rpl_semi_sync_trace_level", + &rpl_semi_sync_trace_level, + fix_rpl_semi_sync_trace_level); +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); sys_var_thd_ulong sys_range_alloc_block_size("range_alloc_block_size", &SV::range_alloc_block_size); +sys_var_long_ptr sys_reserved_super_connections("reserved_super_connections", + &reserved_super_connections); sys_var_thd_ulong sys_query_alloc_block_size("query_alloc_block_size", &SV::query_alloc_block_size, fix_thd_mem_root); @@ -225,6 +259,11 @@ sys_var_thd_ulong sys_trans_prealloc_size("transaction_prealloc_size", &SV::trans_prealloc_size, fix_trans_mem_root); +sys_var_sync_binlog_period sys_sync_binlog_period("sync_binlog", + &sync_binlog_period); +sys_var_long_ptr sys_sync_mirror_binlog_period( + "sync_mirror_binlog_period", + &sync_mirror_binlog_period); #ifdef HAVE_QUERY_CACHE sys_var_long_ptr sys_query_cache_limit("query_cache_limit", @@ -261,12 +300,18 @@ &SV::net_wait_timeout); #ifdef HAVE_INNOBASE_DB +sys_var_long_ptr sys_innodb_btr_estimate_n_pages("innodb_btr_estimate_n_pages", + &btr_key_val_estimate_n_pages); sys_var_long_ptr sys_innodb_max_dirty_pages_pct("innodb_max_dirty_pages_pct", &srv_max_buf_pool_modified_pct); sys_var_long_ptr sys_innodb_max_purge_lag("innodb_max_purge_lag", &srv_max_purge_lag); 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_thd_bool sys_innodb_table_locks("innodb_table_locks", &SV::innodb_table_locks); #endif @@ -430,7 +475,16 @@ &sys_range_alloc_block_size, &sys_read_buff_size, &sys_read_rnd_buff_size, + &sys_reserved_super_connections, + &sys_rpl_always_enter_innodb, &sys_rpl_recovery_rank, + &sys_rpl_mirror_binlog_enabled, + &sys_rpl_mirror_binlog_no_replicate, + &sys_rpl_semi_sync_enabled, + &sys_rpl_semi_sync_slave_enabled, + &sys_rpl_semi_sync_timeout, + &sys_rpl_semi_sync_trace_level, + &sys_rpl_transaction_enabled, &sys_safe_updates, &sys_select_limit, &sys_server_id, @@ -444,6 +498,8 @@ &sys_sql_low_priority_updates, &sys_sql_max_join_size, &sys_sql_warnings, + &sys_sync_binlog_period, + &sys_sync_mirror_binlog_period, &sys_table_cache_size, &sys_table_type, &sys_thread_cache_size, @@ -454,10 +510,12 @@ &sys_tx_isolation, &sys_os, #ifdef HAVE_INNOBASE_DB + &sys_innodb_btr_estimate_n_pages, &sys_innodb_max_dirty_pages_pct, &sys_innodb_max_purge_lag, &sys_innodb_autoextend_increment, &sys_innodb_table_locks, + &sys_innodb_clear_replication_status, #endif &sys_unique_checks }; @@ -512,7 +570,10 @@ #ifdef HAVE_INNOBASE_DB {"innodb_additional_mem_pool_size", (char*) &innobase_additional_mem_pool_size, SHOW_LONG }, {sys_innodb_autoextend_increment.name, (char*) &sys_innodb_autoextend_increment, SHOW_SYS}, + {sys_innodb_btr_estimate_n_pages.name, (char*) &sys_innodb_btr_estimate_n_pages, SHOW_SYS}, {"innodb_buffer_pool_size", (char*) &innobase_buffer_pool_size, SHOW_LONG }, + {sys_innodb_clear_replication_status.name, + (char*) &sys_innodb_clear_replication_status, SHOW_SYS}, {"innodb_data_file_path", (char*) &innobase_data_file_path, SHOW_CHAR_PTR}, {"innodb_data_home_dir", (char*) &innobase_data_home_dir, SHOW_CHAR_PTR}, {"innodb_fast_shutdown", (char*) &innobase_fast_shutdown, SHOW_MY_BOOL}, @@ -532,6 +593,10 @@ {"innodb_mirrored_log_groups", (char*) &innobase_mirrored_log_groups, SHOW_LONG}, {sys_innodb_table_locks.name, (char*) &sys_innodb_table_locks, SHOW_SYS}, {"innodb_thread_concurrency", (char*) &innobase_thread_concurrency, SHOW_LONG }, + {"innodb_no_share_locks_on_dml_select", (char*) &innodb_no_share_locks_on_dml_select, SHOW_BOOL}, + {"innodb_read_io_threads", (char*) &innobase_read_io_threads, SHOW_LONG }, + {"innodb_write_io_threads", (char*) &innobase_write_io_threads, SHOW_LONG }, + {"innodb_max_merged_io", (char*) &innobase_max_merged_io, SHOW_LONG}, #endif {sys_interactive_timeout.name,(char*) &sys_interactive_timeout, SHOW_SYS}, {sys_join_buffer_size.name, (char*) &sys_join_buffer_size, SHOW_SYS}, @@ -548,7 +613,7 @@ {"log_error", (char*) log_error_file, SHOW_CHAR}, {"log_slave_updates", (char*) &opt_log_slave_updates, SHOW_MY_BOOL}, {"log_slow_queries", (char*) &opt_slow_log, SHOW_BOOL}, - {"log_update", (char*) &opt_update_log, SHOW_BOOL}, + {"log_update", (char*) &opt_dml_log, SHOW_BOOL}, {sys_log_warnings.name, (char*) &sys_log_warnings, SHOW_SYS}, {sys_long_query_time.name, (char*) &sys_long_query_time, SHOW_SYS}, {sys_low_priority_updates.name, (char*) &sys_low_priority_updates, SHOW_SYS}, @@ -606,7 +671,25 @@ {sys_read_buff_size.name, (char*) &sys_read_buff_size, SHOW_SYS}, {sys_readonly.name, (char*) &sys_readonly, SHOW_SYS}, {sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS}, + {sys_reserved_super_connections.name,(char*) &sys_reserved_super_connections, SHOW_SYS}, + {sys_rpl_always_enter_innodb.name, + (char *) &sys_rpl_always_enter_innodb, SHOW_SYS}, {sys_rpl_recovery_rank.name,(char*) &sys_rpl_recovery_rank, SHOW_SYS}, + {sys_rpl_mirror_binlog_enabled.name, + (char *) &sys_rpl_mirror_binlog_enabled, SHOW_SYS}, + {sys_rpl_mirror_binlog_no_replicate.name, + (char *) &sys_rpl_mirror_binlog_no_replicate, SHOW_SYS}, + {sys_rpl_semi_sync_enabled.name, + (char *) &sys_rpl_semi_sync_enabled, SHOW_SYS}, + {sys_rpl_semi_sync_slave_enabled.name, + (char *) &sys_rpl_semi_sync_slave_enabled, SHOW_SYS}, + {sys_rpl_semi_sync_timeout.name, + (char *) &sys_rpl_semi_sync_timeout, SHOW_SYS}, + {sys_rpl_semi_sync_trace_level.name, + (char *) &sys_rpl_semi_sync_trace_level, SHOW_SYS}, + {sys_rpl_transaction_enabled.name, + (char *) &sys_rpl_transaction_enabled, SHOW_SYS}, + {"server_hostname", (char*) glob_hostname, SHOW_CHAR}, {sys_server_id.name, (char*) &sys_server_id, SHOW_SYS}, {"skip_external_locking", (char*) &my_disable_locking, SHOW_MY_BOOL}, {"skip_networking", (char*) &opt_disable_networking, SHOW_BOOL}, @@ -618,6 +701,9 @@ #endif {sys_sort_buffer.name, (char*) &sys_sort_buffer, SHOW_SYS}, {"sql_mode", (char*) &opt_sql_mode, SHOW_LONG}, + {sys_sync_binlog_period.name,(char*) &sys_sync_binlog_period, SHOW_SYS}, + {sys_sync_mirror_binlog_period.name, + (char *) &sys_sync_mirror_binlog_period, SHOW_SYS}, {"table_cache", (char*) &table_cache_size, SHOW_LONG}, {sys_table_type.name, (char*) &sys_table_type, SHOW_SYS}, {sys_thread_cache_size.name,(char*) &sys_thread_cache_size, SHOW_SYS}, @@ -679,6 +765,13 @@ 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_extra_sort_file_size(THD *thd, enum_var_type type) @@ -789,6 +882,45 @@ DBUG_VOID_RETURN; } +static void fix_rpl_semi_sync_trace_level(THD *thd, enum_var_type type) +{ + DBUG_ENTER("fix_rpl_semi_sync_trace_level"); + + DBUG_PRINT("info",("rpl_semi_sync_trace_level=%lu", + rpl_semi_sync_trace_lev