# HG changeset patch # User Timo Sirainen # Date 1499776516 -10800 # Node ID ba1a35c5ead70285693b0bf96b0050fb365e012b # Parent e01bc3015b2f2e188a3141d5f33095d3b2f90c26 lib-index: Track .log.2 rotation time in index header This avoids unnecessarily stat()ing the file. Also it's a bit better since it's tracking the actual rotation time, not the mtime of what the .log file happened to have at the time of rotation. The initial rotation timestamp is written only to the dovecot.index header without going through dovecot.index.log. This works, because the dovecot.index is written practically always after a log rotation. For the rare cases when it doesn't happen, the dovecot.index.log.2 just gets deleted later after the next log rotation. diff -r e01bc3015b2f -r ba1a35c5ead7 src/doveadm/doveadm-dump-index.c --- a/src/doveadm/doveadm-dump-index.c Tue Jul 11 15:33:56 2017 +0300 +++ b/src/doveadm/doveadm-dump-index.c Tue Jul 11 15:35:16 2017 +0300 @@ -151,6 +151,7 @@ printf("log file head offset ..... = %u\n", hdr->log_file_head_offset); } if (hdr->minor_version >= 3) { + printf("log2 rotate time ......... = %u (%s)\n", hdr->log2_rotate_time, unixdate2str(hdr->log2_rotate_time)); printf("last temp file scan ...... = %u (%s)\n", hdr->last_temp_file_scan, unixdate2str(hdr->last_temp_file_scan)); } printf("day stamp ................ = %u (%s)\n", hdr->day_stamp, unixdate2str(hdr->day_stamp)); diff -r e01bc3015b2f -r ba1a35c5ead7 src/lib-index/mail-index-map-hdr.c --- a/src/lib-index/mail-index-map-hdr.c Tue Jul 11 15:33:56 2017 +0300 +++ b/src/lib-index/mail-index-map-hdr.c Tue Jul 11 15:35:16 2017 +0300 @@ -292,7 +292,8 @@ case 2: /* pre-v2.2 (although should have been done in v2.1 already): make sure the old unused fields are cleared */ - map->hdr.unused_old_sync_size = 0; + map->hdr.unused_old_sync_size_part1 = 0; + map->hdr.log2_rotate_time = 0; map->hdr.last_temp_file_scan = 0; } if (hdr->first_recent_uid == 0) { diff -r e01bc3015b2f -r ba1a35c5ead7 src/lib-index/mail-index-private.h --- a/src/lib-index/mail-index-private.h Tue Jul 11 15:33:56 2017 +0300 +++ b/src/lib-index/mail-index-private.h Tue Jul 11 15:35:16 2017 +0300 @@ -174,6 +174,7 @@ uoff_t log_rotate_min_size, log_rotate_max_size; unsigned int log_rotate_min_created_ago_secs; unsigned int log_rotate_log2_stale_secs; + uint32_t pending_log2_rotate_time; pool_t extension_pool; ARRAY(struct mail_index_registered_ext) extensions; diff -r e01bc3015b2f -r ba1a35c5ead7 src/lib-index/mail-index-sync.c --- a/src/lib-index/mail-index-sync.c Tue Jul 11 15:33:56 2017 +0300 +++ b/src/lib-index/mail-index-sync.c Tue Jul 11 15:35:16 2017 +0300 @@ -870,6 +870,14 @@ &next_uid, sizeof(next_uid), FALSE); } } + if (index->pending_log2_rotate_time != 0) { + uint32_t log2_rotate_time = index->pending_log2_rotate_time; + + mail_index_update_header(ctx->ext_trans, + offsetof(struct mail_index_header, log2_rotate_time), + &log2_rotate_time, sizeof(log2_rotate_time), TRUE); + index->pending_log2_rotate_time = 0; + } ret2 = mail_index_transaction_commit(&ctx->ext_trans); if (cache_lock != NULL) diff -r e01bc3015b2f -r ba1a35c5ead7 src/lib-index/mail-index-write.c --- a/src/lib-index/mail-index-write.c Tue Jul 11 15:33:56 2017 +0300 +++ b/src/lib-index/mail-index-write.c Tue Jul 11 15:35:16 2017 +0300 @@ -140,6 +140,10 @@ hdr->log_file_seq = file->hdr.file_seq; hdr->log_file_head_offset = hdr->log_file_tail_offset = file->hdr.hdr_size; + /* Assume .log.2 was created successfully. If it + wasn't, it just causes an extra stat() and gets + fixed later on. */ + hdr->log2_rotate_time = ioloop_time; } } diff -r e01bc3015b2f -r ba1a35c5ead7 src/lib-index/mail-index.h --- a/src/lib-index/mail-index.h Tue Jul 11 15:33:56 2017 +0300 +++ b/src/lib-index/mail-index.h Tue Jul 11 15:35:16 2017 +0300 @@ -105,7 +105,11 @@ uint32_t log_file_tail_offset; uint32_t log_file_head_offset; - uint64_t unused_old_sync_size; + uint32_t unused_old_sync_size_part1; + /* Timestamp of when .log was rotated into .log.2. This can be used to + optimize checking when it's time to unlink it without stat()ing it. + 0 = unknown, -1 = .log.2 doesn't exists. */ + uint32_t log2_rotate_time; uint32_t last_temp_file_scan; /* daily first UIDs that have been added to index. */ diff -r e01bc3015b2f -r ba1a35c5ead7 src/lib-index/mail-transaction-log.c --- a/src/lib-index/mail-transaction-log.c Tue Jul 11 15:33:56 2017 +0300 +++ b/src/lib-index/mail-transaction-log.c Tue Jul 11 15:35:16 2017 +0300 @@ -39,21 +39,37 @@ static void mail_transaction_log_2_unlink_old(struct mail_transaction_log *log) { struct stat st; + uint32_t log2_rotate_time = log->index->map->hdr.log2_rotate_time; if (MAIL_INDEX_IS_IN_MEMORY(log->index)) return; - if (nfs_safe_stat(log->filepath2, &st) < 0) { - if (errno != ENOENT) { + if (log2_rotate_time == 0) { + if (nfs_safe_stat(log->filepath2, &st) == 0) + log2_rotate_time = st.st_mtime; + else if (errno == ENOENT) + log2_rotate_time = (uint32_t)-1; + else { mail_index_set_error(log->index, "stat(%s) failed: %m", log->filepath2); + return; } - return; } - if (ioloop_time - st.st_mtime >= (time_t)log->index->log_rotate_log2_stale_secs && - !log->index->readonly) + if (log2_rotate_time != (uint32_t)-1 && + ioloop_time - log2_rotate_time >= (time_t)log->index->log_rotate_log2_stale_secs && + !log->index->readonly) { i_unlink_if_exists(log->filepath2); + log2_rotate_time = (uint32_t)-1; + } + + if (log2_rotate_time != log->index->map->hdr.log2_rotate_time) { + /* Write this as part of the next sync's transaction. We're + here because we're already opening a sync lock, so it'll + always happen. It's also required especially with mdbox map + index, which doesn't like changes done outside syncing. */ + log->index->pending_log2_rotate_time = log2_rotate_time; + } } int mail_transaction_log_open(struct mail_transaction_log *log)