Threaded IO: parsing WIP 2: refactoring to parse from thread.

This commit is contained in:
antirez 2019-04-26 19:29:50 +02:00
parent 647a66ebba
commit 6ab6a97fe6
2 changed files with 61 additions and 29 deletions

View File

@ -1558,13 +1558,47 @@ int processMultibulkBuffer(client *c) {
return C_ERR; return C_ERR;
} }
/* This function calls processCommand(), but also performs a few sub tasks
* that are useful in that context:
*
* 1. It sets the current client to the client 'c'.
* 2. In the case of master clients, the replication offset is updated.
* 3. The client is reset unless there are reasons to avoid doing it.
*
* The function returns C_ERR in case the client was freed as a side effect
* of processing the command, otherwise C_OK is returned. */
int processCommandAndResetClient(client *c) {
int deadclient = 0;
server.current_client = c;
if (processCommand(c) == C_OK) {
if (c->flags & CLIENT_MASTER && !(c->flags & CLIENT_MULTI)) {
/* Update the applied replication offset of our master. */
c->reploff = c->read_reploff - sdslen(c->querybuf) + c->qb_pos;
}
/* Don't reset the client structure for clients blocked in a
* module blocking command, so that the reply callback will
* still be able to access the client argv and argc field.
* The client will be reset in unblockClientFromModule(). */
if (!(c->flags & CLIENT_BLOCKED) ||
c->btype != BLOCKED_MODULE)
{
resetClient(c);
}
}
if (server.current_client == NULL) deadclient = 1;
server.current_client = NULL;
/* freeMemoryIfNeeded may flush slave output buffers. This may
* result into a slave, that may be the active client, to be
* freed. */
return deadclient ? C_ERR : C_OK;
}
/* This function is called every time, in the client structure 'c', there is /* This function is called every time, in the client structure 'c', there is
* more query buffer to process, because we read more data from the socket * more query buffer to process, because we read more data from the socket
* or because a client was blocked and later reactivated, so there could be * or because a client was blocked and later reactivated, so there could be
* pending query buffer, already representing a full command, to process. */ * pending query buffer, already representing a full command, to process. */
void processInputBuffer(client *c) { void processInputBuffer(client *c) {
int deadclient = 0;
/* Keep processing while there is something in the input buffer */ /* Keep processing while there is something in the input buffer */
while(c->qb_pos < sdslen(c->querybuf)) { while(c->qb_pos < sdslen(c->querybuf)) {
/* Return if clients are paused. */ /* Return if clients are paused. */
@ -1573,6 +1607,10 @@ void processInputBuffer(client *c) {
/* Immediately abort if the client is in the middle of something. */ /* Immediately abort if the client is in the middle of something. */
if (c->flags & CLIENT_BLOCKED) break; if (c->flags & CLIENT_BLOCKED) break;
/* Don't process more buffers from clients that have already pending
* commands to execute in c->argv. */
if (c->flags & CLIENT_PENDING_COMMAND) break;
/* Don't process input from the master while there is a busy script /* Don't process input from the master while there is a busy script
* condition on the slave. We want just to accumulate the replication * condition on the slave. We want just to accumulate the replication
* stream (instead of replying -BUSY like we do with other clients) and * stream (instead of replying -BUSY like we do with other clients) and
@ -1618,35 +1656,26 @@ void processInputBuffer(client *c) {
if (c->argc == 0) { if (c->argc == 0) {
resetClient(c); resetClient(c);
} else { } else {
/* Only reset the client when the command was executed. */ /* If we are in the context of an I/O thread, we can't really
server.current_client = c; * execute the command here. All we can do is to flag the client
if (processCommand(c) == C_OK) { * as one that needs to process the command. */
if (c->flags & CLIENT_MASTER && !(c->flags & CLIENT_MULTI)) { if (c->flags & CLIENT_PENDING_READ) {
/* Update the applied replication offset of our master. */ c->flags |= CLIENT_PENDING_COMMAND;
c->reploff = c->read_reploff - sdslen(c->querybuf) + c->qb_pos; break;
} }
/* Don't reset the client structure for clients blocked in a /* We are finally ready to execute the command. */
* module blocking command, so that the reply callback will if (processCommandAndResetClient(c) == C_ERR) {
* still be able to access the client argv and argc field. /* If the client is no longer valid, we avoid exiting this
* The client will be reset in unblockClientFromModule(). */ * loop and trimming the client buffer later. So we return
if (!(c->flags & CLIENT_BLOCKED) || * ASAP in that case. */
c->btype != BLOCKED_MODULE) return;
{
resetClient(c);
}
} }
if (server.current_client == NULL) deadclient = 1;
server.current_client = NULL;
/* freeMemoryIfNeeded may flush slave output buffers. This may
* result into a slave, that may be the active client, to be
* freed. */
if (deadclient) break;
} }
} }
/* Trim to pos */ /* Trim to pos */
if (!deadclient && c->qb_pos) { if (c->qb_pos) {
sdsrange(c->querybuf,c->qb_pos,-1); sdsrange(c->querybuf,c->qb_pos,-1);
c->qb_pos = 0; c->qb_pos = 0;
} }
@ -1737,9 +1766,7 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
sds ci = catClientInfoString(sdsempty(),c), bytes = sdsempty(); sds ci = catClientInfoString(sdsempty(),c), bytes = sdsempty();
bytes = sdscatrepr(bytes,c->querybuf,64); bytes = sdscatrepr(bytes,c->querybuf,64);
// FIXME: This may be called from an I/O thread and it is not safe to serverLog(LL_WARNING,"Closing client that reached max query buffer length: %s (qbuf initial bytes: %s)", ci, bytes);
// log from there for now.
// serverLog(LL_WARNING,"Closing client that reached max query buffer length: %s (qbuf initial bytes: %s)", ci, bytes);
sdsfree(ci); sdsfree(ci);
sdsfree(bytes); sdsfree(bytes);
freeClientAsync(c); freeClientAsync(c);
@ -2747,6 +2774,10 @@ int handleClientsWithPendingReadsUsingThreads(void) {
while((ln = listNext(&li))) { while((ln = listNext(&li))) {
client *c = listNodeValue(ln); client *c = listNodeValue(ln);
c->flags &= ~CLIENT_PENDING_READ; c->flags &= ~CLIENT_PENDING_READ;
if (c->flags & CLIENT_PENDING_COMMAND) {
c->flags &= ~ CLIENT_PENDING_COMMAND;
processCommandAndResetClient(c);
}
processInputBufferAndReplicate(c); processInputBufferAndReplicate(c);
} }
listEmpty(server.clients_pending_read); listEmpty(server.clients_pending_read);

View File

@ -288,6 +288,7 @@ typedef long long mstime_t; /* millisecond time type. */
#define CLIENT_PENDING_READ (1<<29) /* The client has pending reads and was put #define CLIENT_PENDING_READ (1<<29) /* The client has pending reads and was put
in the list of clients we can read in the list of clients we can read
from. */ from. */
#define CLIENT_PENDING_COMMAND (1<<30) /* */
/* Client block type (btype field in client structure) /* Client block type (btype field in client structure)
* if CLIENT_BLOCKED flag is set. */ * if CLIENT_BLOCKED flag is set. */