summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <sasha@mysql.sashanet.com>2000-10-26 22:11:55 -0600
committerunknown <sasha@mysql.sashanet.com>2000-10-26 22:11:55 -0600
commitadd02ff882e168edc2cf5d4f24796e788b31634c (patch)
tree1b71072bebf724dd061370737f97c2a08a176ae3 /sql
parent293d7c8313ba8faa41f39d06617a542e337d8883 (diff)
downloadmariadb-git-add02ff882e168edc2cf5d4f24796e788b31634c.tar.gz
fixed --skip-slave-thread bug
added PURGE MASTER LOGS TO and SHOW MASTER LOGS fixed the output of SHOW MASTER STATUS updated docs Docs/manual.texi: Update for PURGE MASTER LOGS TO, SHOW MASTER LOGS sql/lex.h: added PURGE sql/log.cc: update for PURGE BitKeeper/etc/ignore: Added include/.my_sys.h.swp PENDING/2000-10-25.01 PENDING/2000-10-25.02 support-files/mysql-3.23.27-beta.spec to the ignore list sql/mysqld.cc: fixed bug in --skip-slave-start sql/sql_class.cc: added linfo to THD sql/sql_class.h: updates for PURGE sql/sql_lex.h: updates for PURGE sql/sql_parse.cc: updates for PURGE sql/sql_repl.cc: updates for PURGE sql/sql_repl.h: updates for PURGE sql/sql_yacc.yy: updates for PURGE
Diffstat (limited to 'sql')
-rw-r--r--sql/lex.h1
-rw-r--r--sql/log.cc141
-rw-r--r--sql/mysqld.cc4
-rw-r--r--sql/sql_class.cc1
-rw-r--r--sql/sql_class.h18
-rw-r--r--sql/sql_lex.h3
-rw-r--r--sql/sql_parse.cc19
-rw-r--r--sql/sql_repl.cc166
-rw-r--r--sql/sql_repl.h5
-rw-r--r--sql/sql_yacc.yy15
10 files changed, 367 insertions, 6 deletions
diff --git a/sql/lex.h b/sql/lex.h
index a5c1b6eb123..a75fa07c3b7 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -233,6 +233,7 @@ static SYMBOL symbols[] = {
{ "PACK_KEYS", SYM(PACK_KEYS_SYM),0,0},
{ "PARTIAL", SYM(PARTIAL),0,0},
{ "PASSWORD", SYM(PASSWORD),0,0},
+ { "PURGE", SYM(PURGE),0,0},
{ "PRECISION", SYM(PRECISION),0,0},
{ "PRIMARY", SYM(PRIMARY_SYM),0,0},
{ "PROCEDURE", SYM(PROCEDURE),0,0},
diff --git a/sql/log.cc b/sql/log.cc
index d245f49bf7d..42af3a8397b 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -19,6 +19,7 @@
#include "mysql_priv.h"
#include "sql_acl.h"
+#include "sql_repl.h"
#include <my_dir.h>
#include <stdarg.h>
@@ -256,7 +257,8 @@ int MYSQL_LOG::find_first_log(LOG_INFO* linfo, const char* log_name)
}
// if the log entry matches, empty string matching anything
- if(!log_name_len || (fname[log_name_len] == '\n' && !memcmp(fname, log_name, log_name_len)))
+ if(!log_name_len || (fname[log_name_len] == '\n' &&
+ !memcmp(fname, log_name, log_name_len)))
{
if(log_name_len)
fname[log_name_len] = 0; // to kill \n
@@ -275,6 +277,137 @@ err:
return error;
}
+
+int MYSQL_LOG::purge_logs(THD* thd, const char* to_log)
+{
+ if(!index_file) return LOG_INFO_INVALID;
+ if(no_rotate) return LOG_INFO_PURGE_NO_ROTATE;
+ int error;
+ char fname[FN_REFLEN];
+ char* fname_end, *p;
+ uint fname_len, i;
+ bool logs_to_purge_inited = 0, logs_to_keep_inited = 0, found_log = 0;
+ DYNAMIC_ARRAY logs_to_purge, logs_to_keep;
+ my_off_t purge_offset ;
+ pthread_mutex_lock(&LOCK_index);
+
+ if(my_fseek(index_file, 0, MY_SEEK_SET,
+ MYF(MY_WME) ) == MY_FILEPOS_ERROR)
+ {
+ error = LOG_INFO_SEEK;
+ goto err;
+ }
+
+ if(init_dynamic_array(&logs_to_purge, sizeof(char*), 1024, 1024))
+ {
+ error = LOG_INFO_MEM;
+ goto err;
+ }
+ logs_to_purge_inited = 1;
+
+ if(init_dynamic_array(&logs_to_keep, sizeof(char*), 1024, 1024))
+ {
+ error = LOG_INFO_MEM;
+ goto err;
+ }
+ logs_to_keep_inited = 1;
+
+
+ for(;;)
+ {
+ if(!fgets(fname, FN_REFLEN, index_file))
+ {
+ if(feof(index_file))
+ break;
+ else
+ error = LOG_INFO_IO;
+ goto err;
+ }
+
+ *(fname_end = (strend(fname) - 1)) = 0; // kill \n
+ fname_len = (uint)(fname_end - fname);
+
+ if(!memcmp(fname, to_log, fname_len + 1 ))
+ {
+ found_log = 1;
+ purge_offset = my_ftell(index_file, MYF(MY_WME)) - fname_len - 1;
+ }
+
+ if(!found_log && log_in_use(fname))
+ // if one of the logs before the target is in use
+ {
+ error = LOG_INFO_IN_USE;
+ goto err;
+ }
+
+ p = sql_memdup(fname, (uint)(fname_end - fname) + 1);
+ if((found_log) ?
+ insert_dynamic(&logs_to_keep, (gptr) &p) :
+ insert_dynamic(&logs_to_purge, (gptr) &p)
+ )
+ {
+ error = LOG_INFO_MEM;
+ goto err;
+ }
+ }
+
+ if(!found_log)
+ {
+ error = LOG_INFO_EOF;
+ goto err;
+ }
+
+ for(i = 0; i < logs_to_purge.elements; i++)
+ {
+ char* l;
+ get_dynamic(&logs_to_purge, (gptr)&l, i);
+ if(my_delete(l, MYF(MY_WME)))
+ sql_print_error("Error deleting %s during purge", l);
+ }
+
+ // if we get killed -9 here, the sysadmin would have to do a small
+ // vi job on the log index file after restart - otherwise, this should
+ // be safe
+ my_fclose(index_file, MYF(MY_WME));
+ if(!(index_file = my_fopen(index_file_name, O_BINARY|O_WRONLY,
+ MYF(MY_WME))))
+ {
+ sql_print_error("Ouch! Could not re-open the binlog index file \
+during log purge for write");
+ error = LOG_INFO_FATAL;
+ goto err;
+ }
+
+ for(i = 0; i < logs_to_keep.elements; i++)
+ {
+ char* l;
+ get_dynamic(&logs_to_keep, (gptr)&l, i);
+ fprintf(index_file, "%s\n", l);
+ }
+ my_fclose(index_file, MYF(MY_WME));
+
+ if(!(index_file = my_fopen(index_file_name, O_BINARY|O_RDWR|O_APPEND,
+ MYF(MY_WME))))
+ {
+ sql_print_error("Ouch! Could not re-open the binlog index file \
+during log purge for append");
+ error = LOG_INFO_FATAL;
+ goto err;
+ }
+ // now update offsets
+ adjust_linfo_offsets(purge_offset);
+ error = 0;
+err:
+ pthread_mutex_unlock(&LOCK_index);
+ if(logs_to_purge_inited)
+ delete_dynamic(&logs_to_purge);
+ if(logs_to_keep_inited)
+ delete_dynamic(&logs_to_keep);
+
+ return error;
+
+}
+
int MYSQL_LOG::find_next_log(LOG_INFO* linfo)
{
// mutex needed because we need to make sure the file pointer does not move
@@ -285,6 +418,12 @@ int MYSQL_LOG::find_next_log(LOG_INFO* linfo)
char* end ;
pthread_mutex_lock(&LOCK_index);
+ if(linfo->fatal)
+ {
+ error = LOG_INFO_FATAL;
+ goto err;
+ }
+
if(my_fseek(index_file, linfo->index_file_offset, MY_SEEK_SET, MYF(MY_WME) ) == MY_FILEPOS_ERROR)
{
error = LOG_INFO_SEEK;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 6cb24de17c5..d366c3bd999 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -158,6 +158,8 @@ static bool opt_log,opt_update_log,opt_bin_log,opt_slow_log,opt_noacl,
opt_disable_networking=0, opt_bootstrap=0,opt_skip_show_db=0,
opt_ansi_mode=0,opt_myisam_log=0;
bool opt_sql_bin_update = 0, opt_log_slave_updates = 0;
+extern MASTER_INFO glob_mi;
+extern int init_master_info(MASTER_INFO* mi);
// if sql_bin_update is true, SQL_LOG_UPDATE and SQL_LOG_BIN are kept in sync, and are
// treated as aliases for each other
@@ -1618,6 +1620,8 @@ int main(int argc, char **argv)
if(!opt_skip_slave_start &&
pthread_create(&hThread, &connection_attrib, handle_slave, 0))
sql_print_error("Warning: Can't create thread to handle slave");
+ else if(opt_skip_slave_start)
+ init_master_info(&glob_mi);
}
else
sql_print_error("Server id is not set, slave thread will not be started");
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index b65c5d1978f..f86c0cf7461 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -94,6 +94,7 @@ THD::THD()
options=thd_startup_options;
update_lock_default= low_priority_updates ? TL_WRITE_LOW_PRIORITY : TL_WRITE;
start_time=(time_t) 0;
+ current_linfo = 0;
last_nx_table = last_nx_db = 0;
inactive_timeout=net_wait_timeout;
open_options=ha_open_options;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 4ba3ee87144..d1e83c4ed01 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -34,12 +34,20 @@ enum enum_log_type { LOG_CLOSED, LOG_NORMAL, LOG_NEW, LOG_BIN };
#define LOG_INFO_IO -2
#define LOG_INFO_INVALID -3
#define LOG_INFO_SEEK -4
+#define LOG_INFO_PURGE_NO_ROTATE -5
+#define LOG_INFO_MEM -6
+#define LOG_INFO_FATAL -7
+#define LOG_INFO_IN_USE -8
typedef struct st_log_info
{
char log_file_name[FN_REFLEN];
my_off_t index_file_offset;
- my_off_t pos;
+ my_off_t pos;
+ bool fatal; // if the purge happens to give us a negative offset
+ pthread_mutex_t lock;
+ st_log_info():fatal(0) { pthread_mutex_init(&lock, NULL);}
+ ~st_log_info() { pthread_mutex_destroy(&lock);}
} LOG_INFO;
typedef struct st_master_info
@@ -114,6 +122,7 @@ public:
int generate_new_name(char *new_name,const char *old_name);
void make_log_name(char* buf, const char* log_ident);
bool is_active(const char* log_file_name);
+ int purge_logs(THD* thd, const char* to_log);
void flush(void);
void close(bool exiting = 0); // if we are exiting, we also want to close the
// index file
@@ -126,6 +135,9 @@ public:
inline bool is_open() { return log_type != LOG_CLOSED; }
char* get_index_fname() { return index_file_name;}
char* get_log_fname() { return log_file_name; }
+ void lock_index() { pthread_mutex_lock(&LOCK_index);}
+ void unlock_index() { pthread_mutex_unlock(&LOCK_index);}
+ FILE* get_index_file() { return index_file;}
};
/* character conversion tables */
@@ -295,6 +307,10 @@ public:
bool volatile killed,bootstrap;
bool system_thread,in_lock_tables,global_read_lock;
bool query_error;
+ LOG_INFO* current_linfo;
+ // if we do a purge of binary logs, log index info of the threads
+ // that are currently reading it needs to be adjusted. To do that
+ // each thread that is using LOG_INFO needs to adjust the pointer to it
THD();
~THD();
bool store_globals();
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index aa1a326cad7..674da73ba5d 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -48,7 +48,7 @@ enum enum_sql_command {
SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_SHOW_CREATE,
SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT, SQLCOM_CHANGE_MASTER,
SQLCOM_RENAME_TABLE, SQLCOM_BACKUP_TABLE, SQLCOM_RESTORE_TABLE,
- SQLCOM_RESET
+ SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_SHOW_BINLOGS
};
enum lex_states { STATE_START, STATE_CHAR, STATE_IDENT,
@@ -97,6 +97,7 @@ typedef struct st_lex {
char *length,*dec,*change,*name;
char *db,*db1,*table1,*db2,*table2; /* For outer join using .. */
char *backup_dir; /* For RESTORE/BACKUP */
+ char* to_log; /* For PURGE MASTER LOGS TO */
String *wild;
sql_exchange *exchange;
ha_rows select_limit,offset_limit;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 359ed495a83..b22c876d4fe 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -927,6 +927,13 @@ mysql_execute_command(void)
#endif
break;
}
+ case SQLCOM_PURGE:
+ {
+ if(check_access(thd, PROCESS_ACL, any_db))
+ goto error;
+ res = purge_master_logs(thd, lex->to_log);
+ break;
+ }
case SQLCOM_BACKUP_TABLE:
{
if (check_db_used(thd,tables) ||
@@ -1183,6 +1190,18 @@ mysql_execute_command(void)
res= -1;
break;
}
+ case SQLCOM_SHOW_BINLOGS:
+#ifdef DONT_ALLOW_SHOW_COMMANDS
+ send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ DBUG_VOID_RETURN;
+#else
+ {
+ if(check_access(thd, PROCESS_ACL, any_db))
+ goto error;
+ res = show_binlogs(thd);
+ break;
+ }
+#endif
case SQLCOM_SHOW_CREATE:
#ifdef DONT_ALLOW_SHOW_COMMANDS
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 53a5b00d084..5cd5d3a159e 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -93,6 +93,87 @@ static int send_file(THD *thd)
DBUG_RETURN(error);
}
+void adjust_linfo_offsets(my_off_t purge_offset)
+{
+ THD *tmp;
+
+ pthread_mutex_lock(&LOCK_thread_count);
+ I_List_iterator<THD> it(threads);
+
+ while((tmp=it++))
+ {
+ LOG_INFO* linfo;
+ if((linfo = tmp->current_linfo))
+ {
+ pthread_mutex_lock(&linfo->lock);
+ // no big deal if we just started reading the log
+ // nothing to adjust
+ if(linfo->index_file_offset < purge_offset)
+ linfo->fatal = (linfo->index_file_offset != 0);
+ else
+ linfo->index_file_offset -= purge_offset;
+ pthread_mutex_unlock(&linfo->lock);
+ }
+ }
+
+ pthread_mutex_unlock(&LOCK_thread_count);
+}
+
+bool log_in_use(const char* log_name)
+{
+ int log_name_len = strlen(log_name) + 1;
+ THD *tmp;
+ bool result = 0;
+
+ pthread_mutex_lock(&LOCK_thread_count);
+ I_List_iterator<THD> it(threads);
+
+ while((tmp=it++))
+ {
+ LOG_INFO* linfo;
+ if((linfo = tmp->current_linfo))
+ {
+ pthread_mutex_lock(&linfo->lock);
+ result = !memcmp(log_name, linfo->log_file_name, log_name_len);
+ pthread_mutex_unlock(&linfo->lock);
+ if(result) break;
+ }
+ }
+
+ pthread_mutex_unlock(&LOCK_thread_count);
+ return result;
+}
+
+int purge_master_logs(THD* thd, const char* to_log)
+{
+ char search_file_name[FN_REFLEN];
+ mysql_bin_log.make_log_name(search_file_name, to_log);
+ int res = mysql_bin_log.purge_logs(thd, search_file_name);
+ char* errmsg = 0;
+ switch(res)
+ {
+ case 0: break;
+ case LOG_INFO_EOF: errmsg = "Target log not found in binlog index"; break;
+ case LOG_INFO_IO: errmsg = "I/O error reading log index file"; break;
+ case LOG_INFO_INVALID: errmsg = "Server configuration does not permit \
+binlog purge"; break;
+ case LOG_INFO_SEEK: errmsg = "Failed on fseek()"; break;
+ case LOG_INFO_PURGE_NO_ROTATE: errmsg = "Cannot purge unrotatable log";
+ break;
+ case LOG_INFO_MEM: errmsg = "Out of memory"; break;
+ case LOG_INFO_FATAL: errmsg = "Fatal error during purge"; break;
+ case LOG_INFO_IN_USE: errmsg = "A purgable log is in use, will not purge";
+ break;
+ default:
+ errmsg = "Unknown error during purge"; break;
+ }
+
+ if(errmsg)
+ send_error(&thd->net, 0, errmsg);
+ else
+ send_ok(&thd->net);
+}
+
void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
{
LOG_INFO linfo;
@@ -117,6 +198,9 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
mysql_bin_log.make_log_name(search_file_name, log_ident);
else
search_file_name[0] = 0;
+
+ linfo.index_file_offset = 0;
+ thd->current_linfo = &linfo;
if(mysql_bin_log.find_first_log(&linfo, search_file_name))
{
@@ -366,9 +450,20 @@ sweepstakes if you report the bug";
send_eof(&thd->net);
thd->proc_info = "waiting to finalize termination";
+ pthread_mutex_lock(&LOCK_thread_count);
+ thd->current_linfo = 0;
+ pthread_mutex_unlock(&LOCK_thread_count);
DBUG_VOID_RETURN;
err:
thd->proc_info = "waiting to finalize termination";
+ pthread_mutex_lock(&LOCK_thread_count);
+ // exclude iteration through thread list
+ // this is needed for purge_logs() - it will iterate through
+ // thread list and update thd->current_linfo->index_file_offset
+ // this mutex will make sure that it never tried to update our linfo
+ // after we return from this stack frame
+ thd->current_linfo = 0;
+ pthread_mutex_unlock(&LOCK_thread_count);
if(log)
(void) my_fclose(log, MYF(MY_WME));
send_error(&thd->net, 0, errmsg);
@@ -594,7 +689,8 @@ int show_binlog_info(THD* thd)
{
LOG_INFO li;
mysql_bin_log.get_current_log(&li);
- net_store_data(packet, li.log_file_name);
+ int dir_len = dirname_length(li.log_file_name);
+ net_store_data(packet, li.log_file_name + dir_len);
net_store_data(packet, (longlong)li.pos);
net_store_data(packet, &binlog_do_db);
net_store_data(packet, &binlog_ignore_db);
@@ -613,3 +709,71 @@ int show_binlog_info(THD* thd)
send_eof(&thd->net);
DBUG_RETURN(0);
}
+
+int show_binlogs(THD* thd)
+{
+ const char* errmsg = 0;
+ FILE* index_file;
+ char fname[FN_REFLEN];
+ NET* net = &thd->net;
+ List<Item> field_list;
+ String* packet = &thd->packet;
+
+ if(!mysql_bin_log.is_open())
+ {
+ errmsg = "binlog is not open";
+ goto err;
+ }
+
+ field_list.push_back(new Item_empty_string("Log_name", 128));
+ if(send_fields(thd, field_list, 1))
+ {
+ sql_print_error("Failed in send_fields");
+ return 1;
+ }
+
+ mysql_bin_log.lock_index();
+ index_file = mysql_bin_log.get_index_file();
+ if(!index_file)
+ {
+ errmsg = "Uninitialized index file pointer";
+ mysql_bin_log.unlock_index();
+ goto err;
+ }
+ if(my_fseek(index_file, 0, MY_SEEK_SET, MYF(MY_WME)))
+ {
+ errmsg = "Failed on fseek()";
+ mysql_bin_log.unlock_index();
+ goto err;
+ }
+
+ while(fgets(fname, sizeof(fname), index_file))
+ {
+ char* fname_end;
+ *(fname_end = (strend(fname) - 1)) = 0;
+ int dir_len = dirname_length(fname);
+ packet->length(0);
+ net_store_data(packet, fname + dir_len, (fname_end - fname)-dir_len);
+ if(my_net_write(net, (char*) packet->ptr(), packet->length()))
+ {
+ sql_print_error("Failed in my_net_write");
+ mysql_bin_log.unlock_index();
+ return 1;
+ }
+ }
+
+ mysql_bin_log.unlock_index();
+ send_eof(net);
+ err:
+ if(errmsg)
+ {
+ send_error(net, 0, errmsg);
+ return 1;
+ }
+
+ send_ok(net);
+ return 0;
+}
+
+
+
diff --git a/sql/sql_repl.h b/sql/sql_repl.h
index 9c8d43bda54..a0b60497773 100644
--- a/sql/sql_repl.h
+++ b/sql/sql_repl.h
@@ -14,7 +14,10 @@ int stop_slave(THD* thd = 0, bool net_report = 1);
int change_master(THD* thd);
void reset_slave();
void reset_master();
-
+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);
+int show_binlogs(THD* thd);
extern int init_master_info(MASTER_INFO* mi);
void kill_zombie_dump_threads(uint32 slave_server_id);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 4b404081676..c647ac8a192 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -107,6 +107,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token MASTER_SYM
%token REPAIR
%token RESET_SYM
+%token PURGE
%token SLAVE
%token START_SYM
%token STOP_SYM
@@ -493,7 +494,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <NONE>
query verb_clause create change select drop insert replace insert2
insert_values update delete show describe load alter optimize flush
- reset begin commit rollback slave master_def master_defs
+ reset purge begin commit rollback slave master_def master_defs
repair restore backup analyze check rename
field_list field_list_item field_spec kill
select_item_list select_item values_list no_braces
@@ -549,6 +550,7 @@ verb_clause:
| lock
| kill
| optimize
+ | purge
| rename
| repair
| replace
@@ -2147,6 +2149,10 @@ show_param:
if (!add_table_to_list($3,NULL))
YYABORT;
}
+ | MASTER_SYM LOGS_SYM
+ {
+ Lex->sql_command = SQLCOM_SHOW_BINLOGS;
+ }
| keys_or_index FROM table_ident opt_db
{
Lex->sql_command= SQLCOM_SHOW_KEYS;
@@ -2246,6 +2252,13 @@ reset_option:
SLAVE { Lex->type|= REFRESH_SLAVE; }
| MASTER_SYM { Lex->type|= REFRESH_MASTER; }
+purge:
+ PURGE { Lex->sql_command = SQLCOM_PURGE; Lex->type=0;}
+ MASTER_SYM LOGS_SYM TO_SYM TEXT_STRING
+ {
+ Lex->to_log = $6.str;
+ }
+
/* kill threads */
kill: