| List: | Commits | « Previous MessageNext Message » | |
| From: | Daogang Qu | Date: | November 24 2009 8:39am |
| Subject: | Re: bzr commit into mysql-5.1-bugteam branch (Dao-Gang.Qu:3192) Bug#42851 | ||
| View as plain text | |||
Hi Jon, Thanks for your good comments. You missed the two questions. Please check them below. Thanks! Best Regards, Daogang Andrei Elkin wrote: > Dao-Gang, hello. > > Although the patch looks really good - I only have some cosmetics-wise comments - > I have one question for the whole idea. > > The patch introduces the global limit whereas a limit per session might be a better > solution. > The global limitting has a drawback that if for instance two connectons try logging > the limit value can be hit by the first-and-only error message of the 2nd session. > Therefore the error-log observer would miss that 2nd session error message. > > Was that really disscussed before? > > > Please find my comments inlined. > > cheers, > > Andrei > > > >> #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. >> > > good. > > >> @ 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."); >> > > I suggest slightly extend the text to make is certainly readable by > a human being not just a programmer. > > " log-warnings-ratelimit-burst parameter's value (N) exceeded; discarding > the rest of error messages " > > where N stands for the actual value of the parameter. > > > >> +} >> + >> +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}, >> > > Explanations of parameters for mysqld --help I would suggest to discuss with docs > people. Jon would be great to master short english text here. > I dare to suggest my personal version for the 2 params. > > >> + {"log-warnings-ratelimit-interval", OPT_LOG_WARNINGS_RATELIMIT_INTERVAL, >> + "Minimum length of time between which successive warning messages are " >> + "written to the log file.", >> > > "Time interval within which error messages logging is limitted according to > --log-warnings-ratelimit-burst value" > Hi Jon, What's you idea about the description? Best Regards, Daogang > >> + (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.", >> > > "The limit for the number of warnings that can be error-logged within > --log-warnings-ratelimit-interval value; exceeding messages are not logged" > > Hi Jon, What's you idea about the description? Best Regards, Daogang >> + (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: >> /* >> >> >> # 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 >>
