degesch: partially implement rehashing

This commit is contained in:
Přemysl Eric Janouch 2015-06-23 22:10:16 +02:00
parent 63a65f9f7c
commit e39bb976cb
1 changed files with 74 additions and 3 deletions

View File

@ -1059,6 +1059,8 @@ struct server
// TODO: an output queue to prevent excess floods (this will be needed // TODO: an output queue to prevent excess floods (this will be needed
// especially for away status polling) // especially for away status polling)
bool rehashing; ///< Rehashing IRC identifiers
struct str_map irc_users; ///< IRC user data struct str_map irc_users; ///< IRC user data
struct str_map irc_channels; ///< IRC channel data struct str_map irc_channels; ///< IRC channel data
struct str_map irc_buffer_map; ///< Maps IRC identifiers to buffers struct str_map irc_buffer_map; ///< Maps IRC identifiers to buffers
@ -2791,6 +2793,7 @@ irc_user_on_destroy (void *object, void *user_data)
{ {
struct user *user = object; struct user *user = object;
struct server *s = user_data; struct server *s = user_data;
if (!s->rehashing)
str_map_set (&s->irc_users, user->nickname, NULL); str_map_set (&s->irc_users, user->nickname, NULL);
} }
@ -2877,6 +2880,7 @@ irc_channel_on_destroy (void *object, void *user_data)
struct server *s = user_data; struct server *s = user_data;
LIST_FOR_EACH (struct channel_user, iter, channel->users) LIST_FOR_EACH (struct channel_user, iter, channel->users)
irc_channel_unlink_user (channel, iter); irc_channel_unlink_user (channel, iter);
if (!s->rehashing)
str_map_set (&s->irc_channels, channel->name, NULL); str_map_set (&s->irc_channels, channel->name, NULL);
} }
@ -2924,7 +2928,74 @@ irc_left_channel (struct channel *channel)
static void static void
irc_rehash_and_fix_conflicts (struct server *s) irc_rehash_and_fix_conflicts (struct server *s)
{ {
// TODO // Save the old maps and initialize new ones
struct str_map old_users = s->irc_users;
struct str_map old_channels = s->irc_channels;
struct str_map old_buffer_map = s->irc_buffer_map;
str_map_init (&s->irc_users);
str_map_init (&s->irc_channels);
str_map_init (&s->irc_buffer_map);
s->irc_users .free = old_users .free;
s->irc_channels .free = old_channels .free;
s->irc_buffer_map.free = old_buffer_map.free;
s->irc_users .key_xfrm = s->irc_strxfrm;
s->irc_channels .key_xfrm = s->irc_strxfrm;
s->irc_buffer_map.key_xfrm = s->irc_strxfrm;
// Prevent channels and users from unsetting themselves
// from server maps upon removing the last reference to them
s->rehashing = true;
// TODO: "Removed similarly named buffer %s because of casemapping conflict"
// XXX: to be perfectly sure, we should also check
// whether any users collide with channels and vice versa
struct str_map_iter iter;
str_map_iter_init (&iter, &old_users);
struct user *user;
while ((user = str_map_iter_next (&iter)))
{
// FIXME: don't remove ourselves!
if (str_map_find (&s->irc_users, user->nickname))
{
// TODO: move or merge any PM buffer and remove
// the user from channels and altogether
}
else
{
str_map_set (&s->irc_users, user->nickname, user);
str_map_set (&s->irc_buffer_map, user->nickname,
str_map_find (&old_buffer_map, user->nickname));
}
}
str_map_iter_init (&iter, &old_channels);
struct channel *channel;
while ((channel = str_map_iter_next (&iter)))
{
if (str_map_find (&s->irc_channels, channel->name))
{
// TODO: remove all users from the buffer
// and probably issue NAMES if registered and on the channel,
// and of course remove the colliding channel
}
else
{
str_map_set (&s->irc_channels, channel->name, user);
str_map_set (&s->irc_buffer_map, user->nickname,
str_map_find (&old_buffer_map, user->nickname));
}
}
// Hopefully we've either moved or destroyed all the old content
s->rehashing = false;
str_map_free (&old_users);
str_map_free (&old_channels);
str_map_free (&old_buffer_map);
} }
static void static void