mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-23 00:28:26 -05:00
PSYNC2: fix master cleanup when caching it.
The master client cleanup was incomplete: resetClient() was missing and the output buffer of the client was not reset, so pending commands related to the previous connection could be still sent. The first problem caused the client argument vector to be, at times, half populated, so that when the correct replication stream arrived the protcol got mixed to the arugments creating invalid commands that nobody called. Thanks to @yangsiran for also investigating this problem, after already providing important design / implementation hints for the original PSYNC2 issues (see referenced Github issue). Note that this commit adds a new function to the list library of Redis in order to be able to reset a list without destroying it. Related to issue #3899.
This commit is contained in:
parent
c861e1e1ee
commit
469d6e2b37
16
src/adlist.c
16
src/adlist.c
@ -52,10 +52,8 @@ list *listCreate(void)
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free the whole list.
|
/* Remove all the elements from the list without destroying the list itself. */
|
||||||
*
|
void listEmpty(list *list)
|
||||||
* This function can't fail. */
|
|
||||||
void listRelease(list *list)
|
|
||||||
{
|
{
|
||||||
unsigned long len;
|
unsigned long len;
|
||||||
listNode *current, *next;
|
listNode *current, *next;
|
||||||
@ -68,6 +66,16 @@ void listRelease(list *list)
|
|||||||
zfree(current);
|
zfree(current);
|
||||||
current = next;
|
current = next;
|
||||||
}
|
}
|
||||||
|
list->head = list->tail = NULL;
|
||||||
|
list->len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free the whole list.
|
||||||
|
*
|
||||||
|
* This function can't fail. */
|
||||||
|
void listRelease(list *list)
|
||||||
|
{
|
||||||
|
listEmpty(list);
|
||||||
zfree(list);
|
zfree(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,6 +72,7 @@ typedef struct list {
|
|||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
list *listCreate(void);
|
list *listCreate(void);
|
||||||
void listRelease(list *list);
|
void listRelease(list *list);
|
||||||
|
void listEmpty(list *list);
|
||||||
list *listAddNodeHead(list *list, void *value);
|
list *listAddNodeHead(list *list, void *value);
|
||||||
list *listAddNodeTail(list *list, void *value);
|
list *listAddNodeTail(list *list, void *value);
|
||||||
list *listInsertNode(list *list, listNode *old_node, void *value, int after);
|
list *listInsertNode(list *list, listNode *old_node, void *value, int after);
|
||||||
|
@ -2119,13 +2119,17 @@ void replicationCacheMaster(client *c) {
|
|||||||
/* Unlink the client from the server structures. */
|
/* Unlink the client from the server structures. */
|
||||||
unlinkClient(c);
|
unlinkClient(c);
|
||||||
|
|
||||||
/* Fix the master specific fields: we want to discard to non processed
|
/* Reset the master client so that's ready to accept new commands:
|
||||||
* query buffers and non processed offsets, including pending
|
* we want to discard te non processed query buffers and non processed
|
||||||
* transactions. */
|
* offsets, including pending transactions, already populated arguments,
|
||||||
|
* pending outputs to the master. */
|
||||||
sdsclear(server.master->querybuf);
|
sdsclear(server.master->querybuf);
|
||||||
sdsclear(server.master->pending_querybuf);
|
sdsclear(server.master->pending_querybuf);
|
||||||
server.master->read_reploff = server.master->reploff;
|
server.master->read_reploff = server.master->reploff;
|
||||||
if (c->flags & CLIENT_MULTI) discardTransaction(c);
|
if (c->flags & CLIENT_MULTI) discardTransaction(c);
|
||||||
|
listEmpty(c->reply);
|
||||||
|
c->bufpos = 0;
|
||||||
|
resetClient(c);
|
||||||
|
|
||||||
/* Save the master. Server.master will be set to null later by
|
/* Save the master. Server.master will be set to null later by
|
||||||
* replicationHandleMasterDisconnection(). */
|
* replicationHandleMasterDisconnection(). */
|
||||||
|
Loading…
Reference in New Issue
Block a user