mirror of
https://github.com/MariaDB/server.git
synced 2026-04-24 09:15:30 +02:00
slave-skip-errors
added extra/mysql_install.c - will work on it in 4.0, but it does not hurt to have it sit in 3.23 tree for now since it will eventually be backported to 3.23 anyway Docs/manual.texi: documented slave-skip-errors updated change history extra/resolve_stack_dump.c: fixed wrong help message include/my_bitmap.h: bitmap code updates mysql-test/r/rpl_get_lock.result: test for a possible bug in release_lock() replication mysql-test/t/rpl_get_lock.test: test for possible bug in release_lock replication mysys/my_bitmap.c: bitmap code updates/clean-up sql/mysqld.cc: slave-skip-errors sql/slave.cc: slave-skip-errors sql/slave.h: slave skip errors
This commit is contained in:
parent
b9562004e9
commit
623eedda26
13 changed files with 245 additions and 15 deletions
|
|
@ -23738,6 +23738,33 @@ Updates to a database with a different name than the original
|
|||
|
||||
Example: @code{replicate-rewrite-db=master_db_name->slave_db_name}.
|
||||
|
||||
@item @code{slave-skip-errors=err_code1,err_code2,..} @tab
|
||||
Available only in 3.23.47 and later. Tells the slave thread to continue
|
||||
replication when a query returns an error from the provided
|
||||
list. Normally, replication will discontinue when an error is
|
||||
encountered giving the user a chance to resolve the inconsistency in the
|
||||
data manually. Do not use this option unless you fully understand why
|
||||
you are getting the errors. If there are no bugs in your
|
||||
replication setup and client programs, and no bugs in MySQL itself, you
|
||||
should never get an abort with error.Indiscriminate use of this option
|
||||
will result in slaves being hopelessly out of sync with the master and
|
||||
you having no idea how the problem happened.
|
||||
|
||||
For error codes, you should use the numbers provided by the error message in
|
||||
your slave error log and in the output of @code{SHOW SLAVE STATUS}. Full list
|
||||
of error messages can be found in the source distribution in
|
||||
@code{Docs/mysqld_error.txt}.
|
||||
|
||||
You can ( but should not) also use a very non-recommended value of @code{all}
|
||||
which will ignore all error messages and keep barging along regardless.
|
||||
Needless to say, if you use it, we make no promises regarding your data
|
||||
integrity. Please do not complain if your data on the slave is not anywhere
|
||||
close to what it is on the master in this case - you have been warned.
|
||||
|
||||
Example:
|
||||
|
||||
@code{slave-skip-errors=1062,1053} or @code{slave-skip-errors=all}
|
||||
|
||||
@item @code{skip-slave-start} @tab
|
||||
Tells the slave server not to start the slave on the startup. The user
|
||||
can start it later with @code{SLAVE START}.
|
||||
|
|
@ -46839,17 +46866,21 @@ not yet 100% confident in this code.
|
|||
@appendixsubsec Changes in release 3.23.47
|
||||
@itemize @bullet
|
||||
@item
|
||||
Added @code{slave-skip-errors} option
|
||||
@item
|
||||
Fixed that @code{GROUP BY expr DESC} works.
|
||||
@item
|
||||
Fixed bug when using @code{t1 LEFT JOIN t2 ON t2.key=constant}.
|
||||
@item
|
||||
@code{mysqlconfig} now also work with binary (relocated) distributions.
|
||||
@code{mysql_config} now also work with binary (relocated) distributions.
|
||||
@end itemize
|
||||
|
||||
@node News-3.23.46, News-3.23.45, News-3.23.47, News-3.23.x
|
||||
@appendixsubsec Changes in release 3.23.46
|
||||
@itemize @bullet
|
||||
@item
|
||||
Fixed problem with aliased temporary tables replication
|
||||
@item
|
||||
InnoDB and BDB tables will now use index when doing an @code{ORDER BY}
|
||||
on the whole table.
|
||||
@item
|
||||
|
|
|
|||
62
extra/mysql_install.c
Normal file
62
extra/mysql_install.c
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA */
|
||||
|
||||
/* Install or upgrade MySQL server. By Sasha Pachev <sasha@mysql.com>
|
||||
*/
|
||||
|
||||
#define INSTALL_VERSION "1.0"
|
||||
|
||||
#define DONT_USE_RAID
|
||||
#include <global.h>
|
||||
#include <m_ctype.h>
|
||||
#include <my_sys.h>
|
||||
#include <m_string.h>
|
||||
#include <mysql_version.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
|
||||
struct option long_options[] =
|
||||
{
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"version", no_argument, 0, 'V'},
|
||||
{0, 0,0,0}
|
||||
};
|
||||
|
||||
static void print_version(void)
|
||||
{
|
||||
printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,INSTALL_VERSION,
|
||||
MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
|
||||
}
|
||||
|
||||
static void usage()
|
||||
{
|
||||
print_version();
|
||||
printf("MySQL AB, by Sasha Pachev\n");
|
||||
printf("This software comes with ABSOLUTELY NO WARRANTY\n\n");
|
||||
printf("Install or upgrade MySQL server.\n\n");
|
||||
printf("Usage: %s [OPTIONS] \n", my_progname);
|
||||
printf("\n\
|
||||
-?, --help Display this help and exit.\n\
|
||||
-h, --host=... Connect to host.\n\
|
||||
-V, --version Output version information and exit.\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -75,7 +75,8 @@ static void usage()
|
|||
printf("Usage: %s [OPTIONS] symbols-file [numeric-dump-file]\n", my_progname);
|
||||
printf("\n\
|
||||
-?, --help Display this help and exit.\n\
|
||||
-h, --host=... Connect to host.\n\
|
||||
-s, --symbols-file=... Use specified symbols file.\n\
|
||||
-n, --numeric-dump-file=... Read the dump from specified file.\n\
|
||||
-V, --version Output version information and exit.\n");
|
||||
printf("\n\
|
||||
The symbols-file should include the output from: 'nm --numeric-sort mysqld'.\n\
|
||||
|
|
|
|||
|
|
@ -26,6 +26,11 @@ typedef struct st_bitmap
|
|||
{
|
||||
uchar *bitmap;
|
||||
uint bitmap_size;
|
||||
my_bool thread_safe; /* set if several threads access the bitmap */
|
||||
/* mutex will be acquired for the duration of each bitmap operation if
|
||||
thread_safe flag is set. Otherwise, we optimize by not acquiring the
|
||||
mutex
|
||||
*/
|
||||
#ifdef THREAD
|
||||
pthread_mutex_t mutex;
|
||||
#endif
|
||||
|
|
@ -34,10 +39,14 @@ typedef struct st_bitmap
|
|||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern my_bool bitmap_init(MY_BITMAP *bitmap, uint bitmap_size);
|
||||
extern my_bool bitmap_init(MY_BITMAP *bitmap, uint bitmap_size,
|
||||
my_bool thread_safe);
|
||||
extern void bitmap_free(MY_BITMAP *bitmap);
|
||||
extern void bitmap_set_bit(MY_BITMAP *bitmap, uint bitmap_bit);
|
||||
extern uint bitmap_set_next(MY_BITMAP *bitmap);
|
||||
extern void bitmap_set_all(MY_BITMAP* bitmap);
|
||||
extern my_bool bitmap_is_set(MY_BITMAP* bitmap, uint bitmap_bit);
|
||||
extern void bitmap_clear_all(MY_BITMAP* bitmap);
|
||||
extern void bitmap_clear_bit(MY_BITMAP *bitmap, uint bitmap_bit);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
release_lock("lock")
|
||||
0
|
||||
get_lock("lock",3)
|
||||
1
|
||||
n
|
||||
|
|
|
|||
4
mysql-test/r/rpl_skip_error.result
Normal file
4
mysql-test/r/rpl_skip_error.result
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
n
|
||||
1
|
||||
2
|
||||
3
|
||||
|
|
@ -4,6 +4,7 @@ create table t1(n int);
|
|||
insert into t1 values(get_lock("lock",2));
|
||||
dirty_close master;
|
||||
connection master1;
|
||||
select release_lock("lock");
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
|
|
|
|||
1
mysql-test/t/rpl_skip_error-slave.opt
Normal file
1
mysql-test/t/rpl_skip_error-slave.opt
Normal file
|
|
@ -0,0 +1 @@
|
|||
--slave-skip-error=1053,1062
|
||||
15
mysql-test/t/rpl_skip_error.test
Normal file
15
mysql-test/t/rpl_skip_error.test
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
source include/master-slave.inc;
|
||||
connection master;
|
||||
drop table if exists t1;
|
||||
create table t1 (n int not null primary key);
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
insert into t1 values (1);
|
||||
connection master;
|
||||
insert into t1 values (1);
|
||||
insert into t1 values (2),(3);
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
select * from t1;
|
||||
|
|
@ -26,14 +26,32 @@
|
|||
#include "mysys_priv.h"
|
||||
#include <my_bitmap.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
my_bool bitmap_init(MY_BITMAP *map, uint bitmap_size)
|
||||
inline void bitmap_lock(MY_BITMAP* map)
|
||||
{
|
||||
#ifdef THREAD
|
||||
if (map->thread_safe)
|
||||
pthread_mutex_lock(&map->mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void bitmap_unlock(MY_BITMAP* map)
|
||||
{
|
||||
#ifdef THREAD
|
||||
if (map->thread_safe)
|
||||
pthread_mutex_unlock(&map->mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
my_bool bitmap_init(MY_BITMAP *map, uint bitmap_size, my_bool thread_safe)
|
||||
{
|
||||
if (!(map->bitmap=(uchar*) my_malloc((bitmap_size+7)/8,
|
||||
MYF(MY_WME | MY_ZEROFILL))))
|
||||
return 1;
|
||||
dbug_assert(bitmap_size != ~(uint) 0);
|
||||
#ifdef THREAD
|
||||
map->thread_safe = thread_safe;
|
||||
pthread_mutex_init(&map->mutex, MY_MUTEX_INIT_FAST);
|
||||
#endif
|
||||
map->bitmap_size=bitmap_size;
|
||||
|
|
@ -56,9 +74,9 @@ void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit)
|
|||
{
|
||||
if (bitmap_bit < map->bitmap_size)
|
||||
{
|
||||
pthread_mutex_lock(&map->mutex);
|
||||
bitmap_lock(map);
|
||||
map->bitmap[bitmap_bit / 8] |= (1 << (bitmap_bit & 7));
|
||||
pthread_mutex_unlock(&map->mutex);
|
||||
bitmap_unlock(map);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +88,7 @@ uint bitmap_set_next(MY_BITMAP *map)
|
|||
uint bitmap_size=map->bitmap_size;
|
||||
uint i;
|
||||
|
||||
pthread_mutex_lock(&map->mutex);
|
||||
bitmap_lock(map);
|
||||
for (i=0; i < bitmap_size ; i++, bitmap++)
|
||||
{
|
||||
if (*bitmap != 0xff)
|
||||
|
|
@ -88,7 +106,7 @@ uint bitmap_set_next(MY_BITMAP *map)
|
|||
break; /* Found bit */
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&map->mutex);
|
||||
bitmap_unlock(map);
|
||||
return bit_found;
|
||||
}
|
||||
|
||||
|
|
@ -97,9 +115,29 @@ void bitmap_clear_bit(MY_BITMAP *map, uint bitmap_bit)
|
|||
{
|
||||
if (bitmap_bit < map->bitmap_size)
|
||||
{
|
||||
pthread_mutex_lock(&map->mutex);
|
||||
bitmap_lock(map);
|
||||
map->bitmap[bitmap_bit / 8] &= ~ (1 << (bitmap_bit & 7));
|
||||
pthread_mutex_unlock(&map->mutex);
|
||||
bitmap_unlock(map);
|
||||
}
|
||||
}
|
||||
|
||||
void bitmap_set_all(MY_BITMAP* map)
|
||||
{
|
||||
bitmap_lock(map);
|
||||
memset(map->bitmap, 0xff, (map->bitmap_size+7)/8);
|
||||
bitmap_unlock(map);
|
||||
}
|
||||
|
||||
my_bool bitmap_is_set(MY_BITMAP* map, uint bitmap_bit)
|
||||
{
|
||||
return (bitmap_bit < map->bitmap_size) ?
|
||||
(map->bitmap[bitmap_bit / 8] & (1 << (bitmap_bit & 7))) :
|
||||
0;
|
||||
}
|
||||
|
||||
void bitmap_clear_all(MY_BITMAP* map)
|
||||
{
|
||||
bitmap_lock(map);
|
||||
bzero(map->bitmap,(map->bitmap_size+7)/8);
|
||||
bitmap_unlock(map);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -707,6 +707,8 @@ void clean_up(bool print_message)
|
|||
DBUG_PRINT("exit",("clean_up"));
|
||||
if (cleanup_done++)
|
||||
return; /* purecov: inspected */
|
||||
if (use_slave_mask)
|
||||
bitmap_free(&slave_error_mask);
|
||||
acl_free(1);
|
||||
grant_free();
|
||||
sql_cache_free();
|
||||
|
|
@ -1757,7 +1759,7 @@ int main(int argc, char **argv)
|
|||
#endif
|
||||
select_thread=pthread_self();
|
||||
select_thread_in_use=1;
|
||||
if (use_temp_pool && bitmap_init(&temp_pool,1024))
|
||||
if (use_temp_pool && bitmap_init(&temp_pool,1024,1))
|
||||
unireg_abort(1);
|
||||
|
||||
/*
|
||||
|
|
@ -2600,7 +2602,8 @@ enum options {
|
|||
OPT_GEMINI_UNBUFFERED_IO, OPT_SKIP_SAFEMALLOC,
|
||||
OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS,
|
||||
OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL,
|
||||
OPT_SAFE_USER_CREATE, OPT_SQL_MODE
|
||||
OPT_SAFE_USER_CREATE, OPT_SQL_MODE,
|
||||
OPT_SLAVE_SKIP_ERRORS
|
||||
};
|
||||
|
||||
static struct option long_options[] = {
|
||||
|
|
@ -2735,6 +2738,8 @@ static struct option long_options[] = {
|
|||
{"skip-stack-trace", no_argument, 0, (int) OPT_SKIP_STACK_TRACE},
|
||||
{"skip-symlink", no_argument, 0, (int) OPT_SKIP_SYMLINKS},
|
||||
{"skip-thread-priority", no_argument, 0, (int) OPT_SKIP_PRIOR},
|
||||
{"slave-skip-errors", required_argument,0,
|
||||
(int) OPT_SLAVE_SKIP_ERRORS},
|
||||
{"socket", required_argument, 0, (int) OPT_SOCKET},
|
||||
{"sql-bin-update-same", no_argument, 0, (int) OPT_SQL_BIN_UPDATE_SAME},
|
||||
{"sql-mode", required_argument, 0, (int) OPT_SQL_MODE},
|
||||
|
|
@ -3396,6 +3401,9 @@ static void get_options(int argc,char **argv)
|
|||
case 'P':
|
||||
mysql_port= (unsigned int) atoi(optarg);
|
||||
break;
|
||||
case OPT_SLAVE_SKIP_ERRORS:
|
||||
init_slave_skip_errors(optarg);
|
||||
break;
|
||||
case OPT_SAFEMALLOC_MEM_LIMIT:
|
||||
#if !defined(DBUG_OFF) && defined(SAFEMALLOC)
|
||||
safemalloc_mem_limit = atoi(optarg);
|
||||
|
|
|
|||
60
sql/slave.cc
60
sql/slave.cc
|
|
@ -29,6 +29,8 @@
|
|||
volatile bool slave_running = 0;
|
||||
pthread_t slave_real_id;
|
||||
MASTER_INFO glob_mi;
|
||||
MY_BITMAP slave_error_mask;
|
||||
bool use_slave_mask = 0;
|
||||
HASH replicate_do_table, replicate_ignore_table;
|
||||
DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table;
|
||||
bool do_table_inited = 0, ignore_table_inited = 0;
|
||||
|
|
@ -73,6 +75,50 @@ static byte* get_table_key(TABLE_RULE_ENT* e, uint* len,
|
|||
return (byte*)e->db;
|
||||
}
|
||||
|
||||
/* called from get_options() in mysqld.cc on start-up */
|
||||
void init_slave_skip_errors(char* arg)
|
||||
{
|
||||
char* p,*end;
|
||||
int err_code = 0;
|
||||
my_bool last_was_digit = 0;
|
||||
if (bitmap_init(&slave_error_mask,MAX_SLAVE_ERROR,0))
|
||||
{
|
||||
fprintf(stderr, "Badly out of memory, please check your system status\n");
|
||||
exit(1);
|
||||
}
|
||||
use_slave_mask = 1;
|
||||
for (;isspace(*arg);++arg)
|
||||
/* empty */;
|
||||
/* force first three chars to lower case */
|
||||
for (p = arg, end = arg + 3; *p && p < end; ++p)
|
||||
*p = tolower(*p);
|
||||
if (!memcmp(arg,"all",3))
|
||||
{
|
||||
bitmap_set_all(&slave_error_mask);
|
||||
return;
|
||||
}
|
||||
for (p = arg, end = strend(arg); p < end; ++p)
|
||||
{
|
||||
int digit = *p - '0';
|
||||
if (digit >= 0 && digit < 10) /* found real digit */
|
||||
{
|
||||
err_code = err_code * 10 + digit;
|
||||
last_was_digit = 1;
|
||||
}
|
||||
else /* delimiter */
|
||||
{
|
||||
if (last_was_digit)
|
||||
{
|
||||
if (err_code < MAX_SLAVE_ERROR)
|
||||
{
|
||||
bitmap_set_bit(&slave_error_mask,err_code);
|
||||
}
|
||||
err_code = 0;
|
||||
last_was_digit = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void init_table_rule_hash(HASH* h, bool* h_inited)
|
||||
{
|
||||
|
|
@ -869,6 +915,11 @@ point. If you are sure that your master is ok, run this query manually on the\
|
|||
}
|
||||
}
|
||||
|
||||
inline int ignored_error_code(int err_code)
|
||||
{
|
||||
return use_slave_mask && bitmap_is_set(&slave_error_mask, err_code);
|
||||
}
|
||||
|
||||
static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len)
|
||||
{
|
||||
Log_event * ev = Log_event::read_log_event((const char*)net->read_pos + 1,
|
||||
|
|
@ -925,11 +976,13 @@ static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len)
|
|||
|
||||
// sanity check to make sure the master did not get a really bad
|
||||
// error on the query
|
||||
if (!check_expected_error(thd, (expected_error = qev->error_code)))
|
||||
if (ignored_error_code((expected_error=qev->error_code)) ||
|
||||
!check_expected_error(thd, expected_error))
|
||||
{
|
||||
mysql_parse(thd, thd->query, q_len);
|
||||
if (expected_error !=
|
||||
(actual_error = thd->net.last_errno) && expected_error)
|
||||
(actual_error = thd->net.last_errno) && expected_error &&
|
||||
!ignored_error_code(actual_error))
|
||||
{
|
||||
const char* errmsg = "Slave: did not get the expected error\
|
||||
running query from master - expected: '%s' (%d), got '%s' (%d)";
|
||||
|
|
@ -939,7 +992,8 @@ static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len)
|
|||
actual_error);
|
||||
thd->query_error = 1;
|
||||
}
|
||||
else if (expected_error == actual_error)
|
||||
else if (expected_error == actual_error ||
|
||||
ignored_error_code(actual_error))
|
||||
{
|
||||
thd->query_error = 0;
|
||||
*last_slave_error = 0;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,11 @@
|
|||
#define SLAVE_H
|
||||
|
||||
#define SLAVE_NET_TIMEOUT 3600
|
||||
#define MAX_SLAVE_ERROR 2000
|
||||
|
||||
extern ulong slave_net_timeout, master_retry_count;
|
||||
extern MY_BITMAP slave_error_mask;
|
||||
extern bool use_slave_mask;
|
||||
|
||||
typedef struct st_master_info
|
||||
{
|
||||
|
|
@ -89,6 +92,7 @@ int add_table_rule(HASH* h, const char* table_spec);
|
|||
int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec);
|
||||
void init_table_rule_hash(HASH* h, bool* h_inited);
|
||||
void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited);
|
||||
void init_slave_skip_errors(char* arg);
|
||||
|
||||
void end_slave(); // clean up
|
||||
int init_master_info(MASTER_INFO* mi);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue