Mercurial > dovecot > core-2.2
comparison src/lib-storage/list/mailbox-list-index-notify.c @ 19118:f600285c3df2
lib-storage: Mailbox list notifications didn't work for INBOX.
Because of some earlier optimizations that changes to INBOX aren't written
to dovecot.list.index.log file.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 08 Sep 2015 00:07:55 +0300 |
parents | fa979ccfa34c |
children | 390d55d627a8 |
comparison
equal
deleted
inserted
replaced
19117:fa979ccfa34c | 19118:f600285c3df2 |
---|---|
3 #include "lib.h" | 3 #include "lib.h" |
4 #include "ioloop.h" | 4 #include "ioloop.h" |
5 #include "str.h" | 5 #include "str.h" |
6 #include "mail-index-private.h" | 6 #include "mail-index-private.h" |
7 #include "mail-transaction-log-private.h" | 7 #include "mail-transaction-log-private.h" |
8 #include "mail-storage.h" | 8 #include "mail-storage-private.h" |
9 #include "mailbox-list-notify.h" | 9 #include "mailbox-list-notify.h" |
10 #include "mailbox-list-notify-tree.h" | 10 #include "mailbox-list-notify-tree.h" |
11 #include "mailbox-list-index.h" | 11 #include "mailbox-list-index.h" |
12 | 12 |
13 #include <sys/stat.h> | 13 #include <sys/stat.h> |
42 enum ilist_ext_type cur_ext; | 42 enum ilist_ext_type cur_ext; |
43 uint32_t cur_ext_id; | 43 uint32_t cur_ext_id; |
44 | 44 |
45 void (*wait_callback)(void *context); | 45 void (*wait_callback)(void *context); |
46 void *wait_context; | 46 void *wait_context; |
47 struct io *io_wait; | 47 struct io *io_wait, *io_wait_inbox; |
48 struct timeout *to_wait, *to_notify; | 48 struct timeout *to_wait, *to_notify; |
49 | 49 |
50 ARRAY_TYPE(seq_range) new_uids, expunged_uids, changed_uids; | 50 ARRAY_TYPE(seq_range) new_uids, expunged_uids, changed_uids; |
51 ARRAY_TYPE(const_string) new_subscriptions, new_unsubscriptions; | 51 ARRAY_TYPE(const_string) new_subscriptions, new_unsubscriptions; |
52 ARRAY(struct mailbox_list_notify_rename) renames; | 52 ARRAY(struct mailbox_list_notify_rename) renames; |
56 unsigned int rename_idx, subscription_idx, unsubscription_idx; | 56 unsigned int rename_idx, subscription_idx, unsubscription_idx; |
57 | 57 |
58 struct mailbox_list_notify_rec notify_rec; | 58 struct mailbox_list_notify_rec notify_rec; |
59 string_t *rec_name; | 59 string_t *rec_name; |
60 | 60 |
61 struct stat last_st; | 61 char *list_log_path, *inbox_log_path; |
62 struct stat list_last_st, inbox_last_st; | |
62 | 63 |
63 unsigned int initialized:1; | 64 unsigned int initialized:1; |
64 unsigned int read_failed:1; | 65 unsigned int read_failed:1; |
66 unsigned int inbox_event_pending:1; | |
65 }; | 67 }; |
66 | 68 |
67 int mailbox_list_index_notify_init(struct mailbox_list *list, | 69 int mailbox_list_index_notify_init(struct mailbox_list *list, |
68 enum mailbox_list_notify_event mask, | 70 enum mailbox_list_notify_event mask, |
69 struct mailbox_list_notify **notify_r) | 71 struct mailbox_list_notify **notify_r) |
70 { | 72 { |
71 struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list); | 73 struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list); |
72 struct mailbox_list_notify_index *inotify; | 74 struct mailbox_list_notify_index *inotify; |
75 const char *index_dir; | |
73 | 76 |
74 if (ilist == NULL) { | 77 if (ilist == NULL) { |
75 /* can't do this without mailbox list indexes */ | 78 /* can't do this without mailbox list indexes */ |
76 return -1; | 79 return -1; |
77 } | 80 } |
95 MAILBOX_LIST_NOTIFY_UNSUBSCRIBE)) != 0) { | 98 MAILBOX_LIST_NOTIFY_UNSUBSCRIBE)) != 0) { |
96 (void)mailbox_list_iter_subscriptions_refresh(list); | 99 (void)mailbox_list_iter_subscriptions_refresh(list); |
97 mailbox_tree_sort(list->subscriptions); | 100 mailbox_tree_sort(list->subscriptions); |
98 inotify->subscriptions = mailbox_tree_dup(list->subscriptions); | 101 inotify->subscriptions = mailbox_tree_dup(list->subscriptions); |
99 } | 102 } |
103 inotify->list_log_path = i_strdup(ilist->index->log->filepath); | |
104 if ((list->ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0 && | |
105 mailbox_list_get_path(list, "INBOX", MAILBOX_LIST_PATH_TYPE_INDEX, | |
106 &index_dir) > 0) { | |
107 /* FIXME: annoyingly hardcoded filename. */ | |
108 inotify->inbox_log_path = i_strdup_printf( | |
109 "%s/"MAIL_INDEX_PREFIX".log", index_dir); | |
110 } | |
100 | 111 |
101 *notify_r = &inotify->notify; | 112 *notify_r = &inotify->notify; |
102 return 1; | 113 return 1; |
103 } | 114 } |
104 | 115 |
110 | 121 |
111 if (inotify->subscriptions != NULL) | 122 if (inotify->subscriptions != NULL) |
112 mailbox_tree_deinit(&inotify->subscriptions); | 123 mailbox_tree_deinit(&inotify->subscriptions); |
113 if (inotify->io_wait != NULL) | 124 if (inotify->io_wait != NULL) |
114 io_remove(&inotify->io_wait); | 125 io_remove(&inotify->io_wait); |
126 if (inotify->io_wait_inbox != NULL) | |
127 io_remove(&inotify->io_wait_inbox); | |
115 if (inotify->to_wait != NULL) | 128 if (inotify->to_wait != NULL) |
116 timeout_remove(&inotify->to_wait); | 129 timeout_remove(&inotify->to_wait); |
117 if (inotify->to_notify != NULL) | 130 if (inotify->to_notify != NULL) |
118 timeout_remove(&inotify->to_notify); | 131 timeout_remove(&inotify->to_notify); |
119 if (inotify->sync_ctx != NULL) | 132 if (inotify->sync_ctx != NULL) |
126 array_free(&inotify->new_uids); | 139 array_free(&inotify->new_uids); |
127 array_free(&inotify->expunged_uids); | 140 array_free(&inotify->expunged_uids); |
128 array_free(&inotify->changed_uids); | 141 array_free(&inotify->changed_uids); |
129 array_free(&inotify->renames); | 142 array_free(&inotify->renames); |
130 str_free(&inotify->rec_name); | 143 str_free(&inotify->rec_name); |
144 i_free(inotify->list_log_path); | |
145 i_free(inotify->inbox_log_path); | |
131 i_free(inotify); | 146 i_free(inotify); |
132 } | 147 } |
133 | 148 |
134 static struct mailbox_list_index_node * | 149 static struct mailbox_list_index_node * |
135 notify_lookup_guid(struct mailbox_list_notify_index *inotify, | 150 notify_lookup_guid(struct mailbox_list_notify_index *inotify, |
164 return index_node; | 179 return index_node; |
165 } | 180 } |
166 | 181 |
167 static void notify_update_stat(struct mailbox_list_notify_index *inotify) | 182 static void notify_update_stat(struct mailbox_list_notify_index *inotify) |
168 { | 183 { |
169 struct mailbox_list_index *ilist = | 184 bool call = FALSE; |
170 INDEX_LIST_CONTEXT(inotify->notify.list); | 185 |
171 const char *path = ilist->index->log->filepath; | 186 if (stat(inotify->list_log_path, &inotify->list_last_st) < 0 && |
172 | 187 errno != ENOENT) { |
173 if (stat(path, &inotify->last_st) < 0 && errno != ENOENT) { | 188 i_error("stat(%s) failed: %m", inotify->list_log_path); |
174 i_error("stat(%s) failed: %m", path); | 189 call = TRUE; |
190 } | |
191 if (inotify->inbox_log_path != NULL) { | |
192 if (stat(inotify->inbox_log_path, &inotify->inbox_last_st) < 0 && | |
193 errno != ENOENT) { | |
194 i_error("stat(%s) failed: %m", inotify->inbox_log_path); | |
195 call = TRUE; | |
196 } | |
197 } | |
198 if (call) | |
175 mailbox_list_index_notify_wait(&inotify->notify, NULL, NULL); | 199 mailbox_list_index_notify_wait(&inotify->notify, NULL, NULL); |
176 } | |
177 } | 200 } |
178 | 201 |
179 static void | 202 static void |
180 mailbox_list_index_notify_sync_init(struct mailbox_list_notify_index *inotify) | 203 mailbox_list_index_notify_sync_init(struct mailbox_list_notify_index *inotify) |
181 { | 204 { |
758 return 1; | 781 return 1; |
759 } else { | 782 } else { |
760 /* caller doesn't care about this change */ | 783 /* caller doesn't care about this change */ |
761 } | 784 } |
762 } | 785 } |
786 if (inotify->inbox_event_pending) { | |
787 inotify->inbox_event_pending = FALSE; | |
788 memset(&inotify->notify_rec, 0, sizeof(inotify->notify_rec)); | |
789 inotify->notify_rec.vname = "INBOX"; | |
790 inotify->notify_rec.storage_name = "INBOX"; | |
791 /* Don't bother trying to figure out which event exactly this | |
792 is. Just send them all and let the caller handle it. */ | |
793 inotify->notify_rec.events = MAILBOX_LIST_NOTIFY_APPENDS | | |
794 MAILBOX_LIST_NOTIFY_EXPUNGES | | |
795 MAILBOX_LIST_NOTIFY_SEEN_CHANGES | | |
796 MAILBOX_LIST_NOTIFY_MODSEQ_CHANGES; | |
797 *rec_r = &inotify->notify_rec; | |
798 return 1; | |
799 } | |
763 | 800 |
764 mailbox_list_index_notify_read_deinit(inotify); | 801 mailbox_list_index_notify_read_deinit(inotify); |
765 return inotify->read_failed ? -1 : 0; | 802 return inotify->read_failed ? -1 : 0; |
766 } | 803 } |
767 | 804 |
771 inotify->wait_callback(inotify->wait_context); | 808 inotify->wait_callback(inotify->wait_context); |
772 } | 809 } |
773 | 810 |
774 static void notify_callback(struct mailbox_list_notify_index *inotify) | 811 static void notify_callback(struct mailbox_list_notify_index *inotify) |
775 { | 812 { |
776 struct stat prev_st = inotify->last_st; | 813 #define INOTIFY_ST_CHANGED(last_st, prev_st) \ |
777 | 814 ((last_st).st_mtime != (prev_st).st_mtime || \ |
815 ST_MTIME_NSEC(last_st) != ST_MTIME_NSEC(prev_st) || \ | |
816 (last_st).st_size != (prev_st).st_size || \ | |
817 (last_st).st_ino != (prev_st).st_ino) | |
818 struct stat list_prev_st = inotify->list_last_st; | |
819 struct stat inbox_prev_st = inotify->inbox_last_st; | |
820 | |
778 notify_update_stat(inotify); | 821 notify_update_stat(inotify); |
779 if (inotify->last_st.st_mtime != prev_st.st_mtime || | 822 if (INOTIFY_ST_CHANGED(inotify->inbox_last_st, inbox_prev_st)) |
780 ST_MTIME_NSEC(inotify->last_st) != ST_MTIME_NSEC(prev_st) || | 823 inotify->inbox_event_pending = TRUE; |
781 inotify->last_st.st_size != prev_st.st_size || | 824 if (inotify->inbox_event_pending || |
782 inotify->last_st.st_ino != prev_st.st_ino) { | 825 INOTIFY_ST_CHANGED(inotify->list_last_st, list_prev_st)) { |
783 /* log has changed. call the callback with a small delay | 826 /* log has changed. call the callback with a small delay |
784 to allow bundling multiple changes together */ | 827 to allow bundling multiple changes together */ |
785 if (inotify->to_notify != NULL) { | 828 if (inotify->to_notify != NULL) { |
786 /* already doing this */ | 829 /* already doing this */ |
787 return; | 830 return; |
796 void (*callback)(void *context), | 839 void (*callback)(void *context), |
797 void *context) | 840 void *context) |
798 { | 841 { |
799 struct mailbox_list_notify_index *inotify = | 842 struct mailbox_list_notify_index *inotify = |
800 (struct mailbox_list_notify_index *)notify; | 843 (struct mailbox_list_notify_index *)notify; |
801 const char *path; | |
802 unsigned int check_interval; | 844 unsigned int check_interval; |
803 | 845 |
804 inotify->wait_callback = callback; | 846 inotify->wait_callback = callback; |
805 inotify->wait_context = context; | 847 inotify->wait_context = context; |
806 | 848 |
807 if (callback == NULL) { | 849 if (callback == NULL) { |
808 if (inotify->io_wait != NULL) | 850 if (inotify->io_wait != NULL) |
809 io_remove(&inotify->io_wait); | 851 io_remove(&inotify->io_wait); |
852 if (inotify->io_wait_inbox != NULL) | |
853 io_remove(&inotify->io_wait_inbox); | |
810 if (inotify->to_wait != NULL) | 854 if (inotify->to_wait != NULL) |
811 timeout_remove(&inotify->to_wait); | 855 timeout_remove(&inotify->to_wait); |
812 if (inotify->to_notify != NULL) | 856 if (inotify->to_notify != NULL) |
813 timeout_remove(&inotify->to_notify); | 857 timeout_remove(&inotify->to_notify); |
814 } else if (inotify->to_wait == NULL) { | 858 } else if (inotify->to_wait == NULL) { |
815 path = inotify->view->index->log->filepath; | 859 (void)io_add_notify(inotify->list_log_path, notify_callback, |
816 (void)io_add_notify(path, notify_callback, inotify, | 860 inotify, &inotify->io_wait); |
817 &inotify->io_wait); | 861 /* we need to check for INBOX explicitly, because INBOX changes |
862 don't get added to mailbox.list.index.log */ | |
863 if (inotify->inbox_log_path != NULL) { | |
864 (void)io_add_notify(inotify->inbox_log_path, | |
865 notify_callback, inotify, | |
866 &inotify->io_wait_inbox); | |
867 } | |
818 /* check with timeout as well, in case io_add_notify() | 868 /* check with timeout as well, in case io_add_notify() |
819 doesn't work (e.g. NFS) */ | 869 doesn't work (e.g. NFS) */ |
820 check_interval = notify->list->mail_set->mailbox_idle_check_interval; | 870 check_interval = notify->list->mail_set->mailbox_idle_check_interval; |
821 i_assert(check_interval > 0); | 871 i_assert(check_interval > 0); |
822 inotify->to_wait = timeout_add(check_interval * 1000, | 872 inotify->to_wait = timeout_add(check_interval * 1000, |