add linkClient(): adds the client and caches the list node.

We have this operation in two places: when caching the master and
when linking a new client after the client creation. By having an API
for this we avoid incurring in errors when modifying one of the two
places forgetting the other. The function is also a good place where to
document why we cache the linked list node.

Related to #4497 and #4210.
This commit is contained in:
antirez 2017-12-05 15:59:56 +01:00 committed by Maxime Bedard
parent 239b08574c
commit 1908aba73d
3 changed files with 14 additions and 8 deletions

View File

@ -67,6 +67,16 @@ int listMatchObjects(void *a, void *b) {
return equalStringObjects(a,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 *createClient(int fd) {
client *c = zmalloc(sizeof(client)); client *c = zmalloc(sizeof(client));
@ -133,14 +143,10 @@ client *createClient(int fd) {
c->pubsub_channels = dictCreate(&objectKeyPointerValueDictType,NULL); c->pubsub_channels = dictCreate(&objectKeyPointerValueDictType,NULL);
c->pubsub_patterns = listCreate(); c->pubsub_patterns = listCreate();
c->peerid = NULL; c->peerid = NULL;
c->client_list_node = NULL;
listSetFreeMethod(c->pubsub_patterns,decrRefCountVoid); listSetFreeMethod(c->pubsub_patterns,decrRefCountVoid);
listSetMatchMethod(c->pubsub_patterns,listMatchObjects); listSetMatchMethod(c->pubsub_patterns,listMatchObjects);
if (fd != -1) { if (fd != -1) linkClient(c);
listAddNodeTail(server.clients,c);
c->client_list_node = listLast(server.clients);
} else {
c->client_list_node = NULL;
}
initClientMultiState(c); initClientMultiState(c);
return c; return c;
} }

View File

@ -2214,8 +2214,7 @@ void replicationResurrectCachedMaster(int newfd) {
server.repl_down_since = 0; server.repl_down_since = 0;
/* Re-add to the list of clients. */ /* Re-add to the list of clients. */
listAddNodeTail(server.clients,server.master); linkClient(server.master);
server.master->client_list_node = listLast(server.clients);
if (aeCreateFileEvent(server.el, newfd, AE_READABLE, if (aeCreateFileEvent(server.el, newfd, AE_READABLE,
readQueryFromClient, server.master)) { readQueryFromClient, server.master)) {
serverLog(LL_WARNING,"Error resurrecting the cached master, impossible to add the readable handler: %s", strerror(errno)); serverLog(LL_WARNING,"Error resurrecting the cached master, impossible to add the readable handler: %s", strerror(errno));

View File

@ -1394,6 +1394,7 @@ int handleClientsWithPendingWrites(void);
int clientHasPendingReplies(client *c); int clientHasPendingReplies(client *c);
void unlinkClient(client *c); void unlinkClient(client *c);
int writeToClient(int fd, client *c, int handler_installed); int writeToClient(int fd, client *c, int handler_installed);
void linkClient(client *c);
#ifdef __GNUC__ #ifdef __GNUC__
void addReplyErrorFormat(client *c, const char *fmt, ...) void addReplyErrorFormat(client *c, const char *fmt, ...)