Mercurial > dovecot > core-2.2
diff src/director/user-directory.c @ 14468:0b4295b48941
director: Optimized adding users to linked list during handshake.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 19 Apr 2012 21:51:48 +0300 |
parents | 5b05411a81cf |
children | 9104a9074a5a |
line wrap: on
line diff
--- a/src/director/user-directory.c Thu Apr 19 20:29:25 2012 +0300 +++ b/src/director/user-directory.c Thu Apr 19 21:51:48 2012 +0300 @@ -24,6 +24,7 @@ struct hash_table *hash; /* sorted by time */ struct user *head, *tail; + struct user *prev_insert_pos; ARRAY_DEFINE(iters, struct user_directory_iter *); @@ -42,6 +43,9 @@ if ((*iterp)->pos == user) (*iterp)->pos = user->next; } + + if (dir->prev_insert_pos == user) + dir->prev_insert_pos = user->next; } static void user_free(struct user_directory *dir, struct user *user) @@ -79,11 +83,61 @@ return hash_table_lookup(dir->hash, POINTER_CAST(username_hash)); } +static void +user_directory_insert_backwards(struct user_directory *dir, + struct user *pos, struct user *user) +{ + for (; pos != NULL; pos = pos->prev) { + if ((time_t)pos->timestamp <= user->timestamp) + break; + } + if (pos == NULL) + DLLIST2_PREPEND(&dir->head, &dir->tail, user); + else { + user->prev = pos; + user->next = pos->next; + user->prev->next = user; + if (user->next != NULL) + user->next->prev = user; + else + dir->tail = user; + } +} + +static void +user_directory_insert_forwards(struct user_directory *dir, + struct user *pos, struct user *user) +{ + for (; pos != NULL; pos = pos->next) { + if ((time_t)pos->timestamp >= user->timestamp) + break; + } + if (pos == NULL) + DLLIST2_APPEND(&dir->head, &dir->tail, user); + else { + user->prev = pos->prev; + user->next = pos; + if (user->prev != NULL) + user->prev->next = user; + else + dir->head = user; + user->next->prev = user; + } +} + struct user * user_directory_add(struct user_directory *dir, unsigned int username_hash, struct mail_host *host, time_t timestamp) { - struct user *user, *pos; + struct user *user; + + if (timestamp == (time_t)-1) { + /* make sure we add it at the end */ + timestamp = ioloop_time; + if (dir->tail != NULL && + timestamp < (time_t)dir->tail->timestamp) + timestamp = (time_t)dir->tail->timestamp; + } user = i_new(struct user, 1); user->username_hash = username_hash; @@ -94,21 +148,24 @@ if (dir->tail == NULL || (time_t)dir->tail->timestamp <= timestamp) DLLIST2_APPEND(&dir->head, &dir->tail, user); else { - /* need to insert to correct position */ - for (pos = dir->tail; pos != NULL; pos = pos->prev) { - if ((time_t)pos->timestamp <= timestamp) - break; - } - if (pos == NULL) - DLLIST2_PREPEND(&dir->head, &dir->tail, user); - else { - user->prev = pos; - user->next = pos->next; - user->prev->next = user; - user->next->prev = user; + /* need to insert to correct position. we should get here + only when handshaking. the handshaking USER requests should + come sorted by timestamp. so keep track of the previous + insert position, the next USER should be inserted after + it. */ + if (dir->prev_insert_pos == NULL) { + /* find the position starting from tail */ + user_directory_insert_backwards(dir, dir->tail, user); + } else if (timestamp < dir->prev_insert_pos->timestamp) { + user_directory_insert_backwards(dir, dir->prev_insert_pos, + user); + } else { + user_directory_insert_forwards(dir, dir->prev_insert_pos, + user); } } + dir->prev_insert_pos = user; hash_table_insert(dir->hash, POINTER_CAST(user->username_hash), user); return user; }