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