From d58f56347a16947757a0112715b13561f49fb539 Mon Sep 17 00:00:00 2001 From: Thomas Sader Date: Wed, 5 Jun 2024 19:30:11 +0200 Subject: [PATCH] Reintroduce user lookup cache Found by: mortmann Patch by: thommey Fixes: #1599 --- src/chan.h | 3 ++- src/chanprog.c | 16 +++++++++++----- src/mod/irc.mod/chan.c | 6 +++++- src/userrec.c | 16 +++++++++++++--- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/chan.h b/src/chan.h index d5f11257d..31b639834 100644 --- a/src/chan.h +++ b/src/chan.h @@ -50,7 +50,8 @@ typedef struct memstruct { time_t split; /* in case they were just netsplit */ time_t last; /* for measuring idle time */ time_t delay; /* for delayed autoop */ - int tried_getuser; // TODO: use it to invalidate user cache + struct userrec *user; /* cached user lookup */ + int tried_getuser; /* negative user lookup cache */ struct memstruct *next; } memberlist; diff --git a/src/chanprog.c b/src/chanprog.c index 37e03d61a..f589593fb 100644 --- a/src/chanprog.c +++ b/src/chanprog.c @@ -118,8 +118,11 @@ struct chanset_t *findchan_by_dname(const char *name) /* Clear the user pointers in the chanlists. * - * Necessary when a hostmask is added/removed, a user is added or a new - * userfile is loaded. + * Necessary when: + * - a hostmask is added/removed + * - an account is added/removed + * - a user is added + * - new userfile is loaded */ void clear_chanlist(void) { @@ -128,14 +131,16 @@ void clear_chanlist(void) for (chan = chanset; chan; chan = chan->next) for (m = chan->channel.member; m && m->nick[0]; m = m->next) { + m->user = NULL; m->tried_getuser = 0; } } /* Clear the user pointer of a specific nick in the chanlists. - - * Necessary when a hostmask is added/removed, a nick changes, etc. - * Does not completely invalidate the channel cache like clear_chanlist(). + * + * Necessary when: + * - their hostmask changed (chghost) + * - their account changed */ void clear_chanlist_member(const char *nick) { @@ -145,6 +150,7 @@ void clear_chanlist_member(const char *nick) for (chan = chanset; chan; chan = chan->next) for (m = chan->channel.member; m && m->nick[0]; m = m->next) if (!rfc_casecmp(m->nick, nick)) { + m->user = NULL; m->tried_getuser = 0; break; } diff --git a/src/mod/irc.mod/chan.c b/src/mod/irc.mod/chan.c index 1d0082547..f0cb827d7 100644 --- a/src/mod/irc.mod/chan.c +++ b/src/mod/irc.mod/chan.c @@ -116,6 +116,8 @@ static void setaccount(char *nick, char *account) } } } + /* Username for nick could be different after account change, invalidate cache */ + clear_chanlist_member(nick); } /* Returns the current channel mode. @@ -1220,7 +1222,7 @@ static int got354(char *from, char *msg) * :geo!awesome@eggdrop.com CHGHOST tehgeo foo.io * changes user hostmask to tehgeo@foo.io */ -static int gotchghost(char *from, char *msg){ +static int gotchghost(char *from, char *msg) { struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; struct userrec *u; struct chanset_t *chan; @@ -1247,6 +1249,8 @@ static int gotchghost(char *from, char *msg){ check_this_member(chan, m->nick, &fr); } } + /* Username for nick could be different after host change, invalidate cache */ + clear_chanlist_member(nick); return 0; } diff --git a/src/userrec.c b/src/userrec.c index 61af179d5..084dbcd64 100644 --- a/src/userrec.c +++ b/src/userrec.c @@ -224,24 +224,34 @@ struct userrec *get_user_by_handle(struct userrec *bu, char *handle) struct userrec *get_user_from_member(memberlist *m) { - struct userrec *ret; + struct userrec *ret = NULL; + + /* Check positive/negative cache first */ + if (m->user || m->tried_getuser) { + return m->user; + } /* Check if there is a user with a matching account if one is provided */ if (m->account[0] != '*') { ret = get_user_by_account(m->account); if (ret) { - return ret; + goto getuser_done; } } + /* Check if there is a user with a matching hostmask if one is provided */ if ((m->userhost[0] != '\0') && (m->nick[0] != '\0')) { char s[NICKMAX+UHOSTLEN+1]; sprintf(s, "%s!%s", m->nick, m->userhost); ret = get_user_by_host(s); if (ret) { - return ret; + goto getuser_done; } } + +getuser_done: + m->user = ret; + m->tried_getuser = 1; return NULL; }