# HG changeset patch # User Timo Sirainen # Date 1487189592 -7200 # Node ID 3538545077cb4e28dd1ce0ab69540592061fd60d # Parent d1860907acf9dc6a5272a5337e62b59e666d4cf3 lib-index: Fix updating mail_index_header.day_first_uid If user received a mail every day, the day_first_uid wasn't being updated. This caused wrong caching decisions to be made in dovecot.index.cache: - Accessing >1 week old emails should have changed caching decision from "tmp" to "yes". This might not have happened, although as long as day_first_uid[7] pointed to an existing mail and email client accessed all the mails, this wouldn't have changed anything. - Cache compression is supposed to drop >1 week old mails when caching decision is "tmp". Not enough mails were being dropped because day_first_uid[7] pointed to a much older than 1 week old mails. Also added a unit test to make sure this works. Broken by d9ee2f9fb3ef7b9391bfeeff1b374aead51667aa diff -r d1860907acf9 -r 3538545077cb src/lib-index/mail-index-transaction-update.c --- a/src/lib-index/mail-index-transaction-update.c Wed Feb 15 22:12:15 2017 +0200 +++ b/src/lib-index/mail-index-transaction-update.c Wed Feb 15 22:13:12 2017 +0200 @@ -148,7 +148,7 @@ /* @UNSAFE: move days forward and fill the missing days with old day_first_uid[0]. */ - if (days > 1 && days < max_days) + if (days > 0 && days < max_days) memmove(hdr.day_first_uid + days, hdr.day_first_uid, (max_days - days) * sizeof(hdr.day_first_uid[0])); for (i = 1; i < days; i++) diff -r d1860907acf9 -r 3538545077cb src/lib-index/test-mail-index-transaction-update.c --- a/src/lib-index/test-mail-index-transaction-update.c Wed Feb 15 22:12:15 2017 +0200 +++ b/src/lib-index/test-mail-index-transaction-update.c Wed Feb 15 22:13:12 2017 +0200 @@ -6,6 +6,7 @@ #include "mail-index-private.h" #include "mail-index-transaction-private.h" +#include static struct mail_index_header hdr; static struct mail_index_record rec; @@ -586,6 +587,74 @@ mail_index_transaction_cleanup(t); } +static void test_mail_index_update_day_first_uid(void) +{ + struct { + uint32_t now; + uint32_t old_day_stamp; + uint32_t new_day_stamp; + uint32_t new_day_first_uid[8]; + } tests[] = { + /* 1487116800 = 2017-02-15 00:00:00 UTC */ + { 1487116800, 1487116800, 1487116800, { 8, 7, 6, 5, 4, 3, 2, 1 } }, + /* still same day */ + { 1487116800+3600*24-1, 1487116800, 1487116800, { 8, 7, 6, 5, 4, 3, 2, 1 } }, + /* one day earlier */ + { 1487116800-1, 1487116800, 1487116800, { 8, 7, 6, 5, 4, 3, 2, 1 } }, + /* next day */ + { 1487116800+3600*24, 1487116800, 1487116800+3600*24, { 9, 8, 7, 6, 5, 4, 3, 2 } }, + { 1487116800+3600*24*2-1, 1487116800, 1487116800+3600*24, { 9, 8, 7, 6, 5, 4, 3, 2 } }, + /* 2 days */ + { 1487116800+3600*24*2, 1487116800, 1487116800+3600*24*2, { 9, 8, 8, 7, 6, 5, 4, 3 } }, + /* 3 days */ + { 1487116800+3600*24*3, 1487116800, 1487116800+3600*24*3, { 9, 8, 8, 8, 7, 6, 5, 4 } }, + /* 4 days */ + { 1487116800+3600*24*4, 1487116800, 1487116800+3600*24*4, { 9, 8, 8, 8, 8, 7, 6, 5 } }, + /* 5 days */ + { 1487116800+3600*24*5, 1487116800, 1487116800+3600*24*5, { 9, 8, 8, 8, 8, 8, 7, 6 } }, + /* 6 days */ + { 1487116800+3600*24*6, 1487116800, 1487116800+3600*24*6, { 9, 8, 8, 8, 8, 8, 8, 7 } }, + /* 7 days */ + { 1487116800+3600*24*7, 1487116800, 1487116800+3600*24*7, { 9, 8, 8, 8, 8, 8, 8, 8 } }, + /* 8 days */ + { 1487116800+3600*24*8, 1487116800, 1487116800+3600*24*8, { 9, 8, 8, 8, 8, 8, 8, 8 } }, + /* 366 days */ + { 1487116800+3600*24*366, 1487116800, 1487116800+3600*24*366, { 9, 8, 8, 8, 8, 8, 8, 8 } }, + }; + struct mail_index_transaction *t; + struct mail_index_record *rec; + unsigned int i, j; + + test_begin("mail index update day first uid"); + + hdr.messages_count = 10; + t = mail_index_transaction_new(); + t->view = t_new(struct mail_index_view, 1); + t->view->map = t_new(struct mail_index_map, 1); + + t_array_init(&t->appends, 1); + rec = array_append_space(&t->appends); + rec->uid = 9; + + for (i = 0; i < N_ELEMENTS(tests); i++) { + i_zero(&hdr); + for (j = 0; j < N_ELEMENTS(hdr.day_first_uid); j++) + hdr.day_first_uid[j] = 8-j; + hdr.day_stamp = tests[i].old_day_stamp + timezone; + memcpy(t->post_hdr_change, &hdr, sizeof(hdr)); + mail_index_update_day_headers(t, tests[i].now + timezone); + + struct mail_index_header new_hdr; + memcpy(&new_hdr, t->post_hdr_change, sizeof(new_hdr)); + test_assert_idx(new_hdr.day_stamp == tests[i].new_day_stamp + timezone, i); + test_assert_idx(memcmp(new_hdr.day_first_uid, + tests[i].new_day_first_uid, + sizeof(uint32_t) * 8) == 0, i); + } + + test_end(); +} + int main(void) { static void (*test_functions[])(void) = { @@ -599,7 +668,9 @@ test_mail_index_transaction_get_flag_update_pos, test_mail_index_modseq_update, test_mail_index_expunge, + test_mail_index_update_day_first_uid, NULL }; + tzset(); return test_run(test_functions); }