AmendHub

Download:

jcs

/

wallops

/

amendments

/

137

irc: Buffer nicks on initial join, then parse all at once

This allows us to do a single big malloc of nicks with some headroom
rather than getting nicks in chunks and having to realloc for each
batch.

jcs made amendment 137 about 1 year ago
--- irc.c Thu Sep 26 14:31:20 2024 +++ irc.c Fri Oct 4 16:01:48 2024 @@ -37,7 +37,8 @@ struct irc_channel * irc_create_channel(struct irc_con void irc_quit_with_message(struct irc_connection *conn, char *str); void irc_dealloc_channel(struct irc_channel *channel); void irc_set_active_channel(struct irc_connection *conn, char *channame); -void irc_parse_names(struct irc_channel *channel, char *line); +void irc_buffer_names(struct irc_channel *channel, char *line); +void irc_parse_buffered_names(struct irc_channel *channel); void irc_add_nick_to_channel(struct irc_channel *channel, char *nick, short flags, short count_hint); void irc_remove_nick_from_channel(struct irc_channel *channel, char *nick); @@ -979,12 +980,12 @@ irc_process_server(struct irc_connection *conn) case 353: /* NAMES output */ if ((channel = irc_find_channel(conn, msg.arg[2]))) - irc_parse_names(channel, msg.msg); + irc_buffer_names(channel, msg.msg); return true; case 366: /* end of NAMES output */ if ((channel = irc_find_channel(conn, msg.arg[1]))) { - channel->parsing_nicks = false; + irc_parse_buffered_names(channel); chatter_sync_nick_list(channel->chatter, channel); } return true; @@ -1491,30 +1492,53 @@ irc_dealloc_channel(struct irc_channel *channel) } void -irc_parse_names(struct irc_channel *channel, char *line) +irc_buffer_names(struct irc_channel *channel, char *line) { + size_t len, s; + + len = strlen(line); + + if (channel->nicks_buf_len + len >= channel->nicks_buf_size) { + s = (IRC_MAX_MSG_SIZE * 5) + 1; + channel->nicks_buf = xrealloc(channel->nicks_buf, + channel->nicks_buf_size + s); + if (channel->nicks_buf == NULL) + panic("Out of memory allocating %ld+%ld bytes for more nicks", + channel->nicks_buf_size, s); + channel->nicks_buf_size += s; + } + + if (channel->nicks_buf_len) { + channel->nicks_buf[channel->nicks_buf_len] = ' '; + channel->nicks_buf_len++; + } + + memcpy(channel->nicks_buf + channel->nicks_buf_len, line, len); + channel->nicks_buf_len += len; + channel->nicks_buf[channel->nicks_buf_len] = '\0'; +} + +void +irc_parse_buffered_names(struct irc_channel *channel) +{ char *nick, *tline; short flags, count; + long start = Ticks; - if (!channel->parsing_nicks) { - /* new names output, clear previous */ - if (channel->nicks_size) { - memset(&channel->nicks, 0, - sizeof(struct irc_channel_nick) * channel->nicks_size); - } - - channel->nnicks = 0; - channel->parsing_nicks = true; - } + if (channel->nicks_size) + memset(&channel->nicks, 0, + sizeof(struct irc_channel_nick) * channel->nicks_size); + channel->nnicks = 0; + /* get a count of nicks to pass as a hint to malloc */ count = 1; - for (tline = line; *tline != '\0'; tline++) + for (tline = channel->nicks_buf; *tline != '\0'; tline++) if (*tline == ' ') count++; - for (;;) { - nick = strsep(&line, " "); + for (tline = channel->nicks_buf; tline != NULL; ) { + nick = strsep(&tline, " "); if (nick[0] == '@') { flags = IRC_NICK_FLAG_OP; @@ -1529,10 +1553,11 @@ irc_parse_names(struct irc_channel *channel, char *lin flags = 0; irc_add_nick_to_channel(channel, nick, flags, count); - - if (line == NULL) - break; } + + xfree(&channel->nicks_buf); + channel->nicks_buf_size = 0; + channel->nicks_buf_len = 0; } void @@ -1540,17 +1565,17 @@ irc_add_nick_to_channel(struct irc_channel *channel, c short flags, short count_hint) { struct irc_channel_nick *anick, *cnick, *pnick; + size_t new_size; short aidx, cidx, ret; if (channel->nnicks >= channel->nicks_size) { - /* allocate a chunk at a time so we don't do this every iteration */ - if (count_hint) - channel->nicks_size += count_hint; - else - channel->nicks_size += 5; + new_size = channel->nicks_size + count_hint; + /* 15% buffer */ + new_size += ((new_size * 100) / 666); + + channel->nicks_size = new_size; channel->nicks = xreallocarray(channel->nicks, - sizeof(struct irc_channel_nick), - channel->nicks_size); + sizeof(struct irc_channel_nick), channel->nicks_size); if (channel->nicks == NULL) panic("Out of memory for %ld nicks (%ld bytes)", channel->nnicks, @@ -1624,7 +1649,7 @@ irc_add_nick_to_channel(struct irc_channel *channel, c } } - if (!channel->parsing_nicks) + if (!channel->nicks_buf_size) chatter_insert_to_nick_list(channel->chatter, channel, anick, cidx); } --- irc.h Fri Sep 20 20:07:53 2024 +++ irc.h Thu Sep 26 16:14:28 2024 @@ -58,7 +58,9 @@ struct irc_channel { struct chatter *chatter; struct irc_connection *connection; struct irc_channel_nick *nicks; - bool parsing_nicks; + char *nicks_buf; + size_t nicks_buf_len; + size_t nicks_buf_size; size_t nnicks; size_t nicks_size; short first_nick;