diff --git a/src/networking.c b/src/networking.c index 2cab29d40c681e2fd5c8442a3d2fd3fa2a3b5381..82c763c95fbaa62f4c07140943e3b46213a1e3db 100644 --- a/src/networking.c +++ b/src/networking.c @@ -67,6 +67,16 @@ int listMatchObjects(void *a, void *b) { return equalStringObjects(a,b); } +/* This function links the client to the global linked list of clients. + * unlinkClient() does the opposite, among other things. */ +void linkClient(client *c) { + listAddNodeTail(server.clients,c); + /* Note that we remember the linked list node where the client is stored, + * this way removing the client in unlinkClient() will not require + * a linear scan, but just a constant time operation. */ + c->client_list_node = listLast(server.clients); +} + client *createClient(int fd) { client *c = zmalloc(sizeof(client)); @@ -133,9 +143,10 @@ client *createClient(int fd) { c->pubsub_channels = dictCreate(&objectKeyPointerValueDictType,NULL); c->pubsub_patterns = listCreate(); c->peerid = NULL; + c->client_list_node = NULL; listSetFreeMethod(c->pubsub_patterns,decrRefCountVoid); listSetMatchMethod(c->pubsub_patterns,listMatchObjects); - if (fd != -1) listAddNodeTail(server.clients,c); + if (fd != -1) linkClient(c); initClientMultiState(c); return c; } @@ -752,9 +763,10 @@ void unlinkClient(client *c) { * fd is already set to -1. */ if (c->fd != -1) { /* Remove from the list of active clients. */ - ln = listSearchKey(server.clients,c); - serverAssert(ln != NULL); - listDelNode(server.clients,ln); + if (c->client_list_node) { + listDelNode(server.clients,c->client_list_node); + c->client_list_node = NULL; + } /* Unregister async I/O handlers and close the socket. */ aeDeleteFileEvent(server.el,c->fd,AE_READABLE); diff --git a/src/replication.c b/src/replication.c index fa00470410903598ea94ff4905c4b2051534233b..2c0c47a27e7bb1bdf76af0f06497ed3f4d77239b 100644 --- a/src/replication.c +++ b/src/replication.c @@ -2226,7 +2226,7 @@ void replicationResurrectCachedMaster(int newfd) { server.repl_down_since = 0; /* Re-add to the list of clients. */ - listAddNodeTail(server.clients,server.master); + linkClient(server.master); if (aeCreateFileEvent(server.el, newfd, AE_READABLE, readQueryFromClient, server.master)) { serverLog(LL_WARNING,"Error resurrecting the cached master, impossible to add the readable handler: %s", strerror(errno)); diff --git a/src/server.h b/src/server.h index 5abb8bdca4272200be48375a2097195231f2ff19..7b0d22eaf6a3241b31fd60a4a38f5d9429e4f91d 100644 --- a/src/server.h +++ b/src/server.h @@ -723,6 +723,7 @@ typedef struct client { dict *pubsub_channels; /* channels a client is interested in (SUBSCRIBE) */ list *pubsub_patterns; /* patterns a client is interested in (SUBSCRIBE) */ sds peerid; /* Cached peer ID. */ + listNode *client_list_node; /* list node in client list */ /* Response buffer */ int bufpos; @@ -1393,6 +1394,7 @@ int handleClientsWithPendingWrites(void); int clientHasPendingReplies(client *c); void unlinkClient(client *c); int writeToClient(int fd, client *c, int handler_installed); +void linkClient(client *c); #ifdef __GNUC__ void addReplyErrorFormat(client *c, const char *fmt, ...)