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;