/src/dovecot/src/lib-storage/index/index-transaction.c
Line | Count | Source |
1 | | /* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "array.h" |
5 | | #include "dict.h" |
6 | | #include "index-storage.h" |
7 | | #include "index-sync-private.h" |
8 | | #include "index-pop3-uidl.h" |
9 | | #include "index-mail.h" |
10 | | |
11 | | static void index_transaction_free(struct mailbox_transaction_context *t) |
12 | 0 | { |
13 | 0 | if (t->view_pvt != NULL) |
14 | 0 | mail_index_view_close(&t->view_pvt); |
15 | 0 | mail_cache_view_close(&t->cache_view); |
16 | 0 | mail_index_view_close(&t->view); |
17 | 0 | if (array_is_created(&t->pvt_saves)) |
18 | 0 | array_free(&t->pvt_saves); |
19 | 0 | array_free(&t->module_contexts); |
20 | 0 | i_free(t->reason); |
21 | 0 | i_free(t); |
22 | 0 | } |
23 | | |
24 | | static int |
25 | | index_transaction_index_commit(struct mail_index_transaction *index_trans, |
26 | | struct mail_index_transaction_commit_result *result_r) |
27 | 0 | { |
28 | 0 | struct mailbox_transaction_context *t = |
29 | 0 | MAIL_STORAGE_CONTEXT_REQUIRE(index_trans); |
30 | 0 | struct index_mailbox_sync_pvt_context *pvt_sync_ctx = NULL; |
31 | 0 | const char *error; |
32 | 0 | int ret = 0; |
33 | |
|
34 | 0 | index_pop3_uidl_update_exists_finish(t); |
35 | |
|
36 | 0 | if (t->attr_pvt_trans != NULL) { |
37 | 0 | if (dict_transaction_commit(&t->attr_pvt_trans, &error) < 0) { |
38 | 0 | mailbox_set_critical(t->box, |
39 | 0 | "Dict private transaction commit failed: %s", error); |
40 | 0 | ret = -1; |
41 | 0 | } |
42 | 0 | } |
43 | 0 | if (t->attr_shared_trans != NULL) { |
44 | 0 | if (dict_transaction_commit(&t->attr_shared_trans, &error) < 0) { |
45 | 0 | mailbox_set_critical(t->box, |
46 | 0 | "Dict shared transaction commit failed: %s", error); |
47 | 0 | ret = -1; |
48 | 0 | } |
49 | 0 | } |
50 | |
|
51 | 0 | if (t->save_ctx != NULL) { |
52 | 0 | mailbox_save_context_deinit(t->save_ctx); |
53 | 0 | if (ret < 0) { |
54 | 0 | t->box->v.transaction_save_rollback(t->save_ctx); |
55 | 0 | t->save_ctx = NULL; |
56 | 0 | } else if (t->box->v.transaction_save_commit_pre(t->save_ctx) < 0) { |
57 | 0 | t->save_ctx = NULL; |
58 | 0 | ret = -1; |
59 | 0 | } |
60 | 0 | } |
61 | |
|
62 | 0 | if (array_is_created(&t->pvt_saves)) { |
63 | 0 | if (index_mailbox_sync_pvt_init(t->box, TRUE, 0, &pvt_sync_ctx) < 0) |
64 | 0 | ret = -1; |
65 | 0 | } |
66 | |
|
67 | 0 | i_assert(t->mail_ref_count == 0); |
68 | 0 | if (ret < 0) |
69 | 0 | t->super.rollback(index_trans); |
70 | 0 | else { |
71 | 0 | if (t->super.commit(index_trans, result_r) < 0) { |
72 | 0 | mailbox_set_index_error(t->box); |
73 | 0 | ret = -1; |
74 | 0 | } else { |
75 | 0 | t->changes->changes_mask = result_r->changes_mask; |
76 | 0 | } |
77 | 0 | } |
78 | |
|
79 | 0 | if (t->save_ctx == NULL) { |
80 | 0 | } else if (ret >= 0) { |
81 | 0 | i_assert(t->save_ctx->dest_mail == NULL); |
82 | 0 | t->box->v.transaction_save_commit_post(t->save_ctx, result_r); |
83 | 0 | } else { |
84 | 0 | t->box->v.transaction_save_rollback(t->save_ctx); |
85 | 0 | } |
86 | | |
87 | 0 | if (pvt_sync_ctx != NULL) { |
88 | 0 | if (index_mailbox_sync_pvt_newmails(pvt_sync_ctx, t) < 0) { |
89 | | /* failed to add private flags. a bit too late to |
90 | | return failure though, so just ignore silently */ |
91 | 0 | } |
92 | 0 | index_mailbox_sync_pvt_deinit(&pvt_sync_ctx); |
93 | 0 | } |
94 | |
|
95 | 0 | if (ret < 0) |
96 | 0 | mail_index_set_error_nolog(t->box->index, mailbox_get_last_error(t->box, NULL)); |
97 | 0 | index_transaction_free(t); |
98 | 0 | return ret; |
99 | 0 | } |
100 | | |
101 | | static void |
102 | | index_transaction_index_rollback(struct mail_index_transaction *index_trans) |
103 | 0 | { |
104 | 0 | struct mailbox_transaction_context *t = |
105 | 0 | MAIL_STORAGE_CONTEXT_REQUIRE(index_trans); |
106 | |
|
107 | 0 | dict_transaction_rollback(&t->attr_pvt_trans); |
108 | 0 | dict_transaction_rollback(&t->attr_shared_trans); |
109 | |
|
110 | 0 | if (t->save_ctx != NULL) { |
111 | 0 | mailbox_save_context_deinit(t->save_ctx); |
112 | 0 | t->box->v.transaction_save_rollback(t->save_ctx); |
113 | 0 | } |
114 | |
|
115 | 0 | i_assert(t->mail_ref_count == 0); |
116 | 0 | t->super.rollback(index_trans); |
117 | 0 | index_transaction_free(t); |
118 | 0 | } |
119 | | |
120 | | static enum mail_index_transaction_flags |
121 | | index_transaction_flags_get(enum mailbox_transaction_flags flags) |
122 | 0 | { |
123 | 0 | enum mail_index_transaction_flags itrans_flags; |
124 | |
|
125 | 0 | itrans_flags = MAIL_INDEX_TRANSACTION_FLAG_AVOID_FLAG_UPDATES; |
126 | 0 | if ((flags & MAILBOX_TRANSACTION_FLAG_HIDE) != 0) |
127 | 0 | itrans_flags |= MAIL_INDEX_TRANSACTION_FLAG_HIDE; |
128 | 0 | if ((flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0) |
129 | 0 | itrans_flags |= MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL; |
130 | 0 | if ((flags & MAILBOX_TRANSACTION_FLAG_SYNC) != 0) |
131 | 0 | itrans_flags |= MAIL_INDEX_TRANSACTION_FLAG_SYNC; |
132 | 0 | return itrans_flags; |
133 | 0 | } |
134 | | |
135 | | void index_transaction_init_pvt(struct mailbox_transaction_context *t) |
136 | 0 | { |
137 | 0 | enum mail_index_transaction_flags itrans_flags; |
138 | |
|
139 | 0 | if (t->box->view_pvt == NULL || t->itrans_pvt != NULL) |
140 | 0 | return; |
141 | | |
142 | 0 | itrans_flags = index_transaction_flags_get(t->flags); |
143 | 0 | t->itrans_pvt = mail_index_transaction_begin(t->box->view_pvt, |
144 | 0 | itrans_flags); |
145 | 0 | t->view_pvt = mail_index_transaction_open_updated_view(t->itrans_pvt); |
146 | 0 | } |
147 | | |
148 | | void index_transaction_init(struct mailbox_transaction_context *t, |
149 | | struct mailbox *box, |
150 | | enum mailbox_transaction_flags flags, |
151 | | const char *reason) |
152 | 0 | { |
153 | 0 | enum mail_index_transaction_flags itrans_flags; |
154 | |
|
155 | 0 | i_assert(box->opened); |
156 | | |
157 | 0 | itrans_flags = index_transaction_flags_get(flags); |
158 | 0 | if ((flags & MAILBOX_TRANSACTION_FLAG_REFRESH) != 0) |
159 | 0 | mail_index_refresh(box->index); |
160 | |
|
161 | 0 | t->flags = flags; |
162 | 0 | t->box = box; |
163 | 0 | t->reason = i_strdup(reason); |
164 | 0 | t->itrans = mail_index_transaction_begin(box->view, itrans_flags); |
165 | 0 | t->view = mail_index_transaction_open_updated_view(t->itrans); |
166 | |
|
167 | 0 | array_create(&t->module_contexts, default_pool, |
168 | 0 | sizeof(void *), 5); |
169 | |
|
170 | 0 | t->cache_view = mail_cache_view_open(box->cache, t->view); |
171 | 0 | t->cache_trans = mail_cache_get_transaction(t->cache_view, t->itrans); |
172 | |
|
173 | 0 | if ((flags & MAILBOX_TRANSACTION_FLAG_NO_CACHE_DEC) != 0) |
174 | 0 | mail_cache_view_update_cache_decisions(t->cache_view, FALSE); |
175 | | |
176 | | /* set up after mail_cache_get_transaction(), so that we'll still |
177 | | have the cache_trans available in _index_commit() */ |
178 | 0 | t->super = t->itrans->v; |
179 | 0 | t->itrans->v.commit = index_transaction_index_commit; |
180 | 0 | t->itrans->v.rollback = index_transaction_index_rollback; |
181 | 0 | MODULE_CONTEXT_SET(t->itrans, mail_storage_mail_index_module, t); |
182 | 0 | } |
183 | | |
184 | | struct mailbox_transaction_context * |
185 | | index_transaction_begin(struct mailbox *box, |
186 | | enum mailbox_transaction_flags flags, |
187 | | const char *reason) |
188 | 0 | { |
189 | 0 | struct mailbox_transaction_context *t; |
190 | |
|
191 | 0 | t = i_new(struct mailbox_transaction_context, 1); |
192 | 0 | index_transaction_init(t, box, flags, reason); |
193 | 0 | return t; |
194 | 0 | } |
195 | | |
196 | | int index_transaction_commit(struct mailbox_transaction_context *t, |
197 | | struct mail_transaction_commit_changes *changes_r) |
198 | 0 | { |
199 | 0 | struct mailbox *box = t->box; |
200 | 0 | struct mail_index_transaction *itrans = t->itrans; |
201 | 0 | struct mail_index_transaction_commit_result result; |
202 | 0 | int ret = 0; |
203 | |
|
204 | 0 | i_zero(changes_r); |
205 | 0 | changes_r->pool = pool_alloconly_create(MEMPOOL_GROWING |
206 | 0 | "transaction changes", 512); |
207 | 0 | p_array_init(&changes_r->saved_uids, changes_r->pool, 32); |
208 | 0 | t->changes = changes_r; |
209 | |
|
210 | 0 | if (t->itrans_pvt != NULL) |
211 | 0 | ret = mail_index_transaction_commit(&t->itrans_pvt); |
212 | 0 | if (mail_index_transaction_commit_full(&itrans, &result) < 0) |
213 | 0 | ret = -1; |
214 | 0 | t = NULL; |
215 | |
|
216 | 0 | if (ret < 0 && mail_index_is_deleted(box->index)) |
217 | 0 | mailbox_set_deleted(box); |
218 | |
|
219 | 0 | changes_r->ignored_modseq_changes = result.ignored_modseq_changes; |
220 | 0 | return ret; |
221 | 0 | } |
222 | | |
223 | | void index_transaction_rollback(struct mailbox_transaction_context *t) |
224 | 0 | { |
225 | 0 | struct mail_index_transaction *itrans = t->itrans; |
226 | |
|
227 | 0 | if (t->itrans_pvt != NULL) |
228 | 0 | mail_index_transaction_rollback(&t->itrans_pvt); |
229 | 0 | mail_index_transaction_rollback(&itrans); |
230 | 0 | } |