Log message:
Create a linked list of connections that have queued data. This allows
flush_connections to scan only the connections that have queued data,
rather than going through every single connection on the server. This
will improve efficiency, but I doubt it'll have a significant impact on
CPU usage.
Testing:
Compiles and runs with no apparent errors. It needs to be brute-forced
to make sure there are no assertion failures.
Notes:
If you ever call MsgQClear(), you MUST call client_drop_sendq() as well!
(Perhaps this should be changed to have client_drop_sendq() call
MsgQClear() itself?)
git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@339
c9e4aea6-c8fd-4c43-8297-
357d70d61c8c
+2000-12-15 Kevin L. Mitchell <klmitch@mit.edu>
+
+ * ircd/send.c: implement the efficiency of flush_connections by
+ creating a linked list of struct Connection's with queued data;
+ also get rid of flush_sendq_except and make sure to yank
+ connections out of the list when their sendQs become empty (notice
+ the assertion in flush_connections!)
+
+ * ircd/s_bsd.c (close_connection): must yank the Connection out of
+ the sendq list
+
+ * ircd/list.c (dealloc_connection): must yank the Connection out
+ of the sendq list
+
+ * ircd/dbuf.c (dbuf_put): call flush_connections instead of the
+ deprecated flush_sendq_except
+
+ * ircd/client.c: define a couple new helper functions for sendq
+ threading--this will make the flush_connections function in send.c
+ considerably more efficient by creating a linked list of
+ Connections that have queued data to send
+
+ * include/send.h: remove flush_sendq_except, as it's not used
+ anymore
+
+ * include/client.h: declare a couple new helper functions for the
+ sendq threading system
+
2000-12-14 Kevin L. Mitchell <klmitch@mit.edu>
* ircd/m_ison.c (m_ison): Apply Diane Bruce's patch to make ISON
extern const char* get_client_name(const struct Client* sptr, int showip);
extern int client_get_ping(const struct Client* local_client);
-
+extern void client_drop_sendq(struct Connection* con);
+extern void client_add_sendq(struct Connection* con,
+ struct Connection** con_p);
#endif /* INCLUDED_client_h */
* Prototypes
*/
extern void send_buffer(struct Client* to, struct MsgBuf* buf, int prio);
-extern void flush_sendq_except(void);
extern void flush_connections(struct Client* cptr);
extern void send_queued(struct Client *to);
Debug((DEBUG_DEBUG, "Client %s Ping %d", cli_name(acptr), ping));
return ping;
}
+
+/*
+ * client_drop_sendq
+ * removes the client's connection from the list of connections with
+ * queued data
+ */
+void client_drop_sendq(struct Connection* con)
+{
+ if (con_prev_p(con)) { /* on the queued data list... */
+ if (con_next(con))
+ con_prev_p(con_next(con)) = con_prev_p(con);
+ *(con_prev_p(con)) = con_next(con);
+
+ con_next(con) = 0;
+ con_prev_p(con) = 0;
+ }
+}
+
+/*
+ * client_add_sendq
+ * adds the client's connection to the list of connections with
+ * queued data
+ */
+void client_add_sendq(struct Connection* con, struct Connection** con_p)
+{
+ if (!con_prev_p(con)) { /* not on the queued data list yet... */
+ con_prev_p(con) = con_p;
+ con_next(con) = *con_p;
+
+ if (*con_p)
+ con_prev_p(*con_p) = &(con_next(con));
+ *con_p = con;
+ }
+}
* attempt to recover from buffer starvation before
* bailing this may help servers running out of memory
*/
- flush_sendq_except();
+ flush_connections(0);
if (0 == (db = dbuf_alloc()))
#endif
return dbuf_malloc_error(dyn);
if (-1 < con_fd(con))
close(con_fd(con));
MsgQClear(&(con_sendQ(con)));
+ client_drop_sendq(con);
DBufClear(&(con_recvQ(con)));
if (con_listener(con))
release_listener(con_listener(con));
cli_flags(cptr) |= FLAGS_DEADSOCKET;
MsgQClear(&(cli_sendQ(cptr)));
+ client_drop_sendq(cli_connect(cptr));
DBufClear(&(cli_recvQ(cptr)));
memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr)));
set_snomask(cptr, 0, SNO_SET);
static int sentalong_marker;
struct SLink *opsarray[32]; /* don't use highest bit unless you change
atoi to strtoul in sendto_op_mask() */
+static struct Connection *send_queues = 0;
+
/*
* dead_link
*
*/
DBufClear(&(cli_recvQ(to)));
MsgQClear(&(cli_sendQ(to)));
+ client_drop_sendq(cli_connect(to));
/*
* Keep a copy of the last comment, for later use...
send_queued(cptr);
}
else {
- int i;
- for (i = HighestFd; i >= 0; i--) {
- if ((cptr = LocalClientArray[i]))
- send_queued(cptr);
+ struct Connection* con;
+ for (con = send_queues; con; con = con_next(con)) {
+ assert(0 > MsgQLength(&(con_sendQ(con))));
+ send_queued(con_client(con));
}
}
}
-/*
- * flush_sendq_except - run through local client array and flush
- * the sendq for each client, if the address of the client sendq
- * is the same as the one specified, it is skipped. This is used
- * by dbuf_put to try to get some more memory before bailing and
- * causing the client to be disconnected.
- */
-void flush_sendq_except(void)
-{
- int i;
- struct Client* cptr;
- for (i = HighestFd; i >= 0; i--) {
- if ( (cptr = LocalClientArray[i]))
- send_queued(cptr);
- }
-}
-
/*
* send_queued
*
msgq_delete(&(cli_sendQ(to)), len);
cli_lastsq(to) = MsgQLength(&(cli_sendQ(to))) / 1024;
if (IsBlocked(to))
- break;
+ return;
}
else {
if (IsDead(to)) {
sprintf(tmp,"Write error: %s",(strerror(cli_error(to))) ? (strerror(cli_error(to))) : "Unknown error" );
dead_link(to, tmp);
}
- break;
+ return;
}
}
+
+ /* Ok, sendq is now empty... */
+ client_drop_sendq(cli_connect(to));
}
void send_buffer(struct Client* to, struct MsgBuf* buf, int prio)
Debug((DEBUG_SEND, "Sending [%p] to %s", buf, cli_name(to)));
msgq_add(&(cli_sendQ(to)), buf, prio);
+ client_add_sendq(cli_connect(to), &send_queues);
/*
* Update statistics. The following is slightly incorrect