How does mysql expire_logs_days work and calculate?
Mysql active and standby replication is done through binlog. When binlog is enabled, the expire_logs_days parameter allows mysql to automatically clean up the binlog from several days ago.
So when did expire_logs_days take effect? The preliminary guess is to judge every time a new binlog is generated. Check the specific implementation, and it is indeed like this:
Source code (5.1.58, log.cc)
Int MYSQL_BIN_LOG::rotate_and_purge (uint flags)
{
...
If (! error & & check_purge & expire_logs_days)
{
Time_t purge_time= my_time (0)-expire_logs_days*24*60*60
If (purge_time > = 0)
Purge_logs_before_date (purge_time)
}
...
}
If expire_logs_days is set, calculate the purge_time every time you binlog rotate (current time-expire_logs_days
This calculation seems to be omitted: expire_logs_days is in days, with a range of 0: 99. 0 means it will not be cleaned up and will not enter the if block naturally:)
Calculated in terms of 99, my_time (0)-992406060 > = 0 is also true), call purge_logs_before_date (purge_time)
Purge_logs_before_date starts the loop with the first binlog file in the log index file: compare the last modification time of the file, if less than purge_time
Just put it in the array to_log. Then call purge_logs to clean up all binlog that meet the criteria.
Int MYSQL_BIN_LOG::purge_logs_before_date (time_t purge_time)
{
...
MY_STAT stat_area
...
Pthread_mutex_lock & LOCK_index)
To_log [0] = 0
If ((error=find_log_pos (& log_info, NullS, 0 / * no mutex*/))
Goto err
While (strcmp (log_file_name, log_info.log_file_name) & &
! is_active (log_info.log_file_name) & &
! log_in_use (log_info.log_file_name))
{
...
If (stat_area.st_mtime < purge_time)
Strmake (to_log
Log_info.log_file_name
Sizeof (log_info.log_file_name)-1)
Else
Break
...
}
Take a look at the implementation of purge_logs:
Int MYSQL_BIN_LOG::purge_logs (const char * to_log
Bool included
Bool need_mutex
Bool need_update_threads
Ulonglong * decrease_log_space)
{
...
While ((strcmp (to_log,log_info.log_file_name) | | (exit_loop=included)) & &
! is_active (log_info.log_file_name) & &
! log_in_use (log_info.log_file_name))
{
If ((error= register_purge_index_entry (log_info.log_file_name)
...
}
...
/ * We know how many files to delete. Update index file. , /
If ((error=update_log_index (& log_info, need_update_threads)
...
/ * Read each entry from purge_index_file and delete the file. , /
If (is_inited_purge_index_file () & &
(error= purge_index_entry (thd, decrease_log_space, FALSE))
...
Purge_logs puts the name of the binlog file that needs to be cleaned into purge_index_file (IO_CACHE), then updates the index file, and finally calls purge_index_entry to delete the binlog file:
Int MYSQL_BIN_LOG::purge_index_entry (THD * thd, ulonglong * decrease_log_space
Bool need_mutex)
{
...
For (;;)
{
...
If (! my_delete (log_info.log_file_name, MYF (0)
{
If (decrease_log_space)
* decrease_log_space-= s.st_size
}
...
}
My_delete calls unlink () to delete the binlog file. At this point, the process of automatically cleaning binlog is completed. In addition, when mysql starts, mysql also executes the purge_logs_before_date (purge_time) process (other operations, if it causes binlog rotate, naturally trigger this process, such as flush logs).
Combing the whole process, it is not difficult to find that in a stressful mysql or production environment, we should not start this parameter (my.cnf does not explicitly set this parameter or set expire_logs_days=0): mysql produces more than a dozen or more binlog files every day, after enabling this parameter, cleaning so many files at a time will inevitably lead to disk io being full, mysql jitter or hang to stay. Therefore, it is recommended that you write your own script, purge one binlog at a time, sleep for a few seconds.
Note:
The expire_logs_days will not be cleared immediately after it is set. The trigger condition is:
Binlog size exceeds max_binlog_size
Execute flush logs manually
When restarting