From: Timo Sirainen Date: Tue, 11 Jul 2017 12:35:16 +0000 (+0300) Subject: lib-index: Track .log.2 rotation time in index header X-Git-Tag: 2.3.0.rc1~1269 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4394b73cacaf2c31a9b601f66b6e26a1c8f114b4;p=thirdparty%2Fdovecot%2Fcore.git 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 --git a/src/doveadm/doveadm-dump-index.c b/src/doveadm/doveadm-dump-index.c index f14e88326f..8d52140d0c 100644 --- a/src/doveadm/doveadm-dump-index.c +++ b/src/doveadm/doveadm-dump-index.c @@ -151,6 +151,7 @@ static void dump_hdr(struct mail_index *index) 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 --git a/src/lib-index/mail-index-map-hdr.c b/src/lib-index/mail-index-map-hdr.c index 1caa3f1a2e..8ca40634e8 100644 --- a/src/lib-index/mail-index-map-hdr.c +++ b/src/lib-index/mail-index-map-hdr.c @@ -292,7 +292,8 @@ int mail_index_map_check_header(struct mail_index_map *map, 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 --git a/src/lib-index/mail-index-private.h b/src/lib-index/mail-index-private.h index cbb114e4a5..58dd42c624 100644 --- a/src/lib-index/mail-index-private.h +++ b/src/lib-index/mail-index-private.h @@ -174,6 +174,7 @@ struct mail_index { 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 --git a/src/lib-index/mail-index-sync.c b/src/lib-index/mail-index-sync.c index 692ae58666..28a7ba0d49 100644 --- a/src/lib-index/mail-index-sync.c +++ b/src/lib-index/mail-index-sync.c @@ -870,6 +870,14 @@ int mail_index_sync_commit(struct mail_index_sync_ctx **_ctx) &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 --git a/src/lib-index/mail-index-write.c b/src/lib-index/mail-index-write.c index 809e81dce3..69ff718567 100644 --- a/src/lib-index/mail-index-write.c +++ b/src/lib-index/mail-index-write.c @@ -140,6 +140,10 @@ void mail_index_write(struct mail_index *index, bool want_rotate) 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 --git a/src/lib-index/mail-index.h b/src/lib-index/mail-index.h index b6434f7a68..64810144b4 100644 --- a/src/lib-index/mail-index.h +++ b/src/lib-index/mail-index.h @@ -105,7 +105,11 @@ struct mail_index_header { 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 --git a/src/lib-index/mail-transaction-log.c b/src/lib-index/mail-transaction-log.c index f86ca20365..08aaf448df 100644 --- a/src/lib-index/mail-transaction-log.c +++ b/src/lib-index/mail-transaction-log.c @@ -39,21 +39,37 @@ mail_transaction_log_alloc(struct mail_index *index) 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)