struct user *user =
user_directory_lookup(ctx->dir->users, ctx->username_hash);
- if (user != NULL)
+ if (user == NULL) {
+ dir_debug("User %u freed while flushing, result=%d",
+ ctx->username_hash, result);
+ } else if (user->kill_state != USER_KILL_STATE_FLUSHING) {
+ dir_debug("User %u move state changed while flushing, result=%d",
+ ctx->username_hash, result);
+ } else {
+ dir_debug("Flushing user %u finished, result=%d",
+ ctx->username_hash, result);
director_user_kill_finish_delayed(ctx->dir, user,
result == 1);
+ }
if (result == 0) {
struct istream *is = iostream_temp_finish(&ctx->reply, (size_t)-1);
char *data;
const char *const args[] = {"FLUSH",
t_strdup_printf("%u", user->username_hash), NULL};
+ user->kill_state = USER_KILL_STATE_FLUSHING;
+
if ((program_client_create(ctx->socket_path, args, &set, FALSE,
&ctx->pclient, &error)) != 0) {
i_error("%s: Failed to flush user hash %u in host %s: %s",
static void
director_finish_user_kill(struct director *dir, struct user *user, bool self)
{
+ i_assert(user->kill_state != USER_KILL_STATE_FLUSHING);
i_assert(user->kill_state != USER_KILL_STATE_DELAY);
if (dir->right == NULL) {
static void director_user_move_timeout(struct user *user)
{
+ i_assert(user->kill_state != USER_KILL_STATE_FLUSHING);
i_assert(user->kill_state != USER_KILL_STATE_DELAY);
if (log_throttle_accept(user_move_throttle)) {
director_finish_user_kill(dir, user, TRUE);
break;
case USER_KILL_STATE_NONE:
+ case USER_KILL_STATE_FLUSHING:
case USER_KILL_STATE_DELAY:
case USER_KILL_STATE_KILLING_NOTIFY_RECEIVED:
break;
/* We're done killing, but waiting for USER-KILLED-EVERYWHERE
notification until this state gets reset. */
USER_KILL_STATE_KILLED_WAITING_FOR_EVERYONE,
+ /* Waiting for the flush socket to finish. */
+ USER_KILL_STATE_FLUSHING,
/* Wait for a while for the user connections to actually die. Note that
only at this stage we can be sure that all the directors know about
the user move (although it could be earlier if we added a new