From ecba786861b2fb4fa04a9f5c1621c67a02ef45f9 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 30 May 2001 18:50:56 -0600 Subject: [PATCH] A slave now can optionally register with the master providing the info on how to connect to the slave for the clients that connect to the master, but would like to know where the slaves are include/mysql_com.h: register slaves mysql-test/mysql-test-run.sh: parameters to test slave registration mysql-test/r/rpl000002.result: test of slave registration mysql-test/t/rpl000002.test: test slave registration sql/mysql_priv.h: slave registration sql/mysqld.cc: slave registration sql/slave.cc: slave registration sql/slave.h: slave registration sql/sql_lex.h: slave registration sql/sql_parse.cc: slave registration sql/sql_repl.cc: slave registration sql/sql_repl.h: slave registration sql/sql_yacc.yy: slave registration --- include/mysql_com.h | 3 +- mysql-test/mysql-test-run.sh | 2 + mysql-test/r/rpl000002.result | 2 + mysql-test/t/rpl000002.test | 1 + sql/mysql_priv.h | 2 +- sql/mysqld.cc | 31 ++++++++- sql/slave.cc | 52 +++++++++++++++ sql/slave.h | 5 +- sql/sql_lex.h | 3 +- sql/sql_parse.cc | 17 ++++- sql/sql_repl.cc | 117 ++++++++++++++++++++++++++++++++++ sql/sql_repl.h | 14 ++++ sql/sql_yacc.yy | 6 +- 13 files changed, 245 insertions(+), 10 deletions(-) diff --git a/include/mysql_com.h b/include/mysql_com.h index 874430910ef..4245101a440 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -42,7 +42,8 @@ enum enum_server_command {COM_SLEEP,COM_QUIT,COM_INIT_DB,COM_QUERY, COM_PROCESS_INFO,COM_CONNECT,COM_PROCESS_KILL, COM_DEBUG,COM_PING,COM_TIME,COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP, - COM_TABLE_DUMP, COM_CONNECT_OUT}; + COM_TABLE_DUMP, COM_CONNECT_OUT, + COM_REGISTER_SLAVE}; #define NOT_NULL_FLAG 1 /* Field can't be NULL */ #define PRI_KEY_FLAG 2 /* Field is part of a primary key */ diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 33045911954..368ab69509d 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -520,6 +520,8 @@ start_slave() --tmpdir=$MYSQL_TMP_DIR \ --language=english \ --skip-innodb --skip-slave-start \ + --report-host=127.0.0.1 --report-user=root \ + --report-port=$SLAVE_MYPORT \ $SMALL_SERVER \ $EXTRA_SLAVE_OPT $EXTRA_SLAVE_MYSQLD_OPT" if [ x$DO_DDD = x1 ] diff --git a/mysql-test/r/rpl000002.result b/mysql-test/r/rpl000002.result index a68ef517708..1586d433d93 100644 --- a/mysql-test/r/rpl000002.result +++ b/mysql-test/r/rpl000002.result @@ -2,6 +2,8 @@ n 2000 2001 2002 +Server_id Host User Password Port +2 127.0.0.1 root 9307 id created 1 1970-01-01 06:25:45 id created diff --git a/mysql-test/t/rpl000002.test b/mysql-test/t/rpl000002.test index 0c490e6316d..865aa5e5bab 100644 --- a/mysql-test/t/rpl000002.test +++ b/mysql-test/t/rpl000002.test @@ -11,6 +11,7 @@ use test; sync_with_master; select * from t1; connection master; +show slave hosts; drop table t1; save_master_pos; connection slave; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index c4967372bb0..aaf1d4200df 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -520,7 +520,7 @@ extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open, LOCK_thread_count,LOCK_mapped_file,LOCK_user_locks, LOCK_status, LOCK_grant, LOCK_error_log, LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone, - LOCK_binlog_update, LOCK_slave, LOCK_server_id; + LOCK_binlog_update, LOCK_slave, LOCK_server_id, LOCK_slave_list; extern pthread_cond_t COND_refresh,COND_thread_count, COND_binlog_update, COND_slave_stopped, COND_slave_start; extern pthread_attr_t connection_attrib; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f25174896ac..1e4a96d2196 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -20,6 +20,7 @@ #include #include "sql_acl.h" #include "slave.h" +#include "sql_repl.h" #include "stacktrace.h" #ifdef HAVE_BERKELEY_DB #include "ha_berkeley.h" @@ -277,9 +278,12 @@ volatile ulong cached_thread_count=0; // replication parameters, if master_host is not NULL, we are a slave my_string master_user = (char*) "test", master_password = 0, master_host=0, master_info_file = (char*) "master.info"; +my_string report_user = (char*) "test", report_password = 0, report_host=0; + const char *localhost=LOCAL_HOST; const char *delayed_user="DELAYED"; uint master_port = MYSQL_PORT, master_connect_retry = 60; +uint report_port = MYSQL_PORT; ulong max_tmp_tables,max_heap_table_size; ulong bytes_sent = 0L, bytes_received = 0L; @@ -341,7 +345,7 @@ pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count, LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received, LOCK_binlog_update, LOCK_slave, LOCK_server_id, - LOCK_user_conn; + LOCK_user_conn, LOCK_slave_list; pthread_cond_t COND_refresh,COND_thread_count,COND_binlog_update, COND_slave_stopped, COND_slave_start; @@ -695,6 +699,7 @@ void clean_up(bool print_message) bitmap_free(&temp_pool); free_max_user_conn(); end_slave(); + end_slave_list(); #ifndef __WIN__ if (!opt_bootstrap) (void) my_delete(pidfile_name,MYF(0)); // This may not always exist @@ -1685,7 +1690,8 @@ int main(int argc, char **argv) randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2); reset_floating_point_exceptions(); init_thr_lock(); - + init_slave_list(); + /* Fix varibles that are base 1024*1024 */ myisam_max_temp_length= (my_off_t) min(((ulonglong) myisam_max_sort_file_size)*1024*1024, (ulonglong) MAX_FILE_SIZE); myisam_max_extra_temp_length= (my_off_t) min(((ulonglong) myisam_max_extra_sort_file_size)*1024*1024, (ulonglong) MAX_FILE_SIZE); @@ -2479,7 +2485,8 @@ enum options { OPT_TEMP_POOL, OPT_DO_PSTACK, OPT_TX_ISOLATION, OPT_GEMINI_FLUSH_LOG, OPT_GEMINI_RECOVER, OPT_GEMINI_UNBUFFERED_IO, OPT_SKIP_SAFEMALLOC, - OPT_SKIP_STACK_TRACE + OPT_SKIP_STACK_TRACE, OPT_REPORT_HOST, + OPT_REPORT_USER, OPT_REPORT_PASSWORD, OPT_REPORT_PORT }; static struct option long_options[] = { @@ -2587,6 +2594,12 @@ static struct option long_options[] = { (int) OPT_REPLICATE_WILD_IGNORE_TABLE}, {"replicate-rewrite-db", required_argument, 0, (int) OPT_REPLICATE_REWRITE_DB}, + // In replication, we may need to tell the other servers how to connect + // to us + {"report-host", required_argument, 0, (int) OPT_REPORT_HOST}, + {"report-user", required_argument, 0, (int) OPT_REPORT_USER}, + {"report-password", required_argument, 0, (int) OPT_REPORT_PASSWORD}, + {"report-port", required_argument, 0, (int) OPT_REPORT_PORT}, {"safe-mode", no_argument, 0, (int) OPT_SAFE}, {"safe-show-database", no_argument, 0, (int) OPT_SAFE_SHOW_DB}, {"socket", required_argument, 0, (int) OPT_SOCKET}, @@ -3712,6 +3725,18 @@ static void get_options(int argc,char **argv) case OPT_MASTER_PORT: master_port= atoi(optarg); break; + case OPT_REPORT_HOST: + report_host=optarg; + break; + case OPT_REPORT_USER: + report_user=optarg; + break; + case OPT_REPORT_PASSWORD: + report_password=optarg; + break; + case OPT_REPORT_PORT: + report_port= atoi(optarg); + break; case OPT_MASTER_CONNECT_RETRY: master_connect_retry= atoi(optarg); break; diff --git a/sql/slave.cc b/sql/slave.cc index 1841f3a9e4a..5b5439353c7 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -569,6 +569,52 @@ error: return 1; } +int register_slave_on_master(MYSQL* mysql) +{ + String packet; + uint len; + char buf[4]; + + if(!report_host) + return 0; + + int4store(buf, server_id); + packet.append(buf, 4); + + len = strlen(report_host); + packet.append((char)(uchar)len); + packet.append(report_host, len); + + len = strlen(report_user); + packet.append((char)(uchar)len); + packet.append(report_user, len); + + if(report_password) + { + len = strlen(report_password); + packet.append((char)(uchar)len); + packet.append(report_password, len); + } + else + { + packet.append((char)0); + } + + int2store(buf, (uint16)report_port); + packet.append(buf, 2); + + if(mc_simple_command(mysql, COM_REGISTER_SLAVE, (char*)packet.ptr(), + packet.length(), 0)) + { + sql_print_error("Error on COM_REGISTER_SLAVE: '%s'", + mc_mysql_error(mysql)); + return 1; + } + + return 0; +} + + int show_master_info(THD* thd) { DBUG_ENTER("show_master_info"); @@ -1245,6 +1291,12 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused))) sql_print_error("Slave thread killed while connecting to master"); goto err; } + + // register ourselves with the master + // if fails, this is not fatal - we just print the error message and go + // on with life + thd->proc_info = "Registering slave on master"; + register_slave_on_master(mysql); while (!slave_killed(thd)) { diff --git a/sql/slave.h b/sql/slave.h index 77197246bad..f4696a18a56 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -66,6 +66,7 @@ typedef struct st_table_rule_ent #define TABLE_RULE_ARR_SIZE 16 int flush_master_info(MASTER_INFO* mi); +int register_slave_on_master(MYSQL* mysql); int mysql_table_dump(THD* thd, const char* db, const char* tbl_name, int fd = -1); @@ -117,9 +118,9 @@ extern int disconnect_slave_event_count, abort_slave_event_count ; #endif // the master variables are defaults read from my.cnf or command line -extern uint master_port, master_connect_retry; +extern uint master_port, master_connect_retry, report_port; extern my_string master_user, master_password, master_host, - master_info_file; + master_info_file, report_user, report_host, report_password; extern I_List replicate_do_db, replicate_ignore_db; extern I_List replicate_rewrite_db; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 8c83e6e587a..e67b93f855b 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -54,7 +54,8 @@ enum enum_sql_command { SQLCOM_RENAME_TABLE, SQLCOM_BACKUP_TABLE, SQLCOM_RESTORE_TABLE, SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_SHOW_BINLOGS, SQLCOM_SHOW_OPEN_TABLES, SQLCOM_LOAD_MASTER_DATA, - SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ + SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ, + SQLCOM_SHOW_SLAVE_HOSTS }; enum lex_states { STATE_START, STATE_CHAR, STATE_IDENT, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 7742df4a2bf..dc4e7358138 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -53,7 +53,7 @@ const char *command_name[]={ "Sleep", "Quit", "Init DB", "Query", "Field List", "Create DB", "Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist", "Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user", - "Binlog Dump","Table Dump", "Connect Out" + "Binlog Dump","Table Dump", "Connect Out", "Register Slave" }; bool volatile abort_slave = 0; @@ -766,6 +766,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (!mysql_change_db(thd,packet)) mysql_log.write(thd,command,"%s",thd->db); break; + case COM_REGISTER_SLAVE: + { + if(register_slave(thd, (uchar*)packet, packet_length)) + send_error(&thd->net); + else + send_ok(&thd->net); + break; + } case COM_TABLE_DUMP: { slow_command = TRUE; @@ -1163,6 +1171,13 @@ mysql_execute_command(void) res = purge_master_logs(thd, lex->to_log); break; } + case SQLCOM_SHOW_SLAVE_HOSTS: + { + if(check_access(thd, FILE_ACL, any_db)) + goto error; + res = show_slave_hosts(thd); + break; + } case SQLCOM_BACKUP_TABLE: { if (check_db_used(thd,tables) || diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index d36fa1a3534..fa5b599c2f8 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -25,9 +25,39 @@ #include #include +#define SLAVE_LIST_CHUNK 128 + extern const char* any_db; extern pthread_handler_decl(handle_slave,arg); +HASH slave_list; + +static uint32* slave_list_key(SLAVE_INFO* si, uint* len, + my_bool not_used __attribute__((unused))) +{ + *len = 4; + return &si->server_id; +} + +static void slave_info_free(void *s) +{ + my_free((byte*)s, MYF(MY_WME)); +} + +void init_slave_list() +{ + hash_init(&slave_list, SLAVE_LIST_CHUNK, 0, 0, + (hash_get_key) slave_list_key, slave_info_free, 0); + pthread_mutex_init(&LOCK_slave_list, MY_MUTEX_INIT_FAST); +} + +void end_slave_list() +{ + pthread_mutex_lock(&LOCK_slave_list); + hash_free(&slave_list); + pthread_mutex_unlock(&LOCK_slave_list); + pthread_mutex_destroy(&LOCK_slave_list); +} static int fake_rotate_event(NET* net, String* packet, char* log_file_name, const char**errmsg) @@ -56,6 +86,55 @@ static int fake_rotate_event(NET* net, String* packet, char* log_file_name, return 0; } +int register_slave(THD* thd, uchar* packet, uint packet_length) +{ + uint len; + SLAVE_INFO* si, *old_si; + int res = 1; + uchar* p = packet, *p_end = packet + packet_length; + + if(check_access(thd, FILE_ACL, any_db)) + return 1; + + if(!(si = (SLAVE_INFO*)my_malloc(sizeof(SLAVE_INFO), MYF(MY_WME)))) + goto err; + + si->server_id = uint4korr(p); + p += 4; + len = (uint)*p++; + if(p + len > p_end || len > sizeof(si->host) - 1) + goto err; + memcpy(si->host, p, len); + si->host[len] = 0; + p += len; + len = *p++; + if(p + len > p_end || len > sizeof(si->user) - 1) + goto err; + memcpy(si->user, p, len); + si->user[len] = 0; + p += len; + len = *p++; + if(p + len > p_end || len > sizeof(si->password) - 1) + goto err; + memcpy(si->password, p, len); + si->password[len] = 0; + p += len; + si->port = uint2korr(p); + pthread_mutex_lock(&LOCK_slave_list); + + if((old_si = (SLAVE_INFO*)hash_search(&slave_list, + (byte*)&si->server_id, 4))) + hash_delete(&slave_list, (byte*)old_si); + + res = hash_insert(&slave_list, (byte*)si); + pthread_mutex_unlock(&LOCK_slave_list); + return res; +err: + if(si) + my_free((byte*)si, MYF(MY_WME)); + return res; +} + static int send_file(THD *thd) { @@ -742,6 +821,44 @@ void reset_master() } +int show_slave_hosts(THD* thd) +{ + DBUG_ENTER("show_slave_hosts"); + List field_list; + field_list.push_back(new Item_empty_string("Server_id", 20)); + field_list.push_back(new Item_empty_string("Host", 20)); + field_list.push_back(new Item_empty_string("User",20)); + field_list.push_back(new Item_empty_string("Password",20)); + field_list.push_back(new Item_empty_string("Port",20)); + + if(send_fields(thd, field_list, 1)) + DBUG_RETURN(-1); + String* packet = &thd->packet; + uint i; + NET* net = &thd->net; + + pthread_mutex_lock(&LOCK_slave_list); + + for(i = 0; i < slave_list.records; ++i) + { + SLAVE_INFO* si = (SLAVE_INFO*)hash_element(&slave_list, i); + packet->length(0); + net_store_data(packet, si->server_id); + net_store_data(packet, si->host); + net_store_data(packet, si->user); + net_store_data(packet, si->password); + net_store_data(packet, (uint)si->port); + if(my_net_write(net, (char*)packet->ptr(), packet->length())) + { + pthread_mutex_unlock(&LOCK_slave_list); + DBUG_RETURN(-1); + } + } + pthread_mutex_unlock(&LOCK_slave_list); + send_eof(net); + DBUG_RETURN(0); +} + int show_binlog_info(THD* thd) { DBUG_ENTER("show_binlog_info"); diff --git a/sql/sql_repl.h b/sql/sql_repl.h index 2428928f044..b82b5d56812 100644 --- a/sql/sql_repl.h +++ b/sql/sql_repl.h @@ -3,6 +3,16 @@ #include "slave.h" +typedef struct st_slave_info +{ + uint32 server_id; + char host[HOSTNAME_LENGTH+1]; + char user[USERNAME_LENGTH+1]; + char password[HASH_PASSWORD_LENGTH+1]; + uint16 port; +} SLAVE_INFO; + +extern HASH slave_list; extern char* master_host; extern my_string opt_bin_logname, master_info_file; extern uint32 server_id; @@ -17,8 +27,12 @@ int stop_slave(THD* thd = 0, bool net_report = 1); int load_master_data(THD* thd); int connect_to_master(THD *thd, MYSQL* mysql, MASTER_INFO* mi); int change_master(THD* thd); +int show_slave_hosts(THD* thd); void reset_slave(); void reset_master(); +void init_slave_list(); +void end_slave_list(); +int register_slave(THD* thd, uchar* packet, uint packet_length); int purge_master_logs(THD* thd, const char* to_log); bool log_in_use(const char* log_name); void adjust_linfo_offsets(my_off_t purge_offset); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index ed17a2dedf4..a3bfd8c04a1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2246,7 +2246,11 @@ show_param: | MASTER_SYM LOGS_SYM { Lex->sql_command = SQLCOM_SHOW_BINLOGS; - } + } + | SLAVE HOSTS_SYM + { + Lex->sql_command = SQLCOM_SHOW_SLAVE_HOSTS; + } | keys_or_index FROM table_ident opt_db { Lex->sql_command= SQLCOM_SHOW_KEYS;