]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
director: Update existing users' timestamps during handshake.
authorTimo Sirainen <tss@iki.fi>
Mon, 29 Jul 2013 19:49:17 +0000 (22:49 +0300)
committerTimo Sirainen <tss@iki.fi>
Mon, 29 Jul 2013 19:49:17 +0000 (22:49 +0300)
src/director/director-connection.c
src/director/user-directory.c
src/director/user-directory.h

index 35efbf38cf50c7420529f67eb0e194cc28ab70e0..9e4dde92f8bd79a1ce4f782ae46bb4120f9ebbda 100644 (file)
@@ -119,6 +119,7 @@ struct director_connection {
        unsigned int synced:1;
        unsigned int wrong_host:1;
        unsigned int verifying_left:1;
+       unsigned int users_unsorted:1;
 };
 
 static void director_connection_disconnected(struct director_connection **conn);
@@ -578,6 +579,10 @@ director_handshake_cmd_user(struct director_connection *conn,
 
        (void)director_user_refresh(conn, username_hash, host,
                                    timestamp, weak, &user);
+       if (user->timestamp < timestamp) {
+               conn->users_unsorted = TRUE;
+               user->timestamp = timestamp;
+       }
        return TRUE;
 }
 
@@ -975,6 +980,12 @@ static bool director_handshake_cmd_done(struct director_connection *conn)
        unsigned int handshake_secs = time(NULL) - conn->created;
        string_t *str;
 
+       if (conn->users_unsorted && conn->user_iter == NULL) {
+               /* we sent our user list before receiving remote's */
+               conn->users_unsorted = FALSE;
+               user_directory_sort(conn->dir->users);
+       }
+
        if (handshake_secs >= DIRECTOR_HANDSHAKE_WARN_SECS || director_debug) {
                str = t_str_new(128);
                str_printfa(str, "director(%s): Handshake took %u secs, "
@@ -1437,6 +1448,12 @@ static int director_connection_send_users(struct director_connection *conn)
        user_directory_iter_deinit(&conn->user_iter);
        director_connection_send(conn, "DONE\n");
 
+       if (conn->users_unsorted && conn->handshake_received) {
+               /* we received remote's list of users before sending ours */
+               conn->users_unsorted = FALSE;
+               user_directory_sort(conn->dir->users);
+       }
+
        ret = o_stream_flush(conn->output);
        timeout_reset(conn->to_ping);
        return ret;
index a8178e0815b07e1afc5bf992ab52b0f35a9425a8..c85a20fb23b93bde2a3e354760ea5337424469d8 100644 (file)
@@ -210,6 +210,43 @@ void user_directory_remove_host(struct user_directory *dir,
        }
 }
 
+static int user_timestamp_cmp(struct user *const *user1,
+                             struct user *const *user2)
+{
+       if ((*user1)->timestamp < (*user2)->timestamp)
+               return -1;
+       if ((*user1)->timestamp > (*user2)->timestamp)
+               return 1;
+       return 0;
+}
+
+void user_directory_sort(struct user_directory *dir)
+{
+       ARRAY(struct user *) users;
+       struct user *user, *const *userp;
+       unsigned int i, users_count = hash_table_count(dir->hash);
+
+       if (users_count == 0) {
+               i_assert(dir->head == NULL);
+               return;
+       }
+
+       /* place all users into array and sort it */
+       i_array_init(&users, users_count);
+       user = dir->head;
+       for (i = 0; i < users_count; i++, user = user->next)
+               array_append(&users, &user, 1);
+       i_assert(user == NULL);
+       array_sort(&users, user_timestamp_cmp);
+
+       /* recreate the linked list */
+       dir->head = dir->tail = NULL;
+       array_foreach(&users, userp)
+               DLLIST2_APPEND(&dir->head, &dir->tail, *userp);
+       i_assert(dir->head->timestamp <= dir->tail->timestamp);
+       array_free(&users);
+}
+
 unsigned int user_directory_get_username_hash(struct user_directory *dir,
                                              const char *username)
 {
index f12cfc166589dae43fbd0cc23d6bddf0630d27d5..7578c6b1616f77f16101a0aea911be167e9e62e6 100644 (file)
@@ -64,6 +64,9 @@ void user_directory_refresh(struct user_directory *dir, struct user *user);
 /* Remove all users that have pointers to given host */
 void user_directory_remove_host(struct user_directory *dir,
                                struct mail_host *host);
+/* Sort users based on the timestamp. This is called only after updating
+   timestamps based on remote director's user list after handshake. */
+void user_directory_sort(struct user_directory *dir);
 
 unsigned int user_directory_get_username_hash(struct user_directory *dir,
                                              const char *username);