]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
dsync: If some uid/modseq changes couldn't be done, exit with different value.
authorTimo Sirainen <tss@iki.fi>
Thu, 19 Nov 2009 00:58:37 +0000 (19:58 -0500)
committerTimo Sirainen <tss@iki.fi>
Thu, 19 Nov 2009 00:58:37 +0000 (19:58 -0500)
--HG--
branch : HEAD

src/dsync/dsync-brain.c
src/dsync/dsync-brain.h
src/dsync/dsync-proxy-client.c
src/dsync/dsync-proxy-server-cmd.c
src/dsync/dsync-worker-local.c
src/dsync/dsync-worker-private.h
src/dsync/dsync-worker.c
src/dsync/dsync-worker.h
src/dsync/dsync.c

index 90f02e62bb04f0003d1d7beadc541394f4c0cd75..763cb65637d398ed2614711a39fd60fb96143476 100644 (file)
@@ -614,3 +614,9 @@ void dsync_brain_sync_all(struct dsync_brain *brain)
                i_assert(brain->state != old_state);
        }
 }
+
+bool dsync_brain_has_unexpected_changes(struct dsync_brain *brain)
+{
+       return dsync_worker_has_unexpected_changes(brain->src_worker) ||
+               dsync_worker_has_unexpected_changes(brain->dest_worker);
+}
index 3a31c55bc254c5d283a37963653f2c4b5f9829eb..0acbeff43e0d88459c115f012127f701746edfb3 100644 (file)
@@ -17,4 +17,6 @@ int dsync_brain_deinit(struct dsync_brain **brain);
 void dsync_brain_sync(struct dsync_brain *brain);
 void dsync_brain_sync_all(struct dsync_brain *brain);
 
+bool dsync_brain_has_unexpected_changes(struct dsync_brain *brain);
+
 #endif
index 67fc6bc17f894cead0caeb285d3dc5456efb86e1..b7bc19e2257d87859e38a86466e5390d426681b2 100644 (file)
@@ -196,10 +196,18 @@ proxy_client_worker_next_msg_get(struct proxy_client_dsync_worker *worker,
 }
 
 static void
-proxy_client_worker_next_finish(const struct proxy_client_request *request,
+proxy_client_worker_next_finish(struct proxy_client_dsync_worker *worker,
+                               const struct proxy_client_request *request,
                                const char *line)
 {
-       request->callback.finish(line[0] == '1', request->context);
+       bool success = TRUE;
+
+       if (strcmp(line, "changes") == 0)
+               worker->worker.unexpected_changes = TRUE;
+       else if (strcmp(line, "ok") != 0)
+               success = FALSE;
+               
+       request->callback.finish(success, request->context);
 }
 
 static bool
@@ -229,7 +237,7 @@ proxy_client_worker_next_reply(struct proxy_client_dsync_worker *worker,
                break;
        case PROXY_CLIENT_REQUEST_TYPE_FINISH:
                worker->finished = TRUE;
-               proxy_client_worker_next_finish(&request, line);
+               proxy_client_worker_next_finish(worker, &request, line);
                break;
        }
        return ret;
index a41d97bee64371a8b218c41462e160bdf5a44a9e..e25eec38fa8008fe030a1c728c60d62b4cdda21d 100644 (file)
@@ -503,9 +503,17 @@ cmd_msg_get(struct dsync_proxy_server *server, const char *const *args)
 static void cmd_finish_callback(bool success, void *context)
 {
        struct dsync_proxy_server *server = context;
+       const char *reply;
+
+       if (!success)
+               reply = "fail\n";
+       else if (dsync_worker_has_unexpected_changes(server->worker))
+               reply = "changes\n";
+       else
+               reply = "ok\n";
 
        server->finished = TRUE;
-       o_stream_send_str(server->output, success ? "1\n" : "0\n");
+       o_stream_send_str(server->output, reply);
 }
 
 static int
index 5cdaf8da48f29091854a29a5f4f0605ffc38da13..e057f4c8830dae4708f847ba6977e6215b3e5562 100644 (file)
@@ -77,6 +77,8 @@ struct local_dsync_worker {
        struct mailbox *selected_box;
        struct mail *mail, *ext_mail;
 
+       ARRAY_TYPE(uint32_t) saved_uids;
+
        mailbox_guid_t get_mailbox;
        struct mail *get_mail;
 
@@ -133,6 +135,7 @@ dsync_worker_init_local(struct mail_user *user, char alt_hierarchy_char)
        worker->mailbox_hash =
                hash_table_create(default_pool, pool, 0,
                                  mailbox_guid_hash, mailbox_guid_cmp);
+       i_array_init(&worker->saved_uids, 128);
        return &worker->worker;
 }
 
@@ -150,6 +153,7 @@ static void local_worker_deinit(struct dsync_worker *_worker)
                hash_table_destroy(&worker->mailbox_changes_hash);
        if (worker->subscription_changes_hash != NULL)
                hash_table_destroy(&worker->subscription_changes_hash);
+       array_free(&worker->saved_uids);
        pool_unref(&worker->pool);
 }
 
@@ -1013,28 +1017,60 @@ local_worker_rename_mailbox(struct dsync_worker *_worker,
        }
 }
 
+static bool
+has_expected_save_uids(struct local_dsync_worker *worker,
+                      const struct mail_transaction_commit_changes *changes)
+{
+       struct seq_range_iter iter;
+       const uint32_t *expected_uids;
+       uint32_t uid;
+       unsigned int i, n, expected_count;
+
+       expected_uids = array_get(&worker->saved_uids, &expected_count);
+       seq_range_array_iter_init(&iter, &changes->saved_uids); i = n = 0;
+       while (seq_range_array_iter_nth(&iter, n++, &uid)) {
+               if (i == expected_count || uid != expected_uids[i++])
+                       return FALSE;
+       }
+       return i == expected_count;
+}
+
 static void local_worker_mailbox_close(struct local_dsync_worker *worker)
 {
        struct mailbox_transaction_context *trans, *ext_trans;
+       struct mail_transaction_commit_changes changes;
 
        i_assert(worker->save_input == NULL);
 
-       if (worker->selected_box != NULL) {
-               trans = worker->mail->transaction;
-               ext_trans = worker->ext_mail->transaction;
-               mail_free(&worker->mail);
-               mail_free(&worker->ext_mail);
-               if (mailbox_transaction_commit(&ext_trans) < 0)
-                       dsync_worker_set_failure(&worker->worker);
-               if (mailbox_transaction_commit(&trans) < 0 ||
-                   mailbox_sync(worker->selected_box,
-                                MAILBOX_SYNC_FLAG_FULL_WRITE, 0, NULL) < 0)
-                       dsync_worker_set_failure(&worker->worker);
-
-               mailbox_close(&worker->selected_box);
-       }
        memset(&worker->selected_box_guid, 0,
               sizeof(worker->selected_box_guid));
+
+       if (worker->selected_box == NULL)
+               return;
+
+       trans = worker->mail->transaction;
+       ext_trans = worker->ext_mail->transaction;
+       mail_free(&worker->mail);
+       mail_free(&worker->ext_mail);
+
+       /* all saves and copies go to ext_trans */
+       if (mailbox_transaction_commit_get_changes(&ext_trans, &changes) < 0)
+               dsync_worker_set_failure(&worker->worker);
+       else {
+               if (changes.ignored_uid_changes != 0 ||
+                   changes.ignored_modseq_changes != 0 ||
+                   !has_expected_save_uids(worker, &changes))
+                       worker->worker.unexpected_changes = TRUE;
+               pool_unref(&changes.pool);
+       }
+       array_clear(&worker->saved_uids);
+
+       if (mailbox_transaction_commit(&trans) < 0 ||
+           mailbox_sync(worker->selected_box,
+                        MAILBOX_SYNC_FLAG_FULL_WRITE, 0, NULL) < 0)
+               dsync_worker_set_failure(&worker->worker);
+
+       mailbox_close(&worker->selected_box);
 }
 
 static void
@@ -1173,12 +1209,15 @@ static void local_worker_msg_expunge(struct dsync_worker *_worker, uint32_t uid)
 }
 
 static void
-local_worker_msg_save_set_metadata(struct mailbox *box,
+local_worker_msg_save_set_metadata(struct local_dsync_worker *worker,
+                                  struct mailbox *box,
                                   struct mail_save_context *save_ctx,
                                   const struct dsync_message *msg)
 {
        struct mail_keywords *keywords;
 
+       i_assert(msg->uid != 0);
+
        if (msg->modseq > 1)
                (void)mailbox_enable(box, MAILBOX_FEATURE_CONDSTORE);
 
@@ -1190,6 +1229,8 @@ local_worker_msg_save_set_metadata(struct mailbox *box,
        mailbox_save_set_uid(save_ctx, msg->uid);
        mailbox_save_set_save_date(save_ctx, msg->save_date);
        mailbox_save_set_min_modseq(save_ctx, msg->modseq);
+
+       array_append(&worker->saved_uids, &msg->uid, 1);
 }
 
 static void
@@ -1217,7 +1258,7 @@ local_worker_msg_copy(struct dsync_worker *_worker,
                ret = -1;
        else {
                save_ctx = mailbox_save_alloc(worker->ext_mail->transaction);
-               local_worker_msg_save_set_metadata(worker->mail->box,
+               local_worker_msg_save_set_metadata(worker, worker->mail->box,
                                                   save_ctx, dest_msg);
                ret = mailbox_copy(&save_ctx, src_mail);
        }
@@ -1290,7 +1331,8 @@ local_worker_msg_save(struct dsync_worker *_worker,
 
        save_ctx = mailbox_save_alloc(worker->ext_mail->transaction);
        mailbox_save_set_guid(save_ctx, msg->guid);
-       local_worker_msg_save_set_metadata(worker->mail->box, save_ctx, msg);
+       local_worker_msg_save_set_metadata(worker, worker->mail->box,
+                                          save_ctx, msg);
        mailbox_save_set_pop3_uidl(save_ctx, data->pop3_uidl);
 
        mailbox_save_set_received_date(save_ctx, data->received_date, 0);
index 5f2323e8d66b474e578eeeaca3f6c75ee6462884..c190e1dab70ab8d7ecbfceea1dd97a770b6d87d3 100644 (file)
@@ -76,6 +76,7 @@ struct dsync_worker {
 
        unsigned int readonly:1;
        unsigned int failed:1;
+       unsigned int unexpected_changes:1;
 };
 
 struct dsync_worker_mailbox_iter {
index d50971ac5b0770fd228242bf00a649cb849ea96d..a27946460ea3e76b8803782a8c0b30864f0c8cd7 100644 (file)
@@ -242,3 +242,8 @@ bool dsync_worker_has_failed(struct dsync_worker *worker)
 {
        return worker->failed;
 }
+
+bool dsync_worker_has_unexpected_changes(struct dsync_worker *worker)
+{
+       return worker->unexpected_changes;
+}
index 726c81c221b37298459b4b3d5c70f715d56dfdd8..7fa2989b70bef63037cff5f2b6f17f4cb4051eec 100644 (file)
@@ -147,5 +147,8 @@ void dsync_worker_finish(struct dsync_worker *worker,
 
 /* Returns TRUE if some commands have failed. */
 bool dsync_worker_has_failed(struct dsync_worker *worker);
+/* Returns TRUE if some UID or modseq changes didn't get assigned as
+   requested. */
+bool dsync_worker_has_unexpected_changes(struct dsync_worker *worker);
 
 #endif
index 7e2a1d86f9bfcf975b9bc855c912b6a6f4290601..f383ca6896136122614e87b408ddfe0b8482a95c 100644 (file)
@@ -84,7 +84,7 @@ int main(int argc, char *argv[])
        struct dsync_worker *worker1, *worker2;
        const char *error, *username, *mailbox = NULL, *mirror_cmd = NULL;
        const char *convert_location = NULL;
-       bool dsync_server = FALSE, readonly = FALSE;
+       bool dsync_server = FALSE, readonly = FALSE, unexpected_changes = FALSE;
        char alt_hierarchy_char = '_';
        int c, ret, fd_in = STDIN_FILENO, fd_out = STDOUT_FILENO;
 
@@ -207,10 +207,13 @@ int main(int argc, char *argv[])
                master_service_run(master_service, dsync_connected);
        }
 
-       if (brain != NULL)
-               ret = dsync_brain_deinit(&brain);
-       else
+       if (brain == NULL)
                ret = 0;
+       else {
+               if (dsync_brain_has_unexpected_changes(brain))
+                       unexpected_changes = TRUE;
+               ret = dsync_brain_deinit(&brain);
+       }
        if (server != NULL)
                dsync_proxy_server_deinit(&server);
 
@@ -223,7 +226,13 @@ int main(int argc, char *argv[])
                mail_user_unref(&mail_user2);
        mail_storage_service_user_free(&service_user);
 
+       if (unexpected_changes &&
+           (brain_flags & DSYNC_BRAIN_FLAG_VERBOSE) != 0) {
+               i_info("Mailbox changes caused a desync. "
+                      "You might want to run dsync again.");
+       }
+
        mail_storage_service_deinit(&storage_service);
        master_service_deinit(&master_service);
-       return ret < 0 ? 1 : 0;
+       return ret < 0 ? 1 : (unexpected_changes ? 2 : 0);
 }