From: Dao-Gang.Qu Date: November 11 2009 6:45am Subject: bzr commit into mysql-5.1-bugteam branch (Dao-Gang.Qu:3192) Bug#42851 List-Archive: http://lists.mysql.com/commits/90047 X-Bug: 42851 Message-Id: <200911110646.nAB6kmw8009953@daogangqu-desktop> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1939036100==" --===============1939036100== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/daogangqu/mysql/bzrwork/bug42851/mysql-5.1-bugteam/ based on revid:davi.arnaut@stripped 3192 Dao-Gang.Qu@stripped 2009-11-11 Bug #42851 Spurious "Statement is not safe to log in statement format." warnings Warnings in error log make error log grow too large. The problem can be resolved by limiting the rate of messages that are written to the log. A volume of messages that is less than or equal to the specified rate is written to the log, whereas the volume of messages that exceeds the rate is discarded. For example, log-warnings-ratelimit-interval = 10 log-warnings-ratelimit-burst = 5 This allows 5 log messages per 10 seconds. The sixth (and posterior) attempts to write a log message within a 10 seconds interval are discarded. @ mysql-test/suite/rpl/r/rpl_ratelimit_warnings.result Test Result for BUG#42851. @ mysql-test/suite/rpl/t/rpl_ratelimit_warnings.test Added the test file to verify if the rate limit works fine. @ sql/log.cc Added the implementation of the 'Rate_limit' class. @ sql/log.h Added the definition of the 'Rate_limit' class. @ sql/mysqld.cc Added OPT_LOG_WARNINGS_RATELIMIT_INTERVAL and OPT_LOG_WARNINGS_RATELIMIT_BURST options for rate limit. added: mysql-test/suite/rpl/r/rpl_ratelimit_warnings.result mysql-test/suite/rpl/t/rpl_ratelimit_warnings-master.opt mysql-test/suite/rpl/t/rpl_ratelimit_warnings-slave.opt mysql-test/suite/rpl/t/rpl_ratelimit_warnings.test modified: sql/log.cc sql/log.h sql/mysqld.cc === added file 'mysql-test/suite/rpl/r/rpl_ratelimit_warnings.result' --- a/mysql-test/suite/rpl/r/rpl_ratelimit_warnings.result 1970-01-01 00:00:00 +0000 +++ b/mysql-test/suite/rpl/r/rpl_ratelimit_warnings.result 2009-11-11 06:45:07 +0000 @@ -0,0 +1,26 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +call mtr.add_suppression("Burst exceeded, rate limiting."); +call mtr.add_suppression("Rate limit lifted, .* warning messages were suppressed."); +CREATE TABLE `t1` ( +`recNo` int(10) unsigned NOT NULL AUTO_INCREMENT, +`string` varchar(64) NOT NULL, +`inUseBy` varchar(38) NOT NULL DEFAULT '', +`tsLastUpdated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE +CURRENT_TIMESTAMP, +PRIMARY KEY (`recNo`), +KEY `tsLastUpdated` (`tsLastUpdated`), +KEY `inUseBy` (`inUseBy`) +); +INSERT INTO t1 SET string='one'; +INSERT INTO t1 SET string='two'; +INSERT INTO t1 SET string='three'; +# above query will produce a warning +SHOW WARNINGS; +Level Code Message +Note 1592 Statement may not be safe to log in statement format. +drop table t1; === added file 'mysql-test/suite/rpl/t/rpl_ratelimit_warnings-master.opt' --- a/mysql-test/suite/rpl/t/rpl_ratelimit_warnings-master.opt 1970-01-01 00:00:00 +0000 +++ b/mysql-test/suite/rpl/t/rpl_ratelimit_warnings-master.opt 2009-11-11 06:45:07 +0000 @@ -0,0 +1 @@ +--log-warnings-ratelimit-interval=10 --log-warnings-ratelimit-burst=5 === added file 'mysql-test/suite/rpl/t/rpl_ratelimit_warnings-slave.opt' --- a/mysql-test/suite/rpl/t/rpl_ratelimit_warnings-slave.opt 1970-01-01 00:00:00 +0000 +++ b/mysql-test/suite/rpl/t/rpl_ratelimit_warnings-slave.opt 2009-11-11 06:45:07 +0000 @@ -0,0 +1 @@ +--log-warnings-ratelimit-interval=10 --log-warnings-ratelimit-burst=5 === added file 'mysql-test/suite/rpl/t/rpl_ratelimit_warnings.test' --- a/mysql-test/suite/rpl/t/rpl_ratelimit_warnings.test 1970-01-01 00:00:00 +0000 +++ b/mysql-test/suite/rpl/t/rpl_ratelimit_warnings.test 2009-11-11 06:45:07 +0000 @@ -0,0 +1,44 @@ +# +# BUG#42851 +# This test verifies if rate limit allows at most 5 log messages +# per 10 seconds. The sixth (and posterior) attempts to write a +# log message within a 10 seconds interval are discarded. +# + +source include/master-slave.inc; +source include/have_binlog_format_statement.inc; + +call mtr.add_suppression("Burst exceeded, rate limiting."); +call mtr.add_suppression("Rate limit lifted, .* warning messages were suppressed."); +# create table +CREATE TABLE `t1` ( + `recNo` int(10) unsigned NOT NULL AUTO_INCREMENT, + `string` varchar(64) NOT NULL, + `inUseBy` varchar(38) NOT NULL DEFAULT '', + `tsLastUpdated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE +CURRENT_TIMESTAMP, + PRIMARY KEY (`recNo`), + KEY `tsLastUpdated` (`tsLastUpdated`), + KEY `inUseBy` (`inUseBy`) +); +# insert test data +INSERT INTO t1 SET string='one'; +INSERT INTO t1 SET string='two'; +INSERT INTO t1 SET string='three'; +# grab one record +let $count=5000; +--disable_warnings +--disable_query_log +while ($count) +{ + UPDATE t1 SET inUseBy='me' WHERE inUseBy='' limit 1; + dec $count; +} +--enable_query_log +--enable_warnings +--echo # above query will produce a warning +SHOW WARNINGS; + +drop table t1; +sync_slave_with_master; + === modified file 'sql/log.cc' --- a/sql/log.cc 2009-10-23 00:03:41 +0000 +++ b/sql/log.cc 2009-11-11 06:45:07 +0000 @@ -51,6 +51,8 @@ LOGGER logger; MYSQL_BIN_LOG mysql_bin_log; ulong sync_binlog_counter= 0; +ulong log_warnings_ratelimit_interval; +ulong log_warnings_ratelimit_burst; static bool test_if_number(const char *str, long *res, bool allow_wildcards); @@ -737,11 +739,80 @@ bool Log_to_csv_event_handler:: return FALSE; } + +Rate_limit::Rate_limit() + : m_count(0), m_suppressed(0), m_begin(0), + interval(0), burst(0) +{} + +Rate_limit::~Rate_limit() +{} + +void Rate_limit::rate_limit_exceeded() +{} + +void Rate_limit::rate_limit_reset(unsigned int suppressed) +{} + +bool Rate_limit::rate_limit_impl() +{ + unsigned int suppressed= 0; + bool exceeds, notify_exceeded= false; + + if (!m_begin) + m_begin= my_time(0); + + if ((m_begin + interval) < my_time(0)) + { + /* Interval has elapsed, reset counters. */ + suppressed= m_suppressed; + m_begin= 0; + m_count= m_suppressed= 0; + } + + /* Whether burst limit has been surpassed. */ + exceeds= (burst && burst <= m_count); + + /* + Issue a notification callback only if the the + limit has been surpassed for the first time. + */ + if (exceeds) + notify_exceeded= !(m_suppressed++); + else + m_count++; + + if (suppressed) + rate_limit_reset(suppressed); + + if (notify_exceeded) + rate_limit_exceeded(); + + return !exceeds; +} + + bool Log_to_file_event_handler:: log_error(enum loglevel level, const char *format, va_list args) { - return vprint_msg_to_log(level, format, args); + bool rv= false; + + if ((level != WARNING_LEVEL) || rate_limit()) + rv= vprint_msg_to_log(level, format, args); + + return rv; +} + +void Log_to_file_event_handler::rate_limit_exceeded() +{ + sql_print_error("Burst exceeded, rate limiting."); +} + +void Log_to_file_event_handler::rate_limit_reset(unsigned int suppressed) +{ + sql_print_error("Rate limit lifted, %u warning messages were suppressed.", + suppressed); } void Log_to_file_event_handler::init_pthread_objects() === modified file 'sql/log.h' --- a/sql/log.h 2009-06-18 13:52:46 +0000 +++ b/sql/log.h 2009-11-11 06:45:07 +0000 @@ -16,6 +16,9 @@ #ifndef LOG_H #define LOG_H +extern ulong log_warnings_ratelimit_interval; +extern ulong log_warnings_ratelimit_burst; + class Relay_log_info; class Format_description_log_event; @@ -459,15 +462,87 @@ public: }; +/** + Rate limiter. +*/ + +class Rate_limit +{ + public: + Rate_limit(); + virtual ~Rate_limit(); + + private: + unsigned int interval; + unsigned int burst; + unsigned int m_count; + unsigned int m_suppressed; + time_t m_begin; + + private: + bool rate_limit_impl(); + + protected: + /** Rate limit exceeded notification. */ + virtual void rate_limit_exceeded(); + + /** + Rate limit lifted notification. + + @param suppressed Number of suppressed attempts. + */ + virtual void rate_limit_reset(unsigned int suppressed); + + public: + /** + Enforce a rate limit based on the number of successive + calls per time interval, e.g. Rate_limit::burst calls + per Rate_limit::interval. + + @remark Designed to mitigate DoS attacks. + + @return Whether a attempt falls within the limit. + @retval true Within rate limit. + @retval false Rate limit exceeded. + */ + bool rate_limit() + { + return interval ? rate_limit_impl() : true; + } + + /** + Set interval of rate limit. + @param The interval of rate limit. + */ + void set_interval(unsigned int ratelimit_interval) + { + interval= ratelimit_interval; + } + + /** + Set burst of rate limit. + @param The burst of rate limit. + */ + void set_burst(unsigned int ratelimit_burst) + { + burst= ratelimit_burst; + } +}; + + /* type of the log table */ #define QUERY_LOG_SLOW 1 #define QUERY_LOG_GENERAL 2 -class Log_to_file_event_handler: public Log_event_handler +class Log_to_file_event_handler: public Log_event_handler, + public Rate_limit { MYSQL_QUERY_LOG mysql_log; MYSQL_QUERY_LOG mysql_slow_log; bool is_initialized; +protected: + void rate_limit_exceeded(); + void rate_limit_reset(unsigned int suppressed); public: Log_to_file_event_handler(): is_initialized(FALSE) {} @@ -565,6 +640,10 @@ public: return file_log_handler->get_mysql_log(); return NULL; } + Log_to_file_event_handler *get_log_file_event_handler() + { + return file_log_handler; + } }; enum enum_binlog_format { === modified file 'sql/mysqld.cc' --- a/sql/mysqld.cc 2009-11-03 00:52:57 +0000 +++ b/sql/mysqld.cc 2009-11-11 06:45:07 +0000 @@ -5700,7 +5700,9 @@ enum options_mysqld OPT_SLAVE_EXEC_MODE, OPT_GENERAL_LOG_FILE, OPT_SLOW_QUERY_LOG_FILE, - OPT_IGNORE_BUILTIN_INNODB + OPT_IGNORE_BUILTIN_INNODB, + OPT_LOG_WARNINGS_RATELIMIT_INTERVAL, + OPT_LOG_WARNINGS_RATELIMIT_BURST }; @@ -6046,6 +6048,18 @@ log and this option justs turns on --log (uchar**) &global_system_variables.log_warnings, (uchar**) &max_system_variables.log_warnings, 0, GET_ULONG, OPT_ARG, 1, 0, 0, 0, 0, 0}, + {"log-warnings-ratelimit-interval", OPT_LOG_WARNINGS_RATELIMIT_INTERVAL, + "Minimum length of time between which successive warning messages are " + "written to the log file.", + (uchar**) &log_warnings_ratelimit_interval, + (uchar**) &log_warnings_ratelimit_interval, + 0, GET_ULONG, REQUIRED_ARG, 5, 0, 0, 0, 0, 0}, + {"log-warnings-ratelimit-burst", OPT_LOG_WARNINGS_RATELIMIT_BURST, + "Number of warning messages within a interval that shall trigger " + "rate limiting.", + (uchar**) &log_warnings_ratelimit_burst, + (uchar**) &log_warnings_ratelimit_burst, + 0, GET_ULONG, REQUIRED_ARG, 25, 0, 0, 0, 0, 0}, {"low-priority-updates", OPT_LOW_PRIORITY_UPDATES, "INSERT/DELETE/UPDATE has lower priority than selects.", (uchar**) &global_system_variables.low_priority_updates, @@ -7860,6 +7874,7 @@ mysqld_get_one_option(int optid, char *argument) { int error; + Log_to_file_event_handler * log_file_event_handler; switch(optid) { case '#': @@ -8396,6 +8411,18 @@ mysqld_get_one_option(int optid, lower_case_table_names= argument ? atoi(argument) : 1; lower_case_table_names_used= 1; break; + case OPT_LOG_WARNINGS_RATELIMIT_INTERVAL: + log_warnings_ratelimit_interval= atoi(argument); + log_file_event_handler = logger.get_log_file_event_handler(); + if (log_file_event_handler) + log_file_event_handler->set_interval(log_warnings_ratelimit_interval); + break; + case OPT_LOG_WARNINGS_RATELIMIT_BURST: + log_warnings_ratelimit_burst= atoi(argument); + log_file_event_handler = logger.get_log_file_event_handler(); + if (log_file_event_handler) + log_file_event_handler->set_burst(log_warnings_ratelimit_burst); + break; #if defined(ENABLED_DEBUG_SYNC) case OPT_DEBUG_SYNC_TIMEOUT: /* --===============1939036100== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/dao-gang.qu@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: dao-gang.qu@stripped # target_branch: file:///home/daogangqu/mysql/bzrwork/bug42851/mysql-\ # 5.1-bugteam/ # testament_sha1: 84e778735be5586e779c2f921f4dba84a204c22a # timestamp: 2009-11-11 14:45:47 +0800 # base_revision_id: davi.arnaut@stripped\ # 4zfm2j149rypot06 # # Begin bundle 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 7kkQHxlKYl8CJhhX1G6I/+LuSKcKEgWSIeOg --===============1939036100==--