Below is the list of changes that have just been committed into a local
5.1 repository of cps. When cps does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet
1.1951 05/12/03 01:45:18 petr@stripped +21 -0
WL#1019 SELECT FROM LOGS: post-review fixes
sql/table.h
1.117 05/12/03 01:45:06 petr@stripped +1 -0
add a flag for in TABLE to mark if the table was locked
by the logger. This is needed for correct name lock
processing (during TRUNCATE and FLUSH LOGS)
sql/sql_parse.cc
1.482 05/12/03 01:45:06 petr@stripped +45 -9
Fix FLUSH LOGS to reopen log tablse.
Fix formatting from the previous patch.
sql/sql_delete.cc
1.159 05/12/03 01:45:06 petr@stripped +34 -0
fix TRUNCATE to work with log tables
sql/sql_class.h
1.269 05/12/03 01:45:05 petr@stripped +78 -4
LOGGER class definition is moved here. This is needed for logger
methods to be seen in the whole server.
sql/sql_base.cc
1.279 05/12/03 01:45:05 petr@stripped +30 -16
TABLE objects used by the logger should be skipped
during refreshes (as log tables are always opened
and locked). fix table_is_used to skip them. This
is needed for FLUSH LOGS to work.
sql/share/errmsg.txt
1.53 05/12/03 01:45:05 petr@stripped +4 -0
add new error messages for the log tables
sql/mysqld.cc
1.490 05/12/03 01:45:04 petr@stripped +36 -18
added option to enable both log formats simultaneously:
"--both-log-formats". Now we could have log tables along
with the old logs.
Fix initialization of the log tables.
sql/mysql_priv.h
1.343 05/12/03 01:45:04 petr@stripped +10 -7
define common log routines
sql/log_event.cc
1.191 05/12/03 01:45:03 petr@stripped +1 -1
fix formatting from the previous patch
sql/log.cc
1.176 05/12/03 01:45:02 petr@stripped +451 -421
fix logging routines: refactored MYSQL_LOG::write() for slow and
general log to avoid code duplication. Now all common actions
are collected in the general log handling routinesm before
individual handlers are called.
sql/lock.cc
1.78 05/12/03 01:45:02 petr@stripped +22 -0
Deny locking of the log tables, which is incompatible with
concurrent insert, unless called from a logger THD.
sql/examples/ha_tina.h
1.9 05/12/03 01:45:02 petr@stripped +15 -1
enable concurrent insert for CSV
sql/examples/ha_tina.cc
1.23 05/12/03 01:45:02 petr@stripped +96 -83
Remove old locking for the log tables, add support for concurrent insert
(see bk commit - 5.1 tree (petr:1.1910) for standalone patch), add some log
tables-specific handling.
scripts/mysql_fix_privilege_tables.sql
1.29 05/12/03 01:45:02 petr@stripped +32 -22
Use SP to create log tables. If we have no CSV support in the
server, log tables should not be created.
scripts/mysql_create_system_tables.sh
1.27 05/12/03 01:45:01 petr@stripped +25 -42
Use SP for the log tables creation. If we have no CSV support in the
server, log tables should not be created. The SP is created in one line.
This is because DELIMITER does not work in bootstrap mode. It is only
recognized by the client.
mysql-test/t/log_tables.test
1.2 05/12/03 01:45:01 petr@stripped +51 -36
correct the test to reflect new concurrent insert-based locking for
the log tables.
mysql-test/t/csv.test
1.3 05/12/03 01:45:01 petr@stripped +38 -0
add tests for concurrent insert (the functionality is added
to CSV in this patch)
mysql-test/r/log_tables.result
1.2 05/12/03 01:45:01 petr@stripped +19 -24
correct result file
mysql-test/r/csv.result
1.2 05/12/03 01:45:01 petr@stripped +17 -0
correct result file
mysql-test/lib/init_db.sql
1.17 05/12/03 01:45:01 petr@stripped +4 -21
Create an SP for the log tables creation. If we have
no CSV support in the server, log tables should not
be created. The SP is created in one line. This is because
DELIMITER does not work in bootstrap mode. It is only
recognized by the client.
configure.in
1.309 05/12/03 01:45:00 petr@stripped +1 -1
ha_tina should be compiled in by default for log tables to work
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: petr
# Host: owlet.
# Root: /home/cps/mysql/devel/mysql-5.1-logs-curr
--- 1.308/configure.in 2005-11-08 09:36:52 +03:00
+++ 1.309/configure.in 2005-12-03 01:45:00 +03:00
@@ -2393,7 +2393,7 @@
])
MYSQL_STORAGE_ENGINE(example)
MYSQL_STORAGE_ENGINE(archive)
-MYSQL_STORAGE_ENGINE(csv,,,,,tina_hton,,ha_tina.o)
+MYSQL_STORAGE_ENGINE(csv,,,"yes",,tina_hton,,ha_tina.o)
MYSQL_STORAGE_ENGINE(blackhole)
MYSQL_STORAGE_ENGINE(federated)
MYSQL_STORAGE_ENGINE(ndbcluster,,ndbcluster,,,,storage/ndb,,,[
--- 1.77/sql/lock.cc 2005-09-15 09:31:40 +04:00
+++ 1.78/sql/lock.cc 2005-12-03 01:45:02 +03:00
@@ -481,6 +481,28 @@
table_ptr[i]->s->table_name);
return 0;
}
+
+ /*
+ Deny locking of the log tables, which is incompatible with
+ concurrent insert. Unless called from a logger THD:
+ general_log_thd or slow_log_thd.
+ */
+ if (table_ptr[i]->s->log_table &&
+ thd->lex->sql_command != SQLCOM_TRUNCATE &&
+ !(thd->lex->sql_command == SQLCOM_FLUSH &&
+ thd->lex->type & REFRESH_LOG) &&
+ (thd != general_log_thd) && (thd != slow_log_thd) &&
+ (table_ptr[i]->reginfo.lock_type >= TL_READ_NO_INSERT))
+ {
+ /*
+ The check >= TL_READ_NO_INSERT denies all write locks
+ plus the only read lock (TL_READ_NO_INSERT itself)
+ */
+ table_ptr[i]->reginfo.lock_type == TL_READ_NO_INSERT ?
+ my_error(ER_CANT_READ_LOCK_LOG_TABLE, MYF(0)) :
+ my_error(ER_CANT_WRITE_LOCK_LOG_TABLE, MYF(0));
+ return 0;
+ }
}
if (!(sql_lock= (MYSQL_LOCK*)
--- 1.175/sql/log.cc 2005-11-15 13:52:25 +03:00
+++ 1.176/sql/log.cc 2005-12-03 01:45:02 +03:00
@@ -34,14 +34,11 @@
#include "message.h"
#endif
-/*
- Currently we have only 3 kinds of logging functions: old-fashioned
- logs, stdout and csv logging routines.
-*/
-#define MAX_LOG_HANDLERS_NUM 3
+/* max size of the log message */
+#define MAX_LOG_BUFFER_SIZE 1024
+#define MAX_USER_HOST_SIZE 512
+#define MAX_TIME_SIZE 32
-/* the following vars are used for the log tables */
-uint is_csv_logs_initialized= FALSE;
/*
We create artificial THD for each of the logs. Since they are shared
between threads.
@@ -49,44 +46,7 @@
THD *general_log_thd= NULL, *slow_log_thd= NULL;
TABLE_LIST general_log, slow_log;
-/* typedefs for log processing functions */
-typedef int (*error_log_handler)(enum loglevel level, const char *format,
- va_list args);
-
-typedef bool (*slow_log_handler)(THD *thd, const char *query, uint query_length,
- time_t query_start_arg);
-
-typedef bool (*general_log_handler)(THD *thd,enum enum_server_command command,
- const char *format, va_list args_arg);
-
-
-/* Class which manages the log tables */
-class Logger
-{
- /* NULL-terminated arrays of logging functions*/
- error_log_handler error_log_print_list[MAX_LOG_HANDLERS_NUM + 1];
- slow_log_handler slow_log_print_list[MAX_LOG_HANDLERS_NUM + 1];
- general_log_handler general_log_print_list[MAX_LOG_HANDLERS_NUM + 1];
-
-public:
-
- int error_log_print(enum loglevel level, const char *format,
- va_list args);
- bool slow_log_print(THD *thd, const char *query, uint query_length,
- time_t query_start_arg);
- bool general_log_print(THD *thd,enum enum_server_command command,
- const char *format, va_list args);
- int init_csv_logs();
- int init(enum enum_printer error_log_printer,
- enum enum_printer slow_log_printer,
- enum enum_printer general_log_printer);
- void init_error_log(enum enum_printer error_log_printer);
- void init_slow_log(enum enum_printer slow_log_printer);
- void init_general_log(enum enum_printer general_log_printer);
-};
-
-Logger logger;
-
+LOGGER logger;
MYSQL_LOG mysql_log, mysql_slow_log, mysql_bin_log;
ulong sync_binlog_counter= 0;
@@ -137,10 +97,10 @@
/*
- Open general log table
+ Open log table of a given type (general or slow log)
- SYNOPSYS
- general_log_table_open()
+ SYNOPSIS
+ open_log_table()
tables pointer to the TABLE_LIST structure which will be used
to open the general log. Later we'll use tables->table
to perform logging in log_general_to_csv()
@@ -148,90 +108,97 @@
DESCRIPTION
The function is used during the server startup. We open the log tables and
- mark them as such. This is needed to provide approproate locking for the
- log tables: the log tables downgrade all locks to TL_WRITE_ALLOW_WRITE,
- so that nobody could lock down the system. Log tables are opened during
- the whole time, while server is running.
+ mark them as such. Log tables are open during the whole time, while
+ server is running.
RETURN
0 - ok
1 - error occured
*/
-int general_log_table_open(TABLE_LIST *tables)
+int open_log_table(uint log_type)
{
+ THD *log_thd, *curr= current_thd;
+ TABLE_LIST *tables;
+ DBUG_ENTER("open_log_table");
- DBUG_ENTER("general_log_table_open");
+ switch (log_type) {
+ case LOG_GENERAL:
+ log_thd= general_log_thd;
+ bzero((char*) &general_log, sizeof(TABLE_LIST));
+ tables= &general_log;
+ tables->alias= tables->table_name= (char*) "general_log";
+ tables->table_name_length= 11;
+ break;
+ case LOG_SLOW:
+ log_thd= slow_log_thd;
+ bzero((char*) &slow_log, sizeof(TABLE_LIST));
+ tables= &slow_log;
+ tables->alias= tables->table_name= (char*) "slow_log";
+ tables->table_name_length= 8;
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
- if (!general_log_thd)
+ /*
+ This way we check that appropriate log thd was created ok during
+ initialization. We cannot check "is_log_tables_initialized" var, as
+ the very initlialization is not finished until this function is
+ completed in the very first time.
+ */
+ if (!log_thd)
+ {
+ DBUG_PRINT("error",("Cannot initialize log tables"));
DBUG_RETURN(1);
+ }
- general_log_thd->store_globals();
+ log_thd->store_globals();
- general_log_thd->db= my_strdup("mysql",MYF(0));
- general_log_thd->db_length= 5;
- bzero((char*) tables, sizeof(TABLE_LIST));
- tables->alias= tables->table_name=(char*) "general_log";
- tables->lock_type= TL_WRITE_ALLOW_WRITE;
- tables->db= general_log_thd->db;
+ log_thd->db= my_strdup("mysql", MYF(0));;
+ log_thd->db_length= 5;
- if (simple_open_n_lock_tables(general_log_thd, tables))
- DBUG_RETURN(1);
+ tables->lock_type= TL_WRITE_CONCURRENT_INSERT;
+ tables->db= log_thd->db;
+ tables->db_length= log_thd->db_length;
- if (tables->table->file->extra(HA_EXTRA_MARK_AS_LOG_TABLE))
+ if (simple_open_n_lock_tables(log_thd, tables) ||
+ tables->table->file->extra(HA_EXTRA_MARK_AS_LOG_TABLE) ||
+ tables->table->file->ha_rnd_init(0))
+ {
+ if (curr)
+ curr->store_globals();
+ else
+ {
+ my_pthread_setspecific_ptr(THR_THD, 0);
+ my_pthread_setspecific_ptr(THR_MALLOC, 0);
+ }
DBUG_RETURN(1);
+ }
- if (tables->table->file->ha_rnd_init(0))
- DBUG_RETURN(1);
+ tables->table->locked_by_logger= TRUE;
+
+ if (curr)
+ curr->store_globals();
+ else
+ {
+ my_pthread_setspecific_ptr(THR_THD, 0);
+ my_pthread_setspecific_ptr(THR_MALLOC, 0);
+ }
DBUG_RETURN(0);
}
-
/*
- Open slow log table
-
- SYNOPSYS
- slow_log_table_open()
- tables pointer to the TABLE_LIST structure which will be used
- to open the slow log.
-
- DESCRIPTION
-
- The function is used during the server startup. For more details see
- comment to general_log_table_open()
-
- RETURN
- 0 - ok
- 1 - error occured
+ this differs from open_log_table by a check, which we cannot
+ do in open_log_table since it is not yet valid at startup.
+ this code assumes that we have logger mutex locked
*/
-
-int slow_log_table_open(TABLE_LIST *tables)
+int reopen_log_table(uint log_type)
{
- DBUG_ENTER("slow_log_table_open");
-
- if (!slow_log_thd)
- DBUG_RETURN(1);
-
- slow_log_thd->store_globals();
-
- slow_log_thd->db= my_strdup("mysql",MYF(0));
- slow_log_thd->db_length= 5;
- bzero((char*) tables, sizeof(TABLE_LIST));
- tables->alias= tables->table_name=(char*) "slow_log";
- tables->lock_type= TL_WRITE_ALLOW_WRITE;
- tables->db= slow_log_thd->db;
-
- if (simple_open_n_lock_tables(slow_log_thd, tables))
- DBUG_RETURN(1);
-
- if (tables->table->file->extra(HA_EXTRA_MARK_AS_LOG_TABLE))
- DBUG_RETURN(1);
-
- /* init handler */
- tables->table->file->ha_rnd_init(0);
-
- DBUG_RETURN(0);
+ if (!logger.is_log_tables_initialized)
+ return 0;
+ return open_log_table(log_type);
}
/* log handlers */
@@ -239,12 +206,9 @@
/*
Log command to the general log table
- SYNOPSYS
+ SYNOPSIS
log_general_to_csv()
- thd THD of the query
command the type of the command being logged
- format format string for the command. as in printf()
- args arguments for the command
DESCRIPTION
@@ -255,90 +219,41 @@
1 - error occured
*/
-bool log_general_to_csv(THD *thd,enum enum_server_command command,
- const char *format, va_list args)
+
+static bool log_general_to_csv(const char *event_time, uint event_time_len,
+ time_t time_t_event_time, const char *user_host,
+ uint user_host_len, int thread_id, int server_id,
+ const char *command_type, uint command_type_len,
+ const char *sql_text, uint sql_text_len)
{
TABLE *table= general_log.table;
- char message_buff[1024];
- Security_context *sctx= thd->security_ctx;
-
- DBUG_ENTER("log_general_to_csv");
- if (!general_log_thd)
- DBUG_RETURN(1);
-
- /* for CURRENT_TIMESTAMP to work */
- general_log_thd->start_time= time((time_t*) 0);
-
- /* print the message to the buffer */
-
- if (what_to_log & (1L << (uint) command))
- {
- ulong id;
-
- if (thd)
- { /* Normal thread */
- if ((thd->options & OPTION_LOG_OFF)
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- && (sctx->master_access & SUPER_ACL)
-#endif
- )
- {
- DBUG_RETURN(0); /* No logging */
- }
- id= thd->thread_id;
- }
- else
- id=0; /* Log from connect handler */
-
- /* set CURRENT_TIMESTAMP */
- table->field[0]->set_null();
-
- /* fill in user_host value */
- sprintf(message_buff, "%s[%s] @ %s [%s]",
- sctx->priv_user ? sctx->priv_user : "",
- sctx->user ? sctx->user : "",
- sctx->host ? sctx->host : "",
- sctx->ip ? sctx->ip : "");
-
- /* store the value */
- table->field[1]->store(message_buff,
- strlen(message_buff),
- &my_charset_latin1);
-
- table->field[2]->store((longlong) id);
- table->field[3]->store((longlong) server_id);
- table->field[4]->store(command_name[(uint) command],
- strlen(command_name[(uint) command]),
- &my_charset_latin1);
- /* prepare message */
- if (format)
- my_vsnprintf(message_buff,
- sizeof(message_buff), format, args);
- else
- message_buff[0]= '\0';
-
- /* store the message */
- table->field[5]->store(message_buff,
- strlen(message_buff),
- &my_charset_latin1);
- table->file->write_row(table->record[0]);
-
- }
+ general_log_thd->start_time= time_t_event_time;
+ /* set default value (which is CURRENT_TIMESTAMP) */
+ table->field[0]->set_null();
- DBUG_RETURN(0);
+ table->field[1]->store(user_host,
+ user_host_len,
+ &my_charset_latin1);
+ table->field[2]->store((longlong) thread_id);
+ table->field[3]->store((longlong) server_id);
+ table->field[4]->store(command_type,
+ command_type_len,
+ &my_charset_latin1);
+ table->field[5]->store(sql_text,
+ sql_text_len,
+ &my_charset_latin1);
+ table->file->write_row(table->record[0]);
+ return FALSE;
}
/*
Log a query to the slow log table
- SYNOPSYS
+ SYNOPSIS
log_slow_to_csv()
thd THD of the query
- query the very query in a text form
- query_string length of the query string
- query_start_arg time when the query was started
DESCRIPTION
@@ -349,52 +264,41 @@
1 - error occured
*/
-bool log_slow_to_csv(THD *thd,const char *query, uint query_length,
- time_t query_start_arg)
+bool log_slow_to_csv(THD *thd, time_t current_time, time_t query_start_arg,
+ const char *user_host, uint user_host_len,
+ longlong query_time, longlong lock_time, bool is_command,
+ const char *sql_text, uint sql_text_len)
{
- my_time_t current_time;
- Security_context *sctx= thd->security_ctx;
-
/* table variables */
TABLE *table= slow_log.table;
- char message_buff[1024];
+ THD *curr= current_thd;
DBUG_ENTER("log_slow_to_csv");
- if (!slow_log_thd)
- DBUG_RETURN(1);
-
- /* for CURRENT_TIMESTAMP to work */
- slow_log_thd->start_time= time((time_t*) 0);
+ /*
+ Set start time for CURRENT_TIMESTAMP to the start of the query.
+ This will be default value for the field
+ */
+ slow_log_thd->start_time= query_start_arg;
- /* compute current time */
- current_time= time(NULL);
/* set default value (which is CURRENT_TIMESTAMP) */
table->field[0]->set_null();
- /* fill in user_host value */
- sprintf(message_buff, "%s[%s] @ %s [%s]",
- sctx->priv_user ? sctx->priv_user : "",
- sctx->user ? sctx->user : "",
- sctx->host ? sctx->host : "",
- sctx->ip ? sctx->ip : "");
-
/* store the value */
- table->field[1]->store(message_buff,
- strlen(message_buff),
+ table->field[1]->store(user_host,
+ user_host_len,
&my_charset_latin1);
if (query_start_arg)
{
/* query_time */
- table->field[2]->store((longlong) (current_time - query_start_arg));
+ table->field[2]->store(query_time);
/* lock_time */
- table->field[3]->store((longlong)
- (thd->time_after_lock - query_start_arg));
+ table->field[3]->store(lock_time);
/* rows_sent */
table->field[4]->store((longlong) thd->sent_row_count);
- /* rows_sent rows_examined*/
+ /* rows_sent rows_examined */
table->field[5]->store((longlong) thd->examined_row_count);
}
else
@@ -420,27 +324,15 @@
/* set value if we do an insert on autoincrement column */
if (thd->insert_id_used)
- {
- /* insert_id */
- if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
- table->field[8]->store((longlong) thd->last_insert_id);
- else
- table->field[8]->set_null();
- }
+ table->field[8]->store((longlong) thd->last_insert_id);
else
table->field[8]->set_null();
table->field[9]->store((longlong) server_id);
- if (!query)
- /* sql_text */
- table->field[10]->store(command_name[thd->command],
- strlen(command_name[thd->command]),
- &my_charset_latin1);
- else
- table->field[10]->store(query,
- query_length,
- &my_charset_latin1);
+ /* sql_text */
+ table->field[10]->store(sql_text,sql_text_len,
+ &my_charset_latin1);
/* write the row */
table->file->write_row(table->record[0]);
@@ -454,72 +346,196 @@
return vprint_msg_to_log(level, format, args);
}
-bool log_slow_old(THD *thd, const char *query, uint query_length,
- time_t query_start_arg)
+bool log_slow_old(THD *thd, time_t current_time, time_t query_start_arg,
+ const char *user_host, uint user_host_len,
+ longlong query_time, longlong lock_time, bool is_command,
+ const char *sql_text, uint sql_text_len)
+{
+ return mysql_slow_log.write(thd, current_time, query_start_arg,
+ user_host, user_host_len,
+ query_time, lock_time, is_command,
+ sql_text, sql_text_len);
+}
+
+bool log_general_old(const char *event_time, uint event_time_len,
+ time_t time_t_event_time, const char *user_host,
+ uint user_host_len, int thread_id, int server_id,
+ const char *command_type, uint command_type_len,
+ const char *sql_text, uint sql_text_len)
+{
+ return mysql_log.write(event_time, event_time_len, time_t_event_time,
+ user_host, user_host_len, thread_id, server_id,
+ command_type, command_type_len, sql_text,
+ sql_text_len);
+}
+
+void LOGGER::init_pthread_objects()
{
- return mysql_slow_log.write(thd, query, query_length, query_start_arg);
+ DBUG_ASSERT(inited == 0);
+ inited= 1;
+ (void) pthread_mutex_init(&LOCK_logger, MY_MUTEX_INIT_SLOW);
}
-bool log_general_old(THD *thd, enum enum_server_command command,
- const char *format, va_list args)
+void LOGGER::lock()
{
- return mysql_log.write(thd, command, format, args);
+ (void) pthread_mutex_lock(&LOCK_logger);
}
+void LOGGER::unlock()
+{
+ (void) pthread_mutex_unlock(&LOCK_logger);
+}
-int Logger::error_log_print(enum loglevel level, const char *format,
+void LOGGER::cleanup()
+{
+ (void) pthread_mutex_destroy(&LOCK_logger);
+}
+
+int LOGGER::error_log_print(enum loglevel level, const char *format,
va_list args)
{
uint error= 0;
error_log_handler *current_handler= error_log_print_list;
+ /* currently we don't need locking here as there is no error_log table */
+
while (*current_handler)
error+= (*current_handler++)(level, format, args);
return error;
}
-bool Logger::slow_log_print(THD *thd, const char *query, uint query_length,
+bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length,
time_t query_start_arg)
{
uint error= 0;
slow_log_handler *current_handler= slow_log_print_list;
+ char message_buff[MAX_LOG_BUFFER_SIZE];
+ char user_host_buff[MAX_USER_HOST_SIZE];
+
+ my_time_t current_time;
+ Security_context *sctx= thd->security_ctx;
+ uint message_buff_len= 0, user_host_len= 0;
+ uint command_name_len= 0;
+ longlong query_time= 0, lock_time= 0;
+ longlong last_insert_id= 0, insert_id= 0;
+
+ current_time= time(NULL);
+
+ if (!(thd->options & OPTION_UPDATE_LOG))
+ return 0;
+
+
+ lock();
+
+ /* fill in user_host value: the format is "%s[%s] @ %s [%s]" */
+ strxnmov(user_host_buff, MAX_USER_HOST_SIZE,
+ sctx->priv_user ? sctx->priv_user : "", "[",
+ sctx->user ? sctx->user : "", "] @ ",
+ sctx->host ? sctx->host : "", " [",
+ sctx->ip ? sctx->ip : "", "]", NullS);
+ user_host_len= strlen(user_host_buff);
+
+ if (query_start_arg)
+ {
+ query_time= (longlong) (current_time - query_start_arg);
+ lock_time= (longlong) (thd->time_after_lock - query_start_arg);
+ }
+
+ if (thd->last_insert_id_used)
+ last_insert_id= (longlong) thd->current_insert_id;
+
+ /* set value if we do an insert on autoincrement column */
+ if (thd->insert_id_used)
+ insert_id= (longlong) thd->last_insert_id;
+
+ if (!query)
+ command_name_len= strlen(command_name[thd->command]);
+
while (*current_handler)
- error+= (*current_handler++)(thd, query, query_length, query_start_arg);
+ error+= (*current_handler++)(thd, current_time, query_start_arg,
+ user_host_buff, user_host_len, query_time,
+ lock_time, query == NULL,
+ query ? query :command_name[thd->command],
+ query ? query_length : command_name_len);
- return error;
+ unlock();
+ return error != 0;
}
-bool Logger::general_log_print(THD *thd,enum enum_server_command command,
+bool LOGGER::general_log_print(THD *thd, enum enum_server_command command,
const char *format, va_list args)
{
uint error= 0;
general_log_handler *current_handler= general_log_print_list;
- while (*current_handler)
- error+= (*current_handler++)(thd, command, format, args);
-
- return error;
-}
+ /* print the message to the buffer */
-int Logger::init_csv_logs()
-{
- if (!is_csv_logs_initialized ||
- !(general_log_thd && slow_log_thd))
+ if (what_to_log & (1L << (uint) command))
{
- if ((!(general_log_thd= new THD)) || general_log_table_open(&general_log))
- return 1;
- if ((!(slow_log_thd= new THD)) || slow_log_table_open(&slow_log))
- return 1;
- is_csv_logs_initialized= TRUE;
- }
+ char message_buff[MAX_LOG_BUFFER_SIZE];
+ char user_host_buff[MAX_USER_HOST_SIZE];
+ char time_buff[MAX_TIME_SIZE];
+ Security_context *sctx= thd->security_ctx;
+ ulong id;
+ uint message_buff_len= 0, user_host_len= 0;
+ uint time_buff_len= 0, command_name_len= 0;
- return 0;
-}
+ if (thd)
+ { /* Normal thread */
+ if ((thd->options & OPTION_LOG_OFF)
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ && (sctx->master_access & SUPER_ACL)
+#endif
+ )
+ {
+ return 0; /* No logging */
+ }
+ id= thd->thread_id;
+ }
+ else
+ id=0; /* Log from connect handler */
+
+ lock();
+ time_t current_time= time(NULL);
+ struct tm start;
+ localtime_r(¤t_time, &start);
+
+ time_buff_len= my_snprintf(time_buff, MAX_TIME_SIZE,
+ "%02d-%02d-%02d %2d:%02d:%02d",
+ start.tm_year % 100, start.tm_mon + 1,
+ start.tm_mday, start.tm_hour,
+ start.tm_min, start.tm_sec);
+
+ /* fill in user_host value */
+ strxnmov(user_host_buff, MAX_USER_HOST_SIZE,
+ sctx->priv_user ? sctx->priv_user : "", "[",
+ sctx->user ? sctx->user : "", "] @ ",
+ sctx->host ? sctx->host : "", " [",
+ sctx->ip ? sctx->ip : "", "]", NullS);
+ user_host_len= strlen(user_host_buff);
+ command_name_len= strlen(command_name[(uint) command]);
+
+ /* prepare message */
+ if (format)
+ message_buff_len= my_vsnprintf(message_buff,
+ sizeof(message_buff), format, args);
+ else
+ message_buff[0]= '\0';
+ while (*current_handler)
+ error+= (*current_handler++) (time_buff, time_buff_len, current_time,
+ user_host_buff, user_host_len, id,
+ server_id, command_name[(uint) command],
+ command_name_len, message_buff,
+ message_buff_len);
+ unlock();
+ }
+ return error != 0;
+}
-void Logger::init_error_log(enum enum_printer error_log_printer)
+void LOGGER::init_error_log(enum enum_printer error_log_printer)
{
switch (error_log_printer) {
case NONE:
@@ -539,7 +555,7 @@
}
}
-void Logger::init_slow_log(enum enum_printer slow_log_printer)
+void LOGGER::init_slow_log(enum enum_printer slow_log_printer)
{
switch (slow_log_printer) {
case NONE:
@@ -561,7 +577,7 @@
}
}
-void Logger::init_general_log(enum enum_printer general_log_printer)
+void LOGGER::init_general_log(enum enum_printer general_log_printer)
{
switch (general_log_printer) {
case NONE:
@@ -584,41 +600,97 @@
}
-int Logger::init(enum enum_printer error_log_printer,
+int LOGGER::init(enum enum_printer error_log_printer,
enum enum_printer slow_log_printer,
enum enum_printer general_log_printer)
{
- int error;
-
/* error log table is not supported yet */
DBUG_ASSERT(error_log_printer != CSV);
- /* no error log table yet */
- if (slow_log_printer == CSV ||
- general_log_printer == CSV)
- error= init_csv_logs();
+ lock();
init_error_log(error_log_printer);
+
+ if (slow_log_printer >= CSV ||
+ general_log_printer >= CSV)
+ {
+ if (!general_log_thd)
+ general_log_thd= new THD;
+
+ if (!slow_log_thd)
+ slow_log_thd= new THD;
+
+ if (!is_log_tables_initialized && general_log_thd && slow_log_thd &&
+ !open_log_table(LOG_GENERAL) && !open_log_table(LOG_SLOW))
+ is_log_tables_initialized= TRUE;
+ else
+ {
+ sql_print_error("Failed to initialize log tables. "
+ "Falling back to the old-fashioned logs");
+ /* fallback to old-fashioned logging routines */
+ slow_log_printer= LEGACY;
+ general_log_printer= LEGACY;
+ }
+ }
init_slow_log(slow_log_printer);
init_general_log(general_log_printer);
- return error;
+ unlock();
+
+ return 0;
}
-void close_log_tables()
+/*
+ lock_in_use Set to 1 (0 = default) if caller has a lock on
+ LOCK_open
+*/
+void close_log_table(uint log_type, bool lock_in_use)
{
- if (is_csv_logs_initialized)
- {
- /* finalize work with tables */
+ THD *curr= current_thd;
+
+ if (!logger.is_log_tables_initialized)
+ return; /* do nothing */
+
+ switch (log_type) {
+ case LOG_GENERAL:
+ general_log_thd->store_globals();
(general_log.table)->file->ha_rnd_end();
+ /* discard logger mark before unlock*/
+ general_log.table->locked_by_logger= FALSE;
+ close_thread_tables(general_log_thd, lock_in_use);
+ break;
+ case LOG_SLOW:
+ slow_log_thd->store_globals();
(slow_log.table)->file->ha_rnd_end();
- /* now we can close the log tables */
- close_thread_tables(general_log_thd);
- close_thread_tables(slow_log_thd);
- is_csv_logs_initialized= FALSE;
+ slow_log.table->locked_by_logger= FALSE;
+ close_thread_tables(slow_log_thd, lock_in_use);
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ if (curr)
+ curr->store_globals();
+ else
+ {
+ my_pthread_setspecific_ptr(THR_THD, 0);
+ my_pthread_setspecific_ptr(THR_MALLOC, 0);
}
}
+/*
+ Called during shutdown: we always open all log tables at
+ startup (even if they are not used for logging). Therefore
+ we should close them at shutdown.
+*/
+void close_log_tables()
+{
+ logger.lock();
+ close_log_table(LOG_GENERAL, FALSE);
+ close_log_table(LOG_SLOW, FALSE);
+ logger.is_log_tables_initialized= FALSE;
+ logger.unlock();
+}
+
/*
this function is mostly a placeholder.
@@ -2031,92 +2103,68 @@
DBUG_RETURN(error);
}
-
/*
Write to normal (not rotable) log
This is the format for the 'normal' log.
*/
-bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
- const char *format, va_list args)
+bool MYSQL_LOG::write(const char *event_time, uint event_time_len,
+ time_t time_t_event_time, const char *user_host,
+ uint user_host_len, int thread_id, int server_id,
+ const char *command_type, uint command_type_len,
+ const char *sql_text, uint sql_text_len)
{
- if (is_open() && (what_to_log & (1L << (uint) command)))
- {
- uint length;
- int error= 0;
- VOID(pthread_mutex_lock(&LOCK_log));
+ char buff[32];
+ uint length= 0;
- /* Test if someone closed between the is_open test and lock */
- if (is_open())
- {
- time_t skr;
- ulong id;
- char buff[32];
-
- if (thd)
- { // Normal thread
- if ((thd->options & OPTION_LOG_OFF)
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- && (thd->security_ctx->master_access & SUPER_ACL)
-#endif
-)
- {
- VOID(pthread_mutex_unlock(&LOCK_log));
- return 0; // No logging
- }
- id=thd->thread_id;
- if (thd->user_time || !(skr=thd->query_start()))
- skr=time(NULL); // Connected
- }
- else
- { // Log from connect handler
- skr=time(NULL);
- id=0;
- }
- if (skr != last_time)
- {
- last_time=skr;
- struct tm tm_tmp;
- struct tm *start;
- localtime_r(&skr,&tm_tmp);
- start=&tm_tmp;
- /* Note that my_b_write() assumes it knows the length for this */
- sprintf(buff,"%02d%02d%02d %2d:%02d:%02d\t",
- start->tm_year % 100,
- start->tm_mon+1,
- start->tm_mday,
- start->tm_hour,
- start->tm_min,
- start->tm_sec);
- if (my_b_write(&log_file, (byte*) buff,16))
- error=errno;
- }
- else if (my_b_write(&log_file, (byte*) "\t\t",2) < 0)
- error=errno;
- length=my_sprintf(buff,
- (buff, "%7ld %-11.11s", id,
- command_name[(uint) command]));
- if (my_b_write(&log_file, (byte*) buff,length))
- error=errno;
- if (format)
- {
- if (my_b_write(&log_file, (byte*) " ",1) ||
- my_b_vprintf(&log_file,format,args) == (uint) -1)
- error=errno;
- }
- if (my_b_write(&log_file, (byte*) "\n",1) ||
- flush_io_cache(&log_file))
- error=errno;
- if (error && ! write_error)
+ VOID(pthread_mutex_lock(&LOCK_log));
+
+ /* Test if someone closed between the is_open test and lock */
+ if (is_open())
+ {
+ /* Note that my_b_write() assumes it knows the length for this */
+ if (time_t_event_time != last_time)
{
- write_error=1;
- sql_print_error(ER(ER_ERROR_ON_WRITE),name,error);
+ last_time= time_t_event_time;
+ if (my_b_write(&log_file, (byte*) event_time, event_time_len))
+ goto err;
}
- }
- VOID(pthread_mutex_unlock(&LOCK_log));
- return error != 0;
+ else
+ if (my_b_write(&log_file, (byte*) "\t\t" ,2) < 0)
+ goto err;
+
+ /* command_type, thread_id */
+ length= my_snprintf(buff, 32, "%5ld ", thread_id);
+
+ if (my_b_write(&log_file, (byte*) buff, length))
+ goto err;
+
+ if (my_b_write(&log_file, (byte*) command_type, command_type_len))
+ goto err;
+
+ if (my_b_write(&log_file, (byte*) "\t", 1))
+ goto err;
+
+ /* sql_text */
+ if (my_b_write(&log_file, (byte*) sql_text, sql_text_len))
+ goto err;
+
+ if (my_b_write(&log_file, (byte*) "\n", 1) ||
+ flush_io_cache(&log_file))
+ goto err;
}
- return 0;
+
+ VOID(pthread_mutex_unlock(&LOCK_log));
+ return FALSE;
+err:
+
+ if (!write_error)
+ {
+ write_error= 1;
+ sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
+ }
+ VOID(pthread_mutex_unlock(&LOCK_log));
+ return TRUE;
}
@@ -2343,8 +2391,8 @@
return logger.slow_log_print(thd, query, query_length, query_start_arg);
}
-bool general_log_print(THD *thd,enum enum_server_command command,
- const char *format,...)
+bool general_log_print(THD *thd, enum enum_server_command command,
+ const char *format, ...)
{
va_list args;
uint error= 0;
@@ -2356,14 +2404,6 @@
return error;
}
-int mysql_init_logs(enum enum_printer error_log_printer,
- enum enum_printer slow_log_printer,
- enum enum_printer general_log_printer)
-{
- return logger.init(error_log_printer, slow_log_printer,
- general_log_printer);
-}
-
void MYSQL_LOG::rotate_and_purge(uint flags)
{
if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
@@ -2511,68 +2551,59 @@
Write to the slow query log.
*/
-bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
- time_t query_start_arg)
+bool MYSQL_LOG::write(THD *thd, time_t current_time, time_t query_start_arg,
+ const char *user_host, uint user_host_len,
+ longlong query_time, longlong lock_time, bool is_command,
+ const char *sql_text, uint sql_text_len)
{
- bool error=0;
- time_t current_time;
- if (!is_open())
- return 0;
+ bool error= 0;
DBUG_ENTER("MYSQL_LOG::write");
+ if (!is_open())
+ DBUG_RETURN(0);
+
VOID(pthread_mutex_lock(&LOCK_log));
if (is_open())
{ // Safety agains reopen
- int tmp_errno=0;
- char buff[80],*end;
- end=buff;
- if (!(thd->options & OPTION_UPDATE_LOG))
- {
- VOID(pthread_mutex_unlock(&LOCK_log));
- DBUG_RETURN(0);
- }
- if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT) || query_start_arg)
+ int tmp_errno= 0;
+ char buff[80], *end;
+ uint buff_len;
+ end= buff;
+
+ if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
{
Security_context *sctx= thd->security_ctx;
- current_time=time(NULL);
if (current_time != last_time)
{
- last_time=current_time;
- struct tm tm_tmp;
- struct tm *start;
- localtime_r(¤t_time,&tm_tmp);
- start=&tm_tmp;
+ last_time= current_time;
+ struct tm start;
+ localtime_r(¤t_time, &start);
+
+ buff_len= my_snprintf(buff, sizeof buff,
+ "# Time: %02d%02d%02d %2d:%02d:%02d\n",
+ start.tm_year % 100, start.tm_mon + 1,
+ start.tm_mday, start.tm_hour,
+ start.tm_min, start.tm_sec);
+
/* Note that my_b_write() assumes it knows the length for this */
- sprintf(buff,"# Time: %02d%02d%02d %2d:%02d:%02d\n",
- start->tm_year % 100,
- start->tm_mon+1,
- start->tm_mday,
- start->tm_hour,
- start->tm_min,
- start->tm_sec);
- if (my_b_write(&log_file, (byte*) buff,24))
+ if (my_b_write(&log_file, (byte*) buff, buff_len))
tmp_errno=errno;
}
- if (my_b_printf(&log_file, "# User@Host: %s[%s] @ %s [%s]\n",
- sctx->priv_user ?
- sctx->priv_user : "",
- sctx->user ? sctx->user : "",
- sctx->host ? sctx->host : "",
- sctx->ip ? sctx->ip : "") ==
- (uint) -1)
+ if (my_b_printf(&log_file, "# User@Host: ", sizeof("# User@Host: ") - 1))
tmp_errno=errno;
- }
- if (query_start_arg)
- {
- /* For slow query log */
- if (my_b_printf(&log_file,
- "# Query_time: %lu Lock_time: %lu Rows_sent: %lu Rows_examined: %lu\n",
- (ulong) (current_time - query_start_arg),
- (ulong) (thd->time_after_lock - query_start_arg),
- (ulong) thd->sent_row_count,
- (ulong) thd->examined_row_count) == (uint) -1)
+ if (my_b_printf(&log_file, user_host, user_host_len))
+ tmp_errno=errno;
+ if (my_b_write(&log_file, (byte*) "\n", 1))
tmp_errno=errno;
}
+ /* For slow query log */
+ if (my_b_printf(&log_file,
+ "# Query_time: %lu Lock_time: %lu"
+ " Rows_sent: %lu Rows_examined: %lu\n",
+ (ulong) query_time, (ulong) lock_time,
+ (ulong) thd->sent_row_count,
+ (ulong) thd->examined_row_count) == (uint) -1)
+ tmp_errno=errno;
if (thd->db && strcmp(thd->db,db))
{ // Database changed
if (my_b_printf(&log_file,"use %s;\n",thd->db) == (uint) -1)
@@ -2593,15 +2624,15 @@
end=longlong10_to_str((longlong) thd->last_insert_id,end,-10);
}
}
- if (thd->query_start_used)
- {
- if (query_start_arg != thd->query_start())
- {
- query_start_arg=thd->query_start();
- end=strmov(end,",timestamp=");
- end=int10_to_str((long) query_start_arg,end,10);
- }
- }
+
+ /*
+ This info usd to show up randomly, depending on whether query_start_
+ checked the query start time or not. now we always write current
+ timestamp to the slow log
+ */
+ end= strmov(end, ",timestamp=");
+ end= int10_to_str((long) current_time, end, 10);
+
if (end != buff)
{
*end++=';';
@@ -2610,14 +2641,13 @@
my_b_write(&log_file, (byte*) buff+1,(uint) (end-buff)))
tmp_errno=errno;
}
- if (!query)
+ if (is_command)
{
- end=strxmov(buff, "# administrator command: ",
- command_name[thd->command], NullS);
- query_length=(ulong) (end-buff);
- query=buff;
+ end= strxmov(buff, "# administrator command: ", NullS);
+ buff_len= (ulong) (end - buff);
+ my_b_write(&log_file, (byte*) buff, buff_len);
}
- if (my_b_write(&log_file, (byte*) query,query_length) ||
+ if (my_b_write(&log_file, (byte*) sql_text, sql_text_len) ||
my_b_write(&log_file, (byte*) ";\n",2) ||
flush_io_cache(&log_file))
tmp_errno=errno;
--- 1.190/sql/log_event.cc 2005-11-15 13:52:25 +03:00
+++ 1.191/sql/log_event.cc 2005-12-03 01:45:03 +03:00
@@ -1722,7 +1722,7 @@
/* If the query was not ignored, it is printed to the general log */
if (thd->net.last_errno != ER_SLAVE_IGNORED_TABLE)
- general_log_print(thd,COM_QUERY,"%s",thd->query);
+ general_log_print(thd, COM_QUERY, "%s", thd->query);
compare_errors:
--- 1.342/sql/mysql_priv.h 2005-11-15 13:52:25 +03:00
+++ 1.343/sql/mysql_priv.h 2005-12-03 01:45:04 +03:00
@@ -1090,18 +1090,18 @@
void sql_print_warning(const char *format, ...);
void sql_print_information(const char *format, ...);
-enum enum_printer
-{
- NONE,
- LEGACY,
- CSV,
- LEGACY_AND_CSV
-};
+/* type of the log table */
+#define LOG_SLOW 1
+#define LOG_GENERAL 2
int mysql_init_logs(enum enum_printer error_log_printer,
enum enum_printer slow_log_printer,
enum enum_printer general_log_printer);
+void mysql_init_logger();
+void mysql_cleanup_logger();
void close_log_tables();
+int reopen_log_table(uint log_type);
+void close_log_table(uint log_type, bool lock_in_use);
int error_log_print(enum loglevel level, const char *format,
va_list args);
@@ -1228,6 +1228,9 @@
extern uint opt_large_page_size;
extern MYSQL_LOG mysql_log,mysql_slow_log,mysql_bin_log;
+extern THD *general_log_thd, *slow_log_thd;
+extern LOGGER logger;
+extern TABLE_LIST general_log, slow_log;
extern FILE *bootstrap_file;
extern int bootstrap_error;
extern FILE *stderror_file;
--- 1.489/sql/mysqld.cc 2005-11-15 13:52:25 +03:00
+++ 1.490/sql/mysqld.cc 2005-12-03 01:45:04 +03:00
@@ -329,7 +329,7 @@
/* Global variables */
bool opt_log, opt_update_log, opt_bin_log, opt_slow_log;
-bool opt_error_log= IF_WIN(1,0), opt_old_log_format;
+bool opt_error_log= IF_WIN(1,0), opt_old_log_format, opt_both_log_formats;
bool opt_disable_networking=0, opt_skip_show_db=0;
my_bool opt_character_set_client_handshake= 1;
bool server_id_supplied = 0;
@@ -2310,12 +2310,12 @@
#ifdef EXTRA_DEBUG
sql_print_information("Got signal %d to shutdown mysqld",sig);
#endif
- /* close log tables, since we cannot log into them during shutdown */
+ /* close log tables, since we cannot use them during shutdown */
close_log_tables();
/* switch to the old log message processing */
- mysql_init_logs(opt_error_log ? LEGACY:NONE,
- opt_slow_log ? LEGACY:NONE,
- opt_log ? LEGACY:NONE);
+ logger.init(opt_error_log ? LEGACY:NONE,
+ opt_slow_log ? LEGACY:NONE,
+ opt_log ? LEGACY:NONE);
DBUG_PRINT("info",("Got signal: %d abort_loop: %d",sig,abort_loop));
if (!abort_loop)
{
@@ -2344,9 +2344,9 @@
(TABLE_LIST*) 0, ¬_used); // Flush logs
}
/* reenable logs after the options were reloaded */
- mysql_init_logs(opt_error_log ? LEGACY:NONE,
- opt_slow_log ? CSV:NONE,
- opt_log ? CSV:NONE);
+ logger.init(opt_error_log ? LEGACY:NONE,
+ opt_slow_log ? CSV:NONE,
+ opt_log ? CSV:NONE);
break;
#ifdef USE_ONE_SIGNAL_HAND
case THR_SERVER_ALARM:
@@ -2975,7 +2975,8 @@
}
}
- if (opt_old_log_format || (have_csv_db != SHOW_OPTION_YES))
+ if (opt_old_log_format || opt_both_log_formats ||
+ (have_csv_db != SHOW_OPTION_YES))
{
/* enable old-fashioned slow log */
if (opt_slow_log)
@@ -2986,14 +2987,19 @@
if (opt_log)
mysql_log.open_query_log(opt_logname);
- mysql_init_logs(opt_error_log ? LEGACY:NONE,
- opt_slow_log ? LEGACY:NONE,
- opt_log ? LEGACY:NONE);
+ if (opt_both_log_formats)
+ logger.init(opt_error_log ? LEGACY:NONE,
+ opt_slow_log ? LEGACY_AND_CSV:NONE,
+ opt_log ? LEGACY_AND_CSV:NONE);
+ else /* if --old-log-format or no CSV compiled in */
+ logger.init(opt_error_log ? LEGACY:NONE,
+ opt_slow_log ? LEGACY:NONE,
+ opt_log ? LEGACY:NONE);
}
else
- mysql_init_logs(opt_error_log ? LEGACY:NONE,
- opt_slow_log ? CSV:NONE,
- opt_log ? CSV:NONE);
+ logger.init(opt_error_log ? LEGACY:NONE,
+ opt_slow_log ? CSV:NONE,
+ opt_log ? CSV:NONE);
if (opt_update_log)
{
@@ -3309,8 +3315,10 @@
#endif
{
DEBUGGER_OFF;
+ /* init log mutexes */
+ logger.init_pthread_objects();
/* Set logs to legacy during startup. In fact this affects only error log */
- mysql_init_logs(LEGACY, LEGACY, LEGACY);
+ logger.init(LEGACY, LEGACY, LEGACY);
rpl_filter= new Rpl_filter;
binlog_filter= new Rpl_filter;
@@ -3585,7 +3593,9 @@
wait_for_signal_thread_to_end();
clean_up_mutexes();
my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
-
+
+ /* should be called last as we want to log errors to the very last moment */
+ logger.cleanup();
exit(0);
return(0); /* purecov: deadcode */
}
@@ -4515,7 +4525,7 @@
OPT_REPLICATE_IGNORE_TABLE, OPT_REPLICATE_WILD_DO_TABLE,
OPT_REPLICATE_WILD_IGNORE_TABLE, OPT_REPLICATE_SAME_SERVER_ID,
OPT_DISCONNECT_SLAVE_EVENT_COUNT, OPT_TC_HEURISTIC_RECOVER,
- OPT_ABORT_SLAVE_EVENT_COUNT, OPT_OLD_LOG_FORMAT,
+ OPT_ABORT_SLAVE_EVENT_COUNT, OPT_OLD_LOG_FORMAT, OPT_BOTH_LOG_FORMATS,
OPT_INNODB_DATA_HOME_DIR,
OPT_INNODB_DATA_FILE_PATH,
OPT_INNODB_LOG_GROUP_HOME_DIR,
@@ -5003,6 +5013,10 @@
"Enable old log file format. (No SELECT * FROM logs)",
(gptr*) &opt_old_log_format, 0, 0, GET_BOOL, OPT_ARG,
0, 0, 0, 0, 0, 0},
+ {"both-log-formats", OPT_BOTH_LOG_FORMATS,
+ "Enable old log file format along with log tables",
+ (gptr*) &opt_both_log_formats, 0, 0, GET_BOOL, OPT_ARG,
+ 0, 0, 0, 0, 0, 0},
{"log-tc", OPT_LOG_TC,
"Path to transaction coordinator log (used for transactions that affect "
"more than one storage engine, when binary log is disabled)",
@@ -6301,6 +6315,7 @@
mysql_home[0]= pidfile_name[0]= log_error_file[0]= 0;
opt_log= opt_update_log= opt_slow_log= 0;
opt_old_log_format= 0;
+ opt_both_log_formats= 0;
opt_bin_log= 0;
opt_disable_networking= opt_skip_show_db=0;
opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname= 0;
@@ -6686,6 +6701,9 @@
break;
case (int) OPT_OLD_LOG_FORMAT:
opt_old_log_format= 1;
+ break;
+ case (int) OPT_BOTH_LOG_FORMATS:
+ opt_both_log_formats= 1;
break;
case (int) OPT_SKIP_NEW:
opt_specialflag|= SPECIAL_NO_NEW_FUNC;
--- 1.278/sql/sql_base.cc 2005-11-15 13:52:26 +03:00
+++ 1.279/sql/sql_base.cc 2005-12-03 01:45:05 +03:00
@@ -1612,6 +1612,10 @@
Wait until all threads has closed the tables in the list
We have also to wait if there is thread that has a lock on this table even
if the table is closed
+ NOTE: log tables are handled differently by the logging routines.
+ E.g. general_log is always opened and locked by the logger
+ and the table handler used by the logger, will be skipped by
+ this check.
*/
bool table_is_used(TABLE *table, bool wait_for_name_lock)
@@ -1625,9 +1629,14 @@
search ;
search = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
{
- if (search->locked_by_flush ||
+ /*
+ Here we skip tables handlers, locked by logger. They are managed
+ separately by the logging routines.
+ */
+ if (!search->locked_by_logger &&
+ (search->locked_by_flush ||
search->locked_by_name && wait_for_name_lock ||
- search->db_stat && search->s->version < refresh_version)
+ search->db_stat && search->s->version < refresh_version))
return 1; // Table is used
}
} while ((table=table->next));
@@ -1849,19 +1858,24 @@
if (error == 5)
DBUG_RETURN(0); // we have just opened VIEW
- /*
- We can't mark all tables in 'mysql' database as system since we don't
- allow to lock such tables for writing with any other tables (even with
- other system tables) and some privilege tables need this.
- */
- if (!my_strcasecmp(system_charset_info, db, "mysql") &&
- !my_strcasecmp(system_charset_info, name, "proc"))
- entry->s->system_table= 1;
-
- if (!my_strcasecmp(system_charset_info, db, "mysql") &&
- (!my_strcasecmp(system_charset_info, name, "slow_log") ||
- !my_strcasecmp(system_charset_info, name, "general_log")))
- entry->s->log_table= 1;
+ if (!my_strcasecmp(system_charset_info, db, "mysql"))
+ {
+ /*
+ We can't mark all tables in 'mysql' database as system since we don't
+ allow to lock such tables for writing with any other tables (even with
+ other system tables) and some privilege tables need this.
+ */
+ if (!my_strcasecmp(system_charset_info, name, "proc"))
+ entry->s->system_table= 1;
+ else
+ {
+ if (!my_strcasecmp(system_charset_info, name, "general_log"))
+ entry->s->log_table= LOG_GENERAL;
+ else
+ if (!my_strcasecmp(system_charset_info, name, "slow_log"))
+ entry->s->log_table= LOG_SLOW;
+ }
+ }
if (Table_triggers_list::check_n_load(thd, db, name, entry, 0))
goto err;
@@ -1939,7 +1953,7 @@
which is already built.
RETURN
- 0 - OK
+ 0 - K
-1 - error
*/
--- 1.268/sql/sql_class.h 2005-11-15 13:52:26 +03:00
+++ 1.269/sql/sql_class.h 2005-12-03 01:45:05 +03:00
@@ -173,6 +173,74 @@
#define RP_LOCK_LOG_IS_ALREADY_LOCKED 1
#define RP_FORCE_ROTATE 2
+/* typedefs for log processing functions */
+typedef int (*error_log_handler)(enum loglevel level, const char *format,
+ va_list args);
+
+typedef bool (*slow_log_handler)(THD *thd, time_t current_time,
+ time_t query_start_arg, const char *user_host,
+ uint user_host_len, longlong query_time,
+ longlong lock_time, bool is_command,
+ const char *sql_text, uint sql_text_len);
+
+typedef bool (*general_log_handler)(const char *event_time,
+ uint event_time_len,
+ time_t time_t_event_time,
+ const char *user_host,
+ uint user_host_len, int thread_id,
+ int server_id, const char *command_type,
+ uint command_type_len,
+ const char *sql_text, uint sql_text_len);
+
+/*
+ Currently we have only 3 kinds of logging functions: old-fashioned
+ logs, stdout and csv logging routines.
+*/
+#define MAX_LOG_HANDLERS_NUM 3
+
+enum enum_printer
+{
+ NONE,
+ LEGACY,
+ CSV,
+ LEGACY_AND_CSV
+};
+
+/* Class which manages the log tables */
+class LOGGER
+{
+ pthread_mutex_t LOCK_logger;
+ /* flag to check whether logger mutex is initialized */
+ uint inited;
+ /* NULL-terminated arrays of logging functions*/
+ error_log_handler error_log_print_list[MAX_LOG_HANDLERS_NUM + 1];
+ slow_log_handler slow_log_print_list[MAX_LOG_HANDLERS_NUM + 1];
+ general_log_handler general_log_print_list[MAX_LOG_HANDLERS_NUM + 1];
+
+public:
+
+ bool is_log_tables_initialized;
+
+ LOGGER() : inited(0), is_log_tables_initialized(FALSE)
+ {}
+ void lock();
+ void unlock();
+ void init_pthread_objects();
+ void cleanup();
+ int error_log_print(enum loglevel level, const char *format,
+ va_list args);
+ bool slow_log_print(THD *thd, const char *query, uint query_length,
+ time_t query_start_arg);
+ bool general_log_print(THD *thd,enum enum_server_command command,
+ const char *format, va_list args);
+ int init(enum enum_printer error_log_printer,
+ enum enum_printer slow_log_printer,
+ enum enum_printer general_log_printer);
+ void init_error_log(enum enum_printer error_log_printer);
+ void init_slow_log(enum enum_printer slow_log_printer);
+ void init_general_log(enum enum_printer general_log_printer);
+};
+
class Log_event;
/*
@@ -306,11 +374,17 @@
const char *log_name);
void new_file(bool need_lock);
/* log a command to the old-fashioned general log */
- bool write(THD *thd, enum enum_server_command command,
- const char *format, va_list args);
+ bool write(const char *event_time, uint event_time_len,
+ time_t time_t_event_time, const char *user_host,
+ uint user_host_len, int thread_id, int server_id,
+ const char *command_type, uint command_type_len,
+ const char *sql_text, uint sql_text_len);
+
/* log a query to the old-fashioned slow query log */
- bool write(THD *thd, const char *query, uint query_length,
- time_t query_start=0);
+ bool write(THD *thd, time_t current_time, time_t query_start_arg,
+ const char *user_host, uint user_host_len,
+ longlong query_time, longlong lock_time, bool is_command,
+ const char *sql_text, uint sql_text_len);
bool write(Log_event* event_info); // binary log write
bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event);
--- 1.158/sql/sql_delete.cc 2005-11-04 23:09:56 +03:00
+++ 1.159/sql/sql_delete.cc 2005-12-03 01:45:06 +03:00
@@ -816,6 +816,8 @@
char path[FN_REFLEN];
TABLE **table_ptr;
bool error;
+ uint closed_log_tables= 0, lock_logger= 0;
+ TABLE_LIST *tmp_table_list;
DBUG_ENTER("mysql_truncate");
bzero((char*) &create_info,sizeof(create_info));
@@ -861,10 +863,34 @@
if (!ha_check_storage_engine_flag(table_type, HTON_CAN_RECREATE)
|| thd->lex->sphead)
goto trunc_by_del;
+
+ /* lock logger as we may need to deal with log tables */
if (lock_and_wait_for_table_name(thd, table_list))
DBUG_RETURN(TRUE);
}
+ /* loop through table_list and close log tables in use */
+ if (!my_strcasecmp(system_charset_info, table_list->db, "mysql"))
+ {
+ if (!my_strcasecmp(system_charset_info, table_list->table_name,
+ "general_log"))
+ {
+ lock_logger= 1;
+ logger.lock();
+ close_log_table(LOG_GENERAL, FALSE);
+ closed_log_tables= closed_log_tables | LOG_GENERAL;
+ }
+ else
+ if (!my_strcasecmp(system_charset_info, table_list->table_name,
+ "slow_log"))
+ {
+ lock_logger= 1;
+ logger.lock();
+ close_log_table(LOG_SLOW, FALSE);
+ closed_log_tables= closed_log_tables | LOG_SLOW;
+ }
+ }
+
*fn_ext(path)=0; // Remove the .frm extension
error= ha_create_table(path,&create_info,1);
query_cache_invalidate3(thd, table_list, 0);
@@ -886,6 +912,14 @@
VOID(pthread_mutex_lock(&LOCK_open));
unlock_table_name(thd, table_list);
VOID(pthread_mutex_unlock(&LOCK_open));
+
+ if (closed_log_tables & LOG_SLOW)
+ reopen_log_table(LOG_SLOW);
+
+ if (closed_log_tables & LOG_GENERAL)
+ reopen_log_table(LOG_GENERAL);
+ if (lock_logger)
+ logger.unlock();
}
else if (error)
{
--- 1.481/sql/sql_parse.cc 2005-11-15 13:52:26 +03:00
+++ 1.482/sql/sql_parse.cc 2005-12-03 01:45:06 +03:00
@@ -447,7 +447,7 @@
else if (res == 2) // client gave short hash, server has long hash
{
net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
- general_log_print(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
+ general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
DBUG_RETURN(-1);
}
net_printf_error(thd, ER_ACCESS_DENIED_ERROR,
@@ -1549,7 +1549,7 @@
packet, strlen(packet), thd->charset());
if (!mysql_change_db(thd, tmp.str, FALSE))
{
- general_log_print(thd,command,"%s",thd->db);
+ general_log_print(thd, command, "%s",thd->db);
send_ok(thd);
}
break;
@@ -1682,7 +1682,7 @@
if (alloc_query(thd, packet, packet_length))
break; // fatal error is set
char *packet_end= thd->query + thd->query_length;
- general_log_print(thd,command,"%s",thd->query);
+ general_log_print(thd, command, "%s", thd->query);
DBUG_PRINT("query",("%-.4096s",thd->query));
if (!(specialflag & SPECIAL_NO_PRIOR))
@@ -1791,7 +1791,7 @@
thd->query_length= strlen(packet); // for simplicity: don't optimize
if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
break;
- general_log_print(thd,command,"%s %s",table_list.table_name, fields);
+ general_log_print(thd, command, "%s %s", table_list.table_name, fields);
if (lower_case_table_names)
my_casedn_str(files_charset_info, table_list.table_name);
remove_escape(table_list.table_name); // This can't have wildcards
@@ -1820,7 +1820,7 @@
#endif
case COM_QUIT:
/* We don't calculate statistics for this command */
- general_log_print(thd,command,NullS);
+ general_log_print(thd, command, NullS);
net->error=0; // Don't give 'abort' message
error=TRUE; // End server
break;
@@ -1840,7 +1840,7 @@
}
if (check_access(thd,CREATE_ACL,db,0,1,0,is_schema_db(db)))
break;
- general_log_print(thd,command,packet);
+ general_log_print(thd, command, packet);
bzero(&create_info, sizeof(create_info));
mysql_create_db(thd, (lower_case_table_names == 2 ? alias : db),
&create_info, 0);
@@ -1865,7 +1865,7 @@
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
break;
}
- general_log_print(thd,command,db);
+ general_log_print(thd, command, db);
mysql_rm_db(thd, db, 0, 0);
break;
}
@@ -1907,7 +1907,7 @@
ulong options= (ulong) (uchar) packet[0];
if (check_global_access(thd,RELOAD_ACL))
break;
- general_log_print(thd,command,NullS);
+ general_log_print(thd, command, NullS);
if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, ¬_used))
send_ok(thd);
break;
@@ -6707,9 +6707,11 @@
#endif
if (options & REFRESH_LOG)
{
+ TABLE_LIST close_slow_log, close_general_log;
/*
Flush the normal query log, the update log, the binary log,
- the slow query log, and the relay log (if it exists).
+ the slow query log, the relay log (if it exists) and the log
+ tables.
*/
/*
@@ -6727,6 +6729,40 @@
rotate_relay_log(active_mi);
pthread_mutex_unlock(&LOCK_active_mi);
#endif
+ bzero((char*) &close_slow_log, sizeof(TABLE_LIST));
+ close_slow_log.alias= close_slow_log.table_name=(char*) "slow_log";
+ close_slow_log.table_name_length= 8;
+ close_slow_log.db= (char*) "mysql";
+ close_slow_log.db_length= 5;
+
+ bzero((char*) &close_general_log, sizeof(TABLE_LIST));
+ close_general_log.alias= close_general_log.table_name=(char*) "general_log";
+ close_general_log.table_name_length= 11;
+ close_general_log.db= (char*) "mysql";
+ close_general_log.db_length= 5;
+
+ /*
+ this will lock and wait for all but the logger thread to release the
+ tables. Then we could reopen log tables. Then release the name locks.
+ */
+ lock_and_wait_for_table_name(thd, &close_slow_log);
+ lock_and_wait_for_table_name(thd, &close_general_log);
+
+ logger.lock();
+
+ VOID(pthread_mutex_lock(&LOCK_open));
+ close_log_table(LOG_GENERAL, TRUE);
+ close_log_table(LOG_SLOW, TRUE);
+ close_general_log.next_local= &close_slow_log;
+ query_cache_invalidate3(thd, &close_general_log, 0);
+ unlock_table_name(thd, &close_slow_log);
+ unlock_table_name(thd, &close_general_log);
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ reopen_log_table(LOG_SLOW);
+ reopen_log_table(LOG_GENERAL);
+ /* end of log tables flush */
+ logger.unlock();
+
if (ha_flush_logs())
result=1;
if (flush_error_log())
--- 1.116/sql/table.h 2005-11-15 13:52:26 +03:00
+++ 1.117/sql/table.h 2005-12-03 01:45:06 +03:00
@@ -270,6 +270,7 @@
my_bool distinct,const_table,no_rows;
my_bool key_read, no_keyread;
my_bool locked_by_flush;
+ my_bool locked_by_logger;
my_bool locked_by_name;
my_bool fulltext_searched;
my_bool no_cache;
--- 1.52/sql/share/errmsg.txt 2005-11-06 15:12:49 +03:00
+++ 1.53/sql/share/errmsg.txt 2005-12-03 01:45:05 +03:00
@@ -5542,3 +5542,7 @@
ER_PLUGIN_IS_NOT_LOADED
eng "Plugin '%-.64s' is not loaded"
+ER_CANT_WRITE_LOCK_LOG_TABLE
+ eng "You can't write-lock a log table. Only read acces is possible."
+ER_CANT_READ_LOCK_LOG_TABLE
+ eng "You can't use usual read lock with log tables. Try READ LOCAL instead."
--- 1.1/mysql-test/r/csv.result 2004-08-13 07:54:29 +04:00
+++ 1.2/mysql-test/r/csv.result 2005-12-03 01:45:01 +03:00
@@ -4929,3 +4929,20 @@
Note 1051 Unknown table 't2'
Note 1051 Unknown table 't3'
Note 1051 Unknown table 't4'
+CREATE TABLE test_concurrent_insert ( val integer ) ENGINE = CSV;
+LOCK TABLES test_concurrent_insert READ LOCAL;
+INSERT INTO test_concurrent_insert VALUES (1);
+SELECT * FROM test_concurrent_insert;
+val
+1
+SELECT * FROM test_concurrent_insert;
+val
+UNLOCK TABLES;
+LOCK TABLES test_concurrent_insert WRITE;
+INSERT INTO test_concurrent_insert VALUES (2);
+SELECT * FROM test_concurrent_insert;
+val
+1
+2
+UNLOCK TABLES;
+DROP TABLE test_concurrent_insert;
--- 1.2/mysql-test/t/csv.test 2005-07-28 04:21:40 +04:00
+++ 1.3/mysql-test/t/csv.test 2005-12-03 01:45:01 +03:00
@@ -1315,3 +1315,41 @@
drop table if exists t1,t2,t3,t4;
# End of 4.1 tests
+
+#
+# Test CONCURRENT INSERT (5.1)
+#
+
+CREATE TABLE test_concurrent_insert ( val integer ) ENGINE = CSV;
+
+connect (con1,localhost,root,,);
+connect (con2,localhost,root,,);
+
+connection con1;
+# obtain TL_READ lock on the table
+LOCK TABLES test_concurrent_insert READ LOCAL;
+
+connection con2;
+# should pass despite of the lock
+INSERT INTO test_concurrent_insert VALUES (1);
+SELECT * FROM test_concurrent_insert;
+
+connection con1;
+# first connection should not notice the changes
+SELECT * FROM test_concurrent_insert;
+
+UNLOCK TABLES;
+
+# Now check that we see our own changes
+
+LOCK TABLES test_concurrent_insert WRITE;
+INSERT INTO test_concurrent_insert VALUES (2);
+SELECT * FROM test_concurrent_insert;
+UNLOCK TABLES;
+
+# cleanup
+DROP TABLE test_concurrent_insert;
+disconnect con2;
+disconnect con1;
+
+
--- 1.22/sql/examples/ha_tina.cc 2005-11-15 13:52:25 +03:00
+++ 1.23/sql/examples/ha_tina.cc 2005-12-03 01:45:02 +03:00
@@ -87,7 +87,7 @@
NULL, /* Flush logs */
NULL, /* Show status */
NULL, /* Replication Report Sent Binlog */
- HTON_NO_FLAGS /* Disable recreate during TRUCATE */
+ HTON_CAN_RECREATE
};
/*****************************************************************************
@@ -225,6 +225,9 @@
share->mapped_file= NULL; // We don't know the state as we just allocated it
if (get_mmap(share, 0) > 0)
goto error3;
+
+ /* init file lenght value used by readers */
+ share->saved_data_file_length= share->file_stat.st_size;
}
share->use_count++;
pthread_mutex_unlock(&tina_mutex);
@@ -304,8 +307,8 @@
These definitions are found in hanler.h
These are not probably completely right.
*/
- current_position(0), next_position(0), chain_alloced(0),
- chain_size(DEFAULT_CHAIN_LENGTH)
+ current_position(0), next_position(0), local_saved_data_file_length(0),
+ chain_alloced(0), chain_size(DEFAULT_CHAIN_LENGTH)
{
/* Set our original buffers from pre-allocated memory */
buffer.set(byte_buffer, IO_SIZE, system_charset_info);
@@ -320,7 +323,7 @@
}
-int ha_tina::tina_unlock()
+void ha_tina::tina_unlock()
{
if (share->is_log_table)
pthread_mutex_unlock(&share->mutex);
@@ -394,8 +397,8 @@
*/
int ha_tina::chain_append()
{
- if (chain_ptr != chain && (chain_ptr - 1)->end == current_position)
- (chain_ptr - 1)->end= next_position;
+ if ( chain_ptr != chain && (chain_ptr -1)->end == current_position)
+ (chain_ptr -1)->end= next_position;
else
{
/* We set up for the next position */
@@ -438,17 +441,15 @@
byte *end_ptr;
DBUG_ENTER("ha_tina::find_current_row");
- tina_lock();
-
mapped_ptr= (byte *)share->mapped_file + current_position;
- /* EOF should be counted as new line */
+ /*
+ We do not read furter then local_saved_data_file_length in order
+ not to confict with undergoing concurrent insert.
+ */
if ((end_ptr= find_eoln(share->mapped_file, current_position,
- share->file_stat.st_size)) == 0)
- {
- tina_unlock();
+ local_saved_data_file_length)) == 0)
DBUG_RETURN(HA_ERR_END_OF_FILE);
- }
for (Field **field=table->field ; *field ; field++)
{
@@ -488,7 +489,6 @@
/* Maybe use \N for null? */
memset(buf, 0, table->s->null_bytes); /* We do not implement nulls! */
- tina_unlock();
DBUG_RETURN(0);
}
@@ -506,6 +506,58 @@
return ha_tina_exts;
}
+/*
+ Three functions below are needed to enable concurrent insert functionality
+ for CSV engine. For more details see mysys/thr_lock.c
+*/
+
+void tina_get_status(void* param, int concurrent_insert)
+{
+ ha_tina *tina= (ha_tina*) param;
+ tina->get_status();
+}
+
+void tina_update_status(void* param)
+{
+ ha_tina *tina= (ha_tina*) param;
+ tina->update_status();
+}
+
+/* this should exist and and return 0 for concurrent insert to work */
+my_bool tina_check_status(void* param)
+{
+ return 0;
+}
+
+/* save the state of the table. Called during the lock phase */
+void ha_tina::get_status()
+{
+ if (share->is_log_table)
+ {
+ /*
+ We have to use mutex to follow pthreads memory visibility
+ rules for share->saved_data_file_length
+ */
+ pthread_mutex_lock(&share->mutex);
+ local_saved_data_file_length= share->saved_data_file_length;
+ pthread_mutex_unlock(&share->mutex);
+ return;
+ }
+ local_saved_data_file_length= share->saved_data_file_length;
+}
+
+
+/*
+ Correct the state of the table. Called by unlock routines
+ before the write lock is released.
+*/
+
+void ha_tina::update_status()
+{
+ /* correct local_saved_data_file_length for writers */
+ share->saved_data_file_length= share->file_stat.st_size;
+}
+
/*
Open a database file. Keep in mind that tables are caches, so
@@ -518,9 +570,19 @@
if (!(share= get_share(name, table)))
DBUG_RETURN(1);
- thr_lock_data_init(&share->lock,&lock,NULL);
+
+ /*
+ Init locking. Pass handler object to the locking routines,
+ so that they could save/update local_saved_data_file_length value
+ during locking. This is needed to enable concurrent inserts.
+ */
+ thr_lock_data_init(&share->lock, &lock, (void*) this);
ref_length=sizeof(off_t);
+ share->lock.get_status= tina_get_status;
+ share->lock.update_status= tina_update_status;
+ share->lock.check_status= tina_check_status;
+
DBUG_RETURN(0);
}
@@ -545,7 +607,6 @@
int size;
DBUG_ENTER("ha_tina::write_row");
- tina_lock();
statistic_increment(table->in_use->status_var.ha_write_count, &LOCK_status);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
@@ -554,10 +615,7 @@
size= encode_quote(buf);
if (my_write(share->data_file, buffer.ptr(), size, MYF(MY_WME | MY_NABP)))
- {
- tina_unlock();
DBUG_RETURN(-1);
- }
/*
Ok, this is means that we will be doing potentially bad things
@@ -567,12 +625,19 @@
might be a solution for this.
*/
if (get_mmap(share, 0) > 0)
- {
- tina_unlock();
DBUG_RETURN(-1);
+
+ /* update local copy of the max position to see our own changes */
+ local_saved_data_file_length= share->file_stat.st_size;
+
+ /* update status for the log tables */
+ if (share->is_log_table)
+ {
+ pthread_mutex_lock(&share->mutex);
+ update_status();
+ pthread_mutex_unlock(&share->mutex);
}
- tina_unlock();
DBUG_RETURN(0);
}
@@ -590,7 +655,6 @@
int size;
DBUG_ENTER("ha_tina::update_row");
- tina_lock();
statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
&LOCK_status);
@@ -601,29 +665,22 @@
size= encode_quote(new_data);
if (chain_append())
- {
- tina_unlock();
DBUG_RETURN(-1);
- }
if (my_write(share->data_file, buffer.ptr(), size, MYF(MY_WME | MY_NABP)))
- {
- tina_unlock();
DBUG_RETURN(-1);
- }
/*
- rewrite the file to remove "holes". We have to do it since now
- we use tl_write_allow_write, and don't want to allow others to
- read inconsistent mmap'ed memory area.
+ UPDATE should never happen on the log tables
*/
if (share->is_log_table)
{
- rnd_end();
- chain_ptr= chain;
+ DBUG_ASSERT(0);
}
- tina_unlock();
+ /* update local copy of the max position to see our own changes */
+ local_saved_data_file_length= share->file_stat.st_size;
+
DBUG_RETURN(0);
}
@@ -642,28 +699,19 @@
DBUG_ENTER("ha_tina::delete_row");
statistic_increment(table->in_use->status_var.ha_delete_count,
&LOCK_status);
- tina_lock();
if (chain_append())
- {
- tina_unlock();
DBUG_RETURN(-1);
- }
--records;
/*
- rewrite the file to remove "holes". We have to do it since now
- we use tl_write_allow_write, and don't want to allow others to
- read inconsistent mmap'ed memory area.
+ DELETE should never happen on the log table
*/
if (share->is_log_table)
{
- rnd_end();
- chain_ptr= chain;
+ DBUG_ASSERT(0);
}
- tina_unlock();
-
DBUG_RETURN(0);
}
@@ -872,9 +920,9 @@
DBUG_ENTER("ha_tina::extra");
if (operation == HA_EXTRA_MARK_AS_LOG_TABLE)
{
- pthread_mutex_lock(&tina_mutex);
+ pthread_mutex_lock(&share->mutex);
share->is_log_table= TRUE;
- pthread_mutex_unlock(&tina_mutex);
+ pthread_mutex_unlock(&share->mutex);
}
DBUG_RETURN(0);
}
@@ -980,44 +1028,9 @@
THR_LOCK_DATA **to,
enum thr_lock_type lock_type)
{
- if (!(share->is_log_table))
- {
- if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
- lock.type=lock_type;
- *to++= &lock;
- return to;
- }
-
- /* special logging for the log tables: only physical consistency is obeyed */
-
if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
- {
- /*
- Set write_allow_write lock. Here we don't check for
- thd->in_lock_tables since we don't want to lock log tables
- in any case.
- */
-
- if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
- lock_type <= TL_WRITE))
- lock_type = TL_WRITE_ALLOW_WRITE;
-
- /*
- In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
- MySQL would use the lock TL_READ_NO_INSERT on t2, and that
- would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
- to t2. Convert the lock to a normal read lock to allow
- concurrent inserts to t2.
- */
-
- if (lock_type == TL_READ_NO_INSERT)
- lock_type = TL_READ;
-
lock.type=lock_type;
- }
-
*to++= &lock;
-
return to;
}
--- 1.8/sql/examples/ha_tina.h 2005-11-15 13:52:25 +03:00
+++ 1.9/sql/examples/ha_tina.h 2005-12-03 01:45:02 +03:00
@@ -26,6 +26,12 @@
uint table_name_length, use_count, is_log_table;
MY_STAT file_stat; /* Stat information for the data file */
File data_file; /* Current open data file */
+ /*
+ Here we save the length of the file for readers. This is updated by
+ inserts, updates and deletes. The var is initialized along with the
+ share initialization.
+ */
+ off_t saved_data_file_length;
pthread_mutex_t mutex;
THR_LOCK lock;
} TINA_SHARE;
@@ -41,6 +47,7 @@
TINA_SHARE *share; /* Shared lock info */
off_t current_position; /* Current position in the file during a file scan */
off_t next_position; /* Next position in the file scan */
+ off_t local_saved_data_file_length; /* save position for reads */
byte byte_buffer[IO_SIZE];
String buffer;
/*
@@ -56,7 +63,7 @@
private:
void tina_lock();
- int tina_unlock();
+ void tina_unlock();
public:
ha_tina(TABLE *table_arg);
@@ -122,6 +129,13 @@
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type);
+
+ /*
+ These functions used to get/update status of the handler.
+ Needed to enable concurrent inserts.
+ */
+ void get_status();
+ void update_status();
/* The following methods were added just for TINA */
int encode_quote(byte *buf);
--- 1.16/mysql-test/lib/init_db.sql 2005-11-15 13:52:24 +03:00
+++ 1.17/mysql-test/lib/init_db.sql 2005-12-03 01:45:01 +03:00
@@ -567,25 +567,8 @@
PRIMARY KEY (db,name,type)
) character set utf8 comment='Stored Procedures';
-CREATE TABLE general_log (
- event_time TIMESTAMP NOT NULL,
- user_host MEDIUMTEXT,
- thread_id INTEGER,
- server_id INTEGER,
- command_type VARCHAR(64),
- argument MEDIUMTEXT
-) engine=CSV CHARACTER SET utf8 comment='General log';
-CREATE TABLE slow_log (
- start_time TIMESTAMP NOT NULL,
- user_host MEDIUMTEXT NOT NULL,
- query_time TIME NOT NULL,
- lock_time TIME NOT NULL,
- rows_sent INTEGER NOT NULL,
- rows_examined INTEGER NOT NULL,
- db VARCHAR(512),
- last_insert_id INTEGER,
- insert_id INTEGER,
- server_id INTEGER,
- sql_text MEDIUMTEXT NOT NULL
-) engine=CSV CHARACTER SET utf8 comment='Slow log';
+CREATE PROCEDURE create_log_tables() BEGIN DECLARE is_csv_enabled int DEFAULT 0; SELECT @@have_csv = 'YES' INTO is_csv_enabled; IF (is_csv_enabled) THEN CREATE TABLE general_log (event_time TIMESTAMP NOT NULL, user_host MEDIUMTEXT, thread_id INTEGER, server_id INTEGER, command_type VARCHAR(64), argument MEDIUMTEXT) engine=CSV CHARACTER SET utf8 comment='General log'; CREATE TABLE slow_log (start_time TIMESTAMP NOT NULL, user_host MEDIUMTEXT NOT NULL, query_time TIME NOT NULL, lock_time TIME NOT NULL, rows_sent INTEGER NOT NULL, rows_examined INTEGER NOT NULL, db VARCHAR(512), last_insert_id INTEGER, insert_id INTEGER, server_id INTEGER, sql_text MEDIUMTEXT NOT NULL) engine=CSV CHARACTER SET utf8 comment='Slow log'; END IF; END;
+CALL create_log_tables();
+DROP PROCEDURE create_log_tables;
+
--- 1.28/scripts/mysql_fix_privilege_tables.sql 2005-11-15 13:52:25 +03:00
+++ 1.29/scripts/mysql_fix_privilege_tables.sql 2005-12-03 01:45:02 +03:00
@@ -532,25 +532,35 @@
-- Create missing log tables (5.1)
--
-CREATE TABLE IF NOT EXISTS general_log (
-event_time TIMESTAMP NOT NULL,
-user_host MEDIUMTEXT,
-thread_id INTEGER,
-server_id INTEGER,
-command_type VARCHAR(64),
-argument MEDIUMTEXT
-) engine=CSV CHARACTER SET utf8 comment='General log';
-
-CREATE TABLE IF NOT EXISTS slow_log (
-start_time TIMESTAMP NOT NULL,
-user_host MEDIUMTEXT NOT NULL,
-query_time TIME NOT NULL,
-lock_time TIME NOT NULL,
-rows_sent INTEGER NOT NULL,
-rows_examined INTEGER NOT NULL,
-db VARCHAR(512),
-last_insert_id INTEGER,
-insert_id INTEGER,
-server_id INTEGER,
-sql_text MEDIUMTEXT NOT NULL
-) engine=CSV CHARACTER SET utf8 comment='Slow log';
+delimiter |
+CREATE PROCEDURE create_log_tables()
+BEGIN
+ DECLARE is_csv_enabled int DEFAULT 0;
+ SELECT @@have_csv = 'YES' INTO is_csv_enabled;
+ IF (is_csv_enabled) THEN
+ CREATE TABLE IF NOT EXISTS general_log (
+ event_time TIMESTAMP NOT NULL,
+ user_host MEDIUMTEXT,
+ thread_id INTEGER,
+ server_id INTEGER,
+ command_type VARCHAR(64),
+ argument MEDIUMTEXT
+ ) engine=CSV CHARACTER SET utf8 comment='General log';
+ CREATE TABLE IF NOT EXISTS slow_log (
+ start_time TIMESTAMP NOT NULL,
+ user_host MEDIUMTEXT NOT NULL,
+ query_time TIME NOT NULL,
+ lock_time TIME NOT NULL,
+ rows_sent INTEGER NOT NULL,
+ rows_examined INTEGER NOT NULL,
+ db VARCHAR(512),
+ last_insert_id INTEGER,
+ insert_id INTEGER,
+ server_id INTEGER,
+ sql_text MEDIUMTEXT NOT NULL
+ ) engine=CSV CHARACTER SET utf8 comment='Slow log';
+ END IF;
+END|
+delimiter ;
+CALL create_log_tables();
+DROP PROCEDURE create_log_tables;
--- 1.1/mysql-test/r/log_tables.result 2005-11-15 13:52:26 +03:00
+++ 1.2/mysql-test/r/log_tables.result 2005-12-03 01:45:01 +03:00
@@ -6,30 +6,25 @@
truncate table slow_log;
select * from slow_log;
start_time user_host query_time lock_time rows_sent rows_examined db last_insert_id insert_id server_id sql_text
-lock tables mysql.general_log WRITE;
-select "This query should be logged in general log ok"
- as "basic log table test";
-basic log table test
-This query should be logged in general log ok
-select * from mysql.general_log where argument like '%query should be%';
-event_time user_host thread_id server_id command_type argument
-TIMESTAMP root[root] @ localhost [] 3 1 Query select "This query should be logged in general log ok"
- as "basic log table test"
-TIMESTAMP root[root] @ localhost [] 3 1 Query select * from mysql.general_log where argument like '%query should be%'
-unlock tables;
-use test;
-create table test_csv_locking (val integer) engine = csv;
-insert into test_csv_locking values (1);
-lock tables test_csv_locking read;
-insert into test_csv_locking values (2);
-ERROR HY000: Table 'test_csv_locking' was locked with a READ lock and can't be updated
-select * from test_csv_locking;
-val
-1
-unlock tables;
-drop table test_csv_locking;
-use mysql;
truncate table general_log;
select * from general_log where argument like '%general_log%';
event_time user_host thread_id server_id command_type argument
-TIMESTAMP root[root] @ localhost [] 2 1 Query select * from general_log where argument like '%general_log%'
+TIMESTAMP root[root] @ localhost [] 1 1 Query select * from general_log where argument like '%general_log%'
+flush logs;
+lock tables mysql.general_log WRITE;
+ERROR HY000: You can't write-lock a log table. Only read acces is possible.
+lock tables mysql.slow_log WRITE;
+ERROR HY000: You can't write-lock a log table. Only read acces is possible.
+lock tables mysql.general_log READ;
+ERROR HY000: You can't use usual read lock with log tables. Try READ LOCAL instead.
+lock tables mysql.slow_log READ;
+ERROR HY000: You can't use usual read lock with log tables. Try READ LOCAL instead.
+lock tables mysql.slow_log READ LOCAL, mysql.general_log READ LOCAL;
+unlock tables;
+lock tables mysql.general_log READ LOCAL;
+ flush logs;
+unlock tables;
+select "Mark that we woke up from flush logs in the test"
+ as "test passed";
+test passed
+Mark that we woke up from flush logs in the test
--- 1.1/mysql-test/t/log_tables.test 2005-11-15 13:52:27 +03:00
+++ 1.2/mysql-test/t/log_tables.test 2005-12-03 01:45:01 +03:00
@@ -8,7 +8,8 @@
use mysql;
#
-# Check that log tables work and we can do basic selects
+# Check that log tables work and we can do basic selects. This also
+# tests truncate, which works in a special mode with the log tables
#
truncate table general_log;
@@ -19,68 +20,82 @@
select * from slow_log;
#
-# Check locking of the log tables
+# We want to check that newly written record of the log tables show up for
+# the query: since log tables use concurrent insert machinery and log tables
+# are always locked by artificial THD, this feature requires additional
+# check in ha_tina::write_row. So, this simple test should prove that the
+# log table flag in the table handler is triggered and working.
#
-connect (con1,localhost,root,,);
-connect (con2,localhost,root,,);
+truncate table general_log;
+--replace_column 1 TIMESTAMP
+select * from general_log where argument like '%general_log%';
-connection con1;
+#
+# check that flush of the log table work fine
+#
-# this call should result in TL_WRITE_ALLOW_WRITE lock on the log table
+flush logs;
+
+#
+# check locking of the log tables
+#
+
+--error 1495
lock tables mysql.general_log WRITE;
-connection con2;
+--error 1495
+lock tables mysql.slow_log WRITE;
#
-# Should pass ok despite of the write lock on general_log as log tables
-# ignore locks (otherwise we could lock down the whole server).
+# This attemts to get TL_READ_NO_INSERT lock, which is incompatible with
+# TL_WRITE_CONCURRENT_INSERT. This should fail, as log tables are always
+# opened and locked by the logger.
#
-select "This query should be logged in general log ok"
- as "basic log table test";
+--error 1496
+lock tables mysql.general_log READ;
+--error 1496
+lock tables mysql.slow_log READ;
---replace_column 1 TIMESTAMP
-select * from mysql.general_log where argument like '%query should be%';
+#
+# This call should result in TL_READ lock on the log table. This is ok and
+# should pass.
+#
-connection con1;
+lock tables mysql.slow_log READ LOCAL, mysql.general_log READ LOCAL;
unlock tables;
-# switch to the test database to create test CSV table
-use test;
-
-# Check that usual CSV locking is in place
+#
+# check that FLUSH LOGS waits for all readers of the log table to vanish
+#
-create table test_csv_locking (val integer) engine = csv;
+connect (con1,localhost,root,,);
+connect (con2,localhost,root,,);
-# insert something to the table
-insert into test_csv_locking values (1);
+connection con1;
-# Obtain read lock on the table. locking rules for the lock tables would
-# have downgraded this to TL_WRITE_ALLOW_WRITE, but for ordinary CSV tables
-# this should not happen
+lock tables mysql.general_log READ LOCAL;
-lock tables test_csv_locking read;
+connection con2;
-# should give an error with usual locking rules
---error 1099
-insert into test_csv_locking values (2);
+# this should wait for log tables to unlock
+send flush logs;
-select * from test_csv_locking;
+connection con1;
unlock tables;
-# cleanup
-drop table test_csv_locking;
+# this connection should be alive by the time
+connection con2;
-# test that queries are actually logged into general_log
-use mysql;
+reap;
-truncate table general_log;
---replace_column 1 TIMESTAMP
-select * from general_log where argument like '%general_log%';
+select "Mark that we woke up from flush logs in the test"
+ as "test passed";
disconnect con2;
disconnect con1;
+
--- 1.26/scripts/mysql_create_system_tables.sh 2005-11-15 13:52:25 +03:00
+++ 1.27/scripts/mysql_create_system_tables.sh 2005-12-03 01:45:01 +03:00
@@ -354,45 +354,6 @@
fi
-if test ! -f $mdata/general_log.frm
-then
- if test "$1" = "verbose" ; then
- echo "Preparing general_log table" 1>&2;
- fi
-
- c_gl="$c_gl CREATE TABLE general_log ("
- c_gl="$c_gl event_time TIMESTAMP NOT NULL,"
- c_gl="$c_gl user_host MEDIUMTEXT,"
- c_gl="$c_gl thread_id INTEGER,"
- c_gl="$c_gl server_id INTEGER,"
- c_gl="$c_gl command_type VARCHAR(64),"
- c_gl="$c_gl argument MEDIUMTEXT"
- c_gl="$c_gl ) engine=CSV CHARACTER SET utf8 comment='General log';"
-fi
-
-
-if test ! -f $mdata/slow_log.frm
-then
- if test "$1" = "verbose" ; then
- echo "Preparing slow_log table" 1>&2;
- fi
-
- c_sl="$c_sl CREATE TABLE slow_log ("
- c_sl="$c_sl start_time TIMESTAMP NOT NULL,"
- c_sl="$c_sl user_host MEDIUMTEXT NOT NULL,"
- c_sl="$c_sl query_time TIME NOT NULL,"
- c_sl="$c_sl lock_time TIME NOT NULL,"
- c_sl="$c_sl rows_sent INTEGER NOT NULL,"
- c_sl="$c_sl rows_examined INTEGER NOT NULL,"
- c_sl="$c_sl db VARCHAR(512),"
- c_sl="$c_sl last_insert_id INTEGER,"
- c_sl="$c_sl insert_id INTEGER,"
- c_sl="$c_sl server_id INTEGER,"
- c_sl="$c_sl sql_text MEDIUMTEXT NOT NULL"
- c_sl="$c_sl ) engine=CSV CHARACTER SET utf8 comment='Slow log';"
-fi
-
-
if test ! -f $mdata/time_zone_name.frm
then
if test "$1" = "verbose" ; then
@@ -782,6 +743,28 @@
c_p="$c_p comment='Stored Procedures';"
fi
+
+if test ! -f $mdata/general_log.frm
+then
+ if test "$1" = "verbose" ; then
+ echo "Preparing general_log table" 1>&2;
+ fi
+ c_gl="$c_gl CREATE PROCEDURE create_general_log_table() BEGIN DECLARE is_csv_enabled int DEFAULT 0; SELECT @@have_csv = 'YES' INTO is_csv_enabled; IF (is_csv_enabled) THEN CREATE TABLE general_log (event_time TIMESTAMP NOT NULL, user_host MEDIUMTEXT, thread_id INTEGER, server_id INTEGER, command_type VARCHAR(64), argument MEDIUMTEXT) engine=CSV CHARACTER SET utf8 comment='General log'; END IF; END;"
+ c_gl="$c_gl CALL create_general_log_table();"
+ c_gl="$c_gl DROP PROCEDURE create_general_log_table;"
+fi
+
+
+if test ! -f $mdata/slow_log.frm
+then
+ if test "$1" = "verbose" ; then
+ echo "Preparing slow_log table" 1>&2;
+ fi
+ c_sl="$c_sl CREATE PROCEDURE create_slow_log_table() BEGIN DECLARE is_csv_enabled int DEFAULT 0; SELECT @@have_csv = 'YES' INTO is_csv_enabled; IF (is_csv_enabled) THEN CREATE TABLE slow_log (start_time TIMESTAMP NOT NULL, user_host MEDIUMTEXT NOT NULL, query_time TIME NOT NULL, lock_time TIME NOT NULL, rows_sent INTEGER NOT NULL, rows_examined INTEGER NOT NULL, db VARCHAR(512), last_insert_id INTEGER, insert_id INTEGER, server_id INTEGER, sql_text MEDIUMTEXT NOT NULL) engine=CSV CHARACTER SET utf8 comment='Slow log'; END IF; END;"
+ c_sl="$c_sl CALL create_slow_log_table();"
+ c_sl="$c_sl DROP PROCEDURE create_slow_log_table;"
+fi
+
cat << END_OF_DATA
use mysql;
set table_type=myisam;
@@ -819,11 +802,11 @@
$c_tzls
$i_tzls
-$c_gl
-$c_sl
-
$c_p
$c_pp
+
+$c_gl
+$c_sl
END_OF_DATA
| Thread |
|---|
| • bk commit into 5.1 tree (petr:1.1951) | Petr Chardin | 2 Dec |