]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Locking fixes. use less memory
authorTimo Sirainen <tss@iki.fi>
Mon, 14 Jun 2004 05:22:51 +0000 (08:22 +0300)
committerTimo Sirainen <tss@iki.fi>
Mon, 14 Jun 2004 05:22:51 +0000 (08:22 +0300)
--HG--
branch : HEAD

src/lib-storage/index/maildir/maildir-sync.c
src/lib-storage/index/maildir/maildir-uidlist.c

index 66db21a9c06a5e70905d54a320aa23677c6366c2..8f60cdb1e3f83e704cb4d27f67f8c25a5cb7b934 100644 (file)
@@ -424,9 +424,6 @@ static int maildir_scan_dir(struct maildir_sync_context *ctx, int new_dir)
         enum maildir_uidlist_rec_flag flags;
        int move_new, ret = 1;
 
-       src = t_str_new(1024);
-       dest = t_str_new(1024);
-
        dir = new_dir ? ctx->new_dir : ctx->cur_dir;
        dirp = opendir(dir);
        if (dirp == NULL) {
@@ -435,6 +432,10 @@ static int maildir_scan_dir(struct maildir_sync_context *ctx, int new_dir)
                return -1;
        }
 
+       t_push();
+       src = t_str_new(1024);
+       dest = t_str_new(1024);
+
        move_new = new_dir && !mailbox_is_readonly(&ctx->ibox->box) &&
                !ctx->ibox->keep_recent;
        while ((dp = readdir(dirp)) != NULL) {
@@ -507,6 +508,8 @@ static int maildir_scan_dir(struct maildir_sync_context *ctx, int new_dir)
                mail_storage_set_critical(storage,
                                          "closedir(%s) failed: %m", dir);
        }
+
+       t_pop();
        return ret < 0 ? -1 : 0;
 }
 
@@ -835,6 +838,15 @@ static int maildir_sync_context(struct maildir_sync_context *ctx)
        ctx->uidlist_sync_ctx =
                maildir_uidlist_sync_init(ctx->ibox->uidlist, ctx->partial);
 
+       /* we have to lock uidlist immediately, otherwise there's race
+          conditions with other processes who might write older maildir
+          file list into uidlist.
+
+          alternative would be to lock it when new files are found, but
+          the directory scans _must_ be restarted then */
+       if (maildir_uidlist_try_lock(ctx->ibox->uidlist) < 0)
+               return -1;
+
        if (maildir_scan_dir(ctx, TRUE) < 0)
                return -1;
        if (cur_changed) {
index bc51ab463d2f348c41bce27a78a1a86ae0a49da8..f7b9c0145f9a6b5f63b89c9e47063fef71acbfe5 100644 (file)
@@ -91,8 +91,12 @@ int maildir_uidlist_try_lock(struct maildir_uidlist *uidlist)
                        "file_dotlock_open(%s) failed: %m", path);
                return -1;
        }
-
        uidlist->lock_fd = fd;
+
+       /* our view of uidlist must be up-to-date if we plan on changing it */
+       if (maildir_uidlist_update(uidlist) < 0)
+               return -1;
+
        return 1;
 }
 
@@ -463,8 +467,10 @@ static int maildir_uidlist_rewrite_fd(struct maildir_uidlist *uidlist,
 
        iter = maildir_uidlist_iter_init(uidlist->ibox->uidlist);
        while (maildir_uidlist_iter_next(iter, &uid, &flags, &filename)) {
+               /* avoid overflowing str buffer so we don't eat more memory
+                  than we need. */
                if (str_len(str) + MAX_INT_STRLEN +
-                   strlen(filename) + 2 >= 4096) {
+                   strlen(filename) + 5 + 10 >= 4096) {
                        /* flush buffer */
                        if (write_full(uidlist->lock_fd,
                                       str_data(str), str_len(str)) < 0) {
@@ -592,6 +598,11 @@ static int maildir_uidlist_sync_uidlist(struct maildir_uidlist_sync_ctx *ctx)
 
        i_assert(!ctx->synced);
 
+       if (UIDLIST_IS_LOCKED(ctx->uidlist)) {
+               ctx->synced = TRUE;
+               return 1;
+       }
+
        if (!ctx->uidlist->initial_read) {
                /* first time reading the uidlist,
                   no locking yet */
@@ -612,10 +623,6 @@ static int maildir_uidlist_sync_uidlist(struct maildir_uidlist_sync_ctx *ctx)
                ctx->failed = TRUE;
                return -1;
        }
-       if (maildir_uidlist_update(ctx->uidlist) < 0) {
-               ctx->failed = TRUE;
-               return -1;
-       }
 
        ctx->synced = TRUE;
        return 1;
@@ -842,8 +849,11 @@ int maildir_uidlist_sync_deinit(struct maildir_uidlist_sync_ctx *ctx)
        if (!ctx->finished)
                maildir_uidlist_sync_finish(ctx);
 
-       if (ctx->new_files_count != 0 && !ctx->failed && !ctx->locked)
+       if (ctx->new_files_count != 0 && !ctx->failed && !ctx->locked) {
+               t_push();
                ret = maildir_uidlist_rewrite(ctx->uidlist);
+               t_pop();
+       }
 
        if (ctx->partial)
                maildir_uidlist_mark_all(ctx->uidlist, FALSE);