comparison src/director/user-directory.c @ 22633:9284bdc3c5c5

director: Don't recreate timeout on every user lookup Recreate it only when the timeout should change.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Sat, 04 Nov 2017 01:34:02 +0200
parents fd12e91c6718
children a96fa917ced1
comparison
equal deleted inserted replaced
22632:fd12e91c6718 22633:9284bdc3c5c5
33 unsigned int timeout_secs; 33 unsigned int timeout_secs;
34 /* If user's expire time is less than this many seconds away, 34 /* If user's expire time is less than this many seconds away,
35 don't assume that other directors haven't yet expired it */ 35 don't assume that other directors haven't yet expired it */
36 unsigned int user_near_expiring_secs; 36 unsigned int user_near_expiring_secs;
37 struct timeout *to_expire; 37 struct timeout *to_expire;
38 time_t to_expire_timestamp;
38 }; 39 };
39 40
40 static void user_move_iters(struct user_directory *dir, struct user *user) 41 static void user_move_iters(struct user_directory *dir, struct user *user)
41 { 42 {
42 struct user_directory_iter *const *iterp; 43 struct user_directory_iter *const *iterp;
64 i_free(user); 65 i_free(user);
65 } 66 }
66 67
67 static bool user_directory_user_has_connections(struct user_directory *dir, 68 static bool user_directory_user_has_connections(struct user_directory *dir,
68 struct user *user, 69 struct user *user,
69 unsigned int *retry_secs_r) 70 time_t *expire_timestamp_r)
70 { 71 {
71 time_t expire_timestamp = user->timestamp + dir->timeout_secs; 72 time_t expire_timestamp = user->timestamp + dir->timeout_secs;
72 73
73 if (expire_timestamp > ioloop_time) { 74 if (expire_timestamp > ioloop_time) {
74 *retry_secs_r = expire_timestamp - ioloop_time; 75 *expire_timestamp_r = expire_timestamp;
75 return TRUE; 76 return TRUE;
76 } 77 }
77 78
78 if (USER_IS_BEING_KILLED(user)) { 79 if (USER_IS_BEING_KILLED(user)) {
79 /* don't free this user until the kill is finished */ 80 /* don't free this user until the kill is finished */
80 *retry_secs_r = USER_BEING_KILLED_EXPIRE_RETRY_SECS; 81 *expire_timestamp_r = ioloop_time +
82 USER_BEING_KILLED_EXPIRE_RETRY_SECS;
81 return TRUE; 83 return TRUE;
82 } 84 }
83 85
84 if (user->weak) { 86 if (user->weak) {
85 if (expire_timestamp + USER_NEAR_EXPIRING_MAX > ioloop_time) { 87 if (expire_timestamp + USER_NEAR_EXPIRING_MAX > ioloop_time) {
86 *retry_secs_r = expire_timestamp + 88 *expire_timestamp_r = expire_timestamp +
87 USER_NEAR_EXPIRING_MAX - ioloop_time; 89 USER_NEAR_EXPIRING_MAX;
88 return TRUE; 90 return TRUE;
89 } 91 }
90 92
91 i_warning("User %u weakness appears to be stuck, removing it", 93 i_warning("User %u weakness appears to be stuck, removing it",
92 user->username_hash); 94 user->username_hash);
94 return FALSE; 96 return FALSE;
95 } 97 }
96 98
97 static void user_directory_drop_expired(struct user_directory *dir) 99 static void user_directory_drop_expired(struct user_directory *dir)
98 { 100 {
99 unsigned int retry_secs = 0; 101 time_t expire_timestamp = 0;
100 102
101 while (dir->head != NULL && 103 while (dir->head != NULL &&
102 !user_directory_user_has_connections(dir, dir->head, &retry_secs)) 104 !user_directory_user_has_connections(dir, dir->head, &expire_timestamp)) {
103 user_free(dir, dir->head); 105 user_free(dir, dir->head);
104 if (dir->to_expire != NULL) 106 expire_timestamp = 0;
105 timeout_remove(&dir->to_expire); 107 }
106 if (retry_secs > 0) { 108 i_assert(expire_timestamp > ioloop_time || expire_timestamp == 0);
107 dir->to_expire = timeout_add(retry_secs * 1000, 109
108 user_directory_drop_expired, dir); 110 if (expire_timestamp != dir->to_expire_timestamp) {
111 if (dir->to_expire != NULL)
112 timeout_remove(&dir->to_expire);
113 if (expire_timestamp != 0) {
114 struct timeval tv = { .tv_sec = expire_timestamp };
115 dir->to_expire_timestamp = tv.tv_sec;
116 dir->to_expire = timeout_add_absolute(&tv,
117 user_directory_drop_expired, dir);
118 }
109 } 119 }
110 } 120 }
111 121
112 unsigned int user_directory_count(struct user_directory *dir) 122 unsigned int user_directory_count(struct user_directory *dir)
113 { 123 {
116 126
117 struct user *user_directory_lookup(struct user_directory *dir, 127 struct user *user_directory_lookup(struct user_directory *dir,
118 unsigned int username_hash) 128 unsigned int username_hash)
119 { 129 {
120 struct user *user; 130 struct user *user;
121 unsigned int retry_secs; 131 time_t expire_timestamp;
122 132
123 user_directory_drop_expired(dir); 133 user_directory_drop_expired(dir);
124 user = hash_table_lookup(dir->hash, POINTER_CAST(username_hash)); 134 user = hash_table_lookup(dir->hash, POINTER_CAST(username_hash));
125 if (user != NULL && !user_directory_user_has_connections(dir, user, &retry_secs)) { 135 if (user != NULL && !user_directory_user_has_connections(dir, user, &expire_timestamp)) {
126 user_free(dir, user); 136 user_free(dir, user);
127 user = NULL; 137 user = NULL;
128 } 138 }
129 return user; 139 return user;
130 } 140 }
206 user); 216 user);
207 } 217 }
208 } 218 }
209 219
210 if (dir->to_expire == NULL) { 220 if (dir->to_expire == NULL) {
211 dir->to_expire = timeout_add(dir->timeout_secs * 1000, 221 struct timeval tv = { .tv_sec = ioloop_time + dir->timeout_secs };
212 user_directory_drop_expired, dir); 222 dir->to_expire_timestamp = tv.tv_sec;
223 dir->to_expire = timeout_add_absolute(&tv, user_directory_drop_expired, dir);
213 } 224 }
214 dir->prev_insert_pos = user; 225 dir->prev_insert_pos = user;
215 hash_table_insert(dir->hash, POINTER_CAST(user->username_hash), user); 226 hash_table_insert(dir->hash, POINTER_CAST(user->username_hash), user);
216 return user; 227 return user;
217 } 228 }