Mercurial > dovecot > original-hg > dovecot-1.2
comparison src/lib-storage/index/maildir/maildir-sync.c @ 3446:113c888cdca1 HEAD
Merge changes from multiple index sync records into one before actually
renaming maildir files.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 29 Jun 2005 01:32:38 +0300 |
parents | 3c51658d6846 |
children | 96de02ea7482 |
comparison
equal
deleted
inserted
replaced
3445:74475a126e2f | 3446:113c888cdca1 |
---|---|
209 struct maildir_mailbox *mbox; | 209 struct maildir_mailbox *mbox; |
210 struct mail_index_view *view; | 210 struct mail_index_view *view; |
211 struct mail_index_sync_ctx *sync_ctx; | 211 struct mail_index_sync_ctx *sync_ctx; |
212 struct mail_index_transaction *trans; | 212 struct mail_index_transaction *trans; |
213 | 213 |
214 struct mail_index_sync_rec sync_rec; | 214 array_t ARRAY_DEFINE(sync_recs, struct mail_index_sync_rec); |
215 uint32_t seq; | 215 uint32_t seq; |
216 int dirty_state; | 216 int dirty_state; |
217 }; | 217 }; |
218 | 218 |
219 static int maildir_expunge(struct maildir_mailbox *mbox, const char *path, | 219 static int maildir_expunge(struct maildir_mailbox *mbox, const char *path, |
233 | 233 |
234 static int maildir_sync_flags(struct maildir_mailbox *mbox, const char *path, | 234 static int maildir_sync_flags(struct maildir_mailbox *mbox, const char *path, |
235 void *context) | 235 void *context) |
236 { | 236 { |
237 struct maildir_index_sync_context *ctx = context; | 237 struct maildir_index_sync_context *ctx = context; |
238 const struct mail_index_sync_rec *recs; | |
238 const char *newpath; | 239 const char *newpath; |
239 enum mail_flags flags; | 240 enum mail_flags flags; |
240 const char *const *keywords; | 241 const char *const *keywords; |
242 unsigned int i, count; | |
241 uint8_t flags8; | 243 uint8_t flags8; |
242 | 244 |
243 ctx->dirty_state = 0; | 245 ctx->dirty_state = 0; |
244 | 246 |
245 (void)maildir_filename_get_flags(path, pool_datastack_create(), | 247 (void)maildir_filename_get_flags(path, pool_datastack_create(), |
246 &flags, &keywords); | 248 &flags, &keywords); |
247 | |
248 flags8 = flags; | 249 flags8 = flags; |
249 mail_index_sync_flags_apply(&ctx->sync_rec, &flags8); | 250 |
251 recs = array_get_modifyable(&ctx->sync_recs, &count); | |
252 for (i = 0; i < count; i++) { | |
253 if (recs[i].uid1 != ctx->seq) | |
254 break; | |
255 | |
256 switch (recs[i].type) { | |
257 case MAIL_INDEX_SYNC_TYPE_FLAGS: | |
258 mail_index_sync_flags_apply(&recs[i], &flags8); | |
259 break; | |
260 case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD: | |
261 case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE: | |
262 case MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET: | |
263 /*FIXME:mail_index_sync_keywords_apply(&recs[i], &keywords);*/ | |
264 break; | |
265 case MAIL_INDEX_SYNC_TYPE_APPEND: | |
266 case MAIL_INDEX_SYNC_TYPE_EXPUNGE: | |
267 i_unreached(); | |
268 break; | |
269 } | |
270 } | |
250 | 271 |
251 newpath = maildir_filename_set_flags(path, flags8, keywords); | 272 newpath = maildir_filename_set_flags(path, flags8, keywords); |
252 if (rename(path, newpath) == 0) { | 273 if (rename(path, newpath) == 0) { |
253 if ((flags8 & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) | 274 if ((flags8 & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) |
254 ctx->dirty_state = -1; | 275 ctx->dirty_state = -1; |
268 mail_storage_set_critical(STORAGE(mbox->storage), | 289 mail_storage_set_critical(STORAGE(mbox->storage), |
269 "rename(%s, %s) failed: %m", path, newpath); | 290 "rename(%s, %s) failed: %m", path, newpath); |
270 return -1; | 291 return -1; |
271 } | 292 } |
272 | 293 |
273 static int maildir_sync_record(struct maildir_mailbox *mbox, | 294 static int |
274 struct maildir_index_sync_context *ctx) | 295 maildir_sync_record_commit_until(struct maildir_index_sync_context *ctx, |
275 { | 296 uint32_t last_seq) |
276 struct mail_index_sync_rec *sync_rec = &ctx->sync_rec; | 297 { |
277 struct mail_index_view *view = ctx->view; | 298 struct mail_index_sync_rec *recs; |
278 uint32_t seq, seq1, seq2, uid; | 299 unsigned int i, count; |
279 | 300 uint32_t seq, uid; |
280 switch (sync_rec->type) { | 301 int expunged, flag_changed; |
281 case MAIL_INDEX_SYNC_TYPE_APPEND: | 302 |
282 break; | 303 recs = array_get_modifyable(&ctx->sync_recs, &count); |
283 case MAIL_INDEX_SYNC_TYPE_EXPUNGE: | 304 for (seq = recs[0].uid1; seq <= last_seq; seq++) { |
284 /* make it go through sequences to avoid looping through huge | 305 expunged = flag_changed = FALSE; |
285 holes in UID range */ | 306 for (i = 0; i < count; i++) { |
286 if (mail_index_lookup_uid_range(view, sync_rec->uid1, | 307 if (recs[i].uid1 > seq) |
287 sync_rec->uid2, | 308 break; |
288 &seq1, &seq2) < 0) | 309 |
310 i_assert(recs[i].uid1 == seq); | |
311 switch (recs[i].type) { | |
312 case MAIL_INDEX_SYNC_TYPE_EXPUNGE: | |
313 expunged = TRUE; | |
314 break; | |
315 case MAIL_INDEX_SYNC_TYPE_FLAGS: | |
316 case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD: | |
317 case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE: | |
318 case MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET: | |
319 flag_changed = TRUE; | |
320 break; | |
321 case MAIL_INDEX_SYNC_TYPE_APPEND: | |
322 i_unreached(); | |
323 break; | |
324 } | |
325 } | |
326 | |
327 if (mail_index_lookup_uid(ctx->view, seq, &uid) < 0) | |
289 return -1; | 328 return -1; |
290 | 329 |
291 if (seq1 == 0) | 330 ctx->seq = seq; |
292 break; | 331 if (expunged) { |
293 | 332 if (maildir_file_do(ctx->mbox, uid, |
294 for (seq = seq1; seq <= seq2; seq++) { | 333 maildir_expunge, ctx) < 0) |
295 if (mail_index_lookup_uid(view, seq, &uid) < 0) | |
296 return -1; | 334 return -1; |
297 if (maildir_file_do(mbox, uid, maildir_expunge, | 335 } else if (flag_changed) { |
298 NULL) < 0) | 336 if (maildir_file_do(ctx->mbox, uid, |
299 return -1; | |
300 } | |
301 break; | |
302 case MAIL_INDEX_SYNC_TYPE_FLAGS: | |
303 if (mail_index_lookup_uid_range(view, sync_rec->uid1, | |
304 sync_rec->uid2, | |
305 &seq1, &seq2) < 0) | |
306 return -1; | |
307 | |
308 if (seq1 == 0) | |
309 break; | |
310 | |
311 for (ctx->seq = seq1; ctx->seq <= seq2; ctx->seq++) { | |
312 if (mail_index_lookup_uid(view, ctx->seq, &uid) < 0) | |
313 return -1; | |
314 if (maildir_file_do(mbox, uid, | |
315 maildir_sync_flags, ctx) < 0) | 337 maildir_sync_flags, ctx) < 0) |
316 return -1; | 338 return -1; |
317 if (ctx->dirty_state < 0) { | 339 } |
318 /* flag isn't dirty anymore */ | 340 |
319 mail_index_update_flags(ctx->trans, ctx->seq, | 341 for (i = count; i > 0; i--) { |
320 MODIFY_REMOVE, | 342 if (++recs[i-1].uid1 > recs[i-1].uid2) { |
321 MAIL_INDEX_MAIL_FLAG_DIRTY); | 343 array_delete(&ctx->sync_recs, i-1, 1); |
344 recs = array_get_modifyable(&ctx->sync_recs, | |
345 &count); | |
346 if (count == 0) { | |
347 /* all sync_recs committed */ | |
348 return 0; | |
349 } | |
322 } | 350 } |
323 } | 351 } |
324 break; | 352 } |
325 case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD: | |
326 case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE: | |
327 case MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET: | |
328 // FIXME | |
329 break; | |
330 } | |
331 | |
332 return 0; | 353 return 0; |
354 } | |
355 | |
356 static int maildir_sync_record(struct maildir_index_sync_context *ctx, | |
357 const struct mail_index_sync_rec *sync_rec) | |
358 { | |
359 struct mail_index_view *view = ctx->view; | |
360 struct mail_index_sync_rec sync_copy; | |
361 | |
362 if (sync_rec == NULL) { | |
363 /* deinit */ | |
364 while (array_count(&ctx->sync_recs) > 0) { | |
365 if (maildir_sync_record_commit_until(ctx, | |
366 (uint32_t)-1) < 0) | |
367 return -1; | |
368 } | |
369 return 0; | |
370 } | |
371 | |
372 if (sync_rec->type == MAIL_INDEX_SYNC_TYPE_APPEND) | |
373 return 0; /* ignore */ | |
374 | |
375 /* convert to sequences to avoid looping through huge holes in | |
376 UID range */ | |
377 sync_copy = *sync_rec; | |
378 if (mail_index_lookup_uid_range(view, sync_rec->uid1, | |
379 sync_rec->uid2, | |
380 &sync_copy.uid1, | |
381 &sync_copy.uid2) < 0) | |
382 return -1; | |
383 | |
384 while (array_count(&ctx->sync_recs) > 0) { | |
385 const struct mail_index_sync_rec *rec = | |
386 array_idx(&ctx->sync_recs, 0); | |
387 | |
388 i_assert(rec->uid1 <= sync_copy.uid1); | |
389 if (rec->uid1 == sync_copy.uid1) | |
390 break; | |
391 | |
392 if (maildir_sync_record_commit_until(ctx, sync_copy.uid1-1) < 0) | |
393 return -1; | |
394 } | |
395 | |
396 array_append(&ctx->sync_recs, &sync_copy, 1); | |
397 return 0; | |
398 } | |
399 | |
400 static int maildir_sync_index_records(struct maildir_index_sync_context *ctx) | |
401 { | |
402 struct mail_index_sync_rec sync_rec; | |
403 int ret; | |
404 | |
405 ret = mail_index_sync_next(ctx->sync_ctx, &sync_rec); | |
406 if (ret <= 0) | |
407 return ret; | |
408 | |
409 ARRAY_CREATE(&ctx->sync_recs, pool_datastack_create(), | |
410 struct mail_index_sync_rec, 32); | |
411 do { | |
412 if (maildir_sync_record(ctx, &sync_rec) < 0) | |
413 return -1; | |
414 | |
415 ret = mail_index_sync_next(ctx->sync_ctx, &sync_rec); | |
416 } while (ret > 0); | |
417 | |
418 if (maildir_sync_record(ctx, NULL) < 0) | |
419 return -1; | |
420 return ret; | |
333 } | 421 } |
334 | 422 |
335 int maildir_sync_last_commit(struct maildir_mailbox *mbox) | 423 int maildir_sync_last_commit(struct maildir_mailbox *mbox) |
336 { | 424 { |
337 struct maildir_index_sync_context ctx; | 425 struct maildir_index_sync_context ctx; |
350 mbox->ibox.commit_log_file_seq, | 438 mbox->ibox.commit_log_file_seq, |
351 mbox->ibox.commit_log_file_offset, | 439 mbox->ibox.commit_log_file_offset, |
352 FALSE, FALSE); | 440 FALSE, FALSE); |
353 if (ret > 0) { | 441 if (ret > 0) { |
354 ctx.trans = mail_index_transaction_begin(ctx.view, FALSE, TRUE); | 442 ctx.trans = mail_index_transaction_begin(ctx.view, FALSE, TRUE); |
355 | 443 if (maildir_sync_index_records(&ctx) < 0) |
356 while ((ret = mail_index_sync_next(ctx.sync_ctx, | 444 ret = -1; |
357 &ctx.sync_rec)) > 0) { | |
358 if (maildir_sync_record(mbox, &ctx) < 0) { | |
359 ret = -1; | |
360 break; | |
361 } | |
362 } | |
363 if (mail_index_transaction_commit(ctx.trans, &seq, &offset) < 0) | 445 if (mail_index_transaction_commit(ctx.trans, &seq, &offset) < 0) |
364 ret = -1; | 446 ret = -1; |
365 if (mail_index_sync_commit(ctx.sync_ctx) < 0) | 447 if (mail_index_sync_commit(ctx.sync_ctx) < 0) |
366 ret = -1; | 448 ret = -1; |
367 } | 449 } |
621 enum maildir_uidlist_rec_flag uflags; | 703 enum maildir_uidlist_rec_flag uflags; |
622 const char *filename; | 704 const char *filename; |
623 enum mail_flags flags; | 705 enum mail_flags flags; |
624 const char *const *keywords; | 706 const char *const *keywords; |
625 uint32_t uid_validity, next_uid; | 707 uint32_t uid_validity, next_uid; |
626 int ret, full_rescan = FALSE; | 708 int ret = 0, full_rescan = FALSE; |
627 | 709 |
628 trans = mail_index_transaction_begin(view, FALSE, TRUE); | 710 trans = mail_index_transaction_begin(view, FALSE, TRUE); |
629 sync_ctx->trans = trans; | 711 sync_ctx->trans = trans; |
630 | 712 |
631 hdr = mail_index_get_header(view); | 713 hdr = mail_index_get_header(view); |
802 mail_index_expunge(trans, seq); | 884 mail_index_expunge(trans, seq); |
803 } | 885 } |
804 | 886 |
805 /* now, sync the index */ | 887 /* now, sync the index */ |
806 mbox->syncing_commit = TRUE; | 888 mbox->syncing_commit = TRUE; |
807 while ((ret = mail_index_sync_next(sync_ctx->sync_ctx, | 889 if (maildir_sync_index_records(sync_ctx) < 0) |
808 &sync_ctx->sync_rec)) > 0) { | 890 ret = -1; |
809 if (maildir_sync_record(mbox, sync_ctx) < 0) { | 891 mbox->syncing_commit = FALSE; |
810 ret = -1; | |
811 break; | |
812 } | |
813 } | |
814 mbox->syncing_commit = FALSE; | |
815 | 892 |
816 if (mbox->dirty_cur_time == 0 && | 893 if (mbox->dirty_cur_time == 0 && |
817 mbox->last_cur_mtime != (time_t)hdr->sync_stamp) { | 894 mbox->last_cur_mtime != (time_t)hdr->sync_stamp) { |
818 uint32_t sync_stamp = mbox->last_cur_mtime; | 895 uint32_t sync_stamp = mbox->last_cur_mtime; |
819 | 896 |