void sub_ev_handler(evutil_socket_t fd, short event, void *args) { sub_client *c = (sub_client *) args; if (event & EV_READ) { c->read_buf = sdsMakeRoomFor(c->read_buf, SUB_READ_BUF_LEN); size_t cur_len = sdslen(c->read_buf); int n = read(fd, c->read_buf + cur_len, SUB_READ_BUF_LEN); if (n == -1) { if (errno == EAGAIN || errno == EINTR) { /* temporary unavailable */ return; } else { srv_log(LOG_ERROR, "[fd %d] failed to read from sublisher: %s", fd, strerror(errno)); sub_cli_release(c); return; } } else if (n == 0) { srv_log(LOG_INFO, "[fd %d] sublisher detached", fd); sub_cli_release(c); return; } else { sdsIncrLen(c->read_buf, n); } process_sub_read_buf(c); } else if (event & EV_WRITE) { send_reply_to_subcli(c); } }
static void pub_ev_handler(evutil_socket_t fd, short event, void *args) { if (!(event & EV_READ)) { srv_log(LOG_WARN, "publisher [fd %d] invalid event: %d", event); return; } pub_client *c = (pub_client *) args; c->read_buf = sdsMakeRoomFor(c->read_buf, PUB_READ_BUF_LEN); size_t cur_len = sdslen(c->read_buf); int nread = read(fd, c->read_buf + cur_len, PUB_READ_BUF_LEN); if (nread == -1) { if (errno == EAGAIN || errno == EINTR) { /* temporary unavailable */ } else { srv_log(LOG_ERROR, "[fd %d] failed to read from publisher: %s", fd, strerror(errno)); pub_cli_release(c); } } else if (nread == 0) { srv_log(LOG_INFO, "[fd %d] publisher detached", fd); pub_cli_release(c); } else { /* chunk[n] = '\0'; srv_log(LOG_INFO, "[fd %d] publisher send: %s", fd, chunk); write(fd, "hello", 5); */ /* data process */ sdsIncrLen(c->read_buf, nread); process_pub_read_buf(c); /*process_publish(c, chunk, nread);*/ } }
void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) { client *c = (client*) privdata; int nread, readlen; size_t qblen; UNUSED(el); UNUSED(mask); readlen = PROTO_IOBUF_LEN; /* If this is a multi bulk request, and we are processing a bulk reply * that is large enough, try to maximize the probability that the query * buffer contains exactly the SDS string representing the object, even * at the risk of requiring more read(2) calls. This way the function * processMultiBulkBuffer() can avoid copying buffers to create the * Redis Object representing the argument. */ if (c->reqtype == PROTO_REQ_MULTIBULK && c->multibulklen && c->bulklen != -1 && c->bulklen >= PROTO_MBULK_BIG_ARG) { int remaining = (unsigned)(c->bulklen+2)-sdslen(c->querybuf); if (remaining < readlen) readlen = remaining; } qblen = sdslen(c->querybuf); if (c->querybuf_peak < qblen) c->querybuf_peak = qblen; c->querybuf = sdsMakeRoomFor(c->querybuf, readlen); nread = read(fd, c->querybuf+qblen, readlen); if (nread == -1) { if (errno == EAGAIN) { return; } else { Log(LL_VERBOSE, "Reading from client: %s",strerror(errno)); freeClient(c); return; } } else if (nread == 0) { Log(LL_VERBOSE, "Client closed connection"); freeClient(c); return; } sdsIncrLen(c->querybuf,nread); c->lastinteraction = server.unixtime; server.stat_net_input_bytes += nread; if (sdslen(c->querybuf) > server.client_max_querybuf_len) { sds ci = catClientInfoString(sdsempty(),c), bytes = sdsempty(); bytes = sdscatrepr(bytes,c->querybuf,64); Log(LL_WARNING,"Closing client that reached max query buffer length: %s (qbuf initial bytes: %s)", ci, bytes); sdsfree(ci); sdsfree(bytes); freeClient(c); return; } processInputBuffer(c); }
void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) { vuiClient *c = (vuiClient *) privdata; int nread, readlen; size_t qblen; /* If this is a multi bulk request, and we are processing a bulk reply * that is large enough, try to maximize the probability that the query * buffer contains exactly the SDS string representing the object, even * at the risk of requiring more read(2) calls. This way the function * processMultiBulkBuffer() can avoid copying buffers to create the * Redis Object representing the argument. */ if (c->prot.waiting) { readlen = c->prot.waiting; } else { readlen = 1024 * 2; } qblen = sdslen(c->querybuf); c->querybuf = sdsMakeRoomFor(c->querybuf, readlen); nread = read(fd, c->querybuf+qblen, readlen); if (nread == -1) { if (errno == EAGAIN) { nread = 0; } else { LogInfo("Reading from client: %s",strerror(errno)); freeClient(c); return; } } else if (nread == 0) { LogInfo("Client closed connection"); freeClient(c); return; } if (nread) { sdsIncrLen(c->querybuf,nread); } //TODO if (sdslen(c->querybuf) > 1024 * 1024) { LogWarn("Closing client that reached max query buffer length"); sdsclear(c->querybuf); freeClient(c); return; } processInputBuffer(c); }
TEST(sds, sds) { // struct sdshdr *sh; sds x = sdsnew("foo"), y; TEST_ASSERT_TRUE( sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0) sdsfree(x); x = sdsnewlen("foo",2); TEST_ASSERT_TRUE( sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0) x = sdscat(x,"bar"); TEST_ASSERT_TRUE( sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0); x = sdscpy(x,"a"); TEST_ASSERT_TRUE( sdslen(x) == 1 && memcmp(x,"a\0",2) == 0) x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk"); TEST_ASSERT_TRUE( sdslen(x) == 33 && memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0) sdsfree(x); x = sdscatprintf(sdsempty(),"%d",123); TEST_ASSERT_TRUE( sdslen(x) == 3 && memcmp(x,"123\0",4) ==0) sdsfree(x); x = sdsnew("xxciaoyyy"); sdstrim(x,"xy"); TEST_ASSERT_TRUE( sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0) y = sdsdup(x); sdsrange(y,1,1); TEST_ASSERT_TRUE( sdslen(y) == 1 && memcmp(y,"i\0",2) == 0) sdsfree(y); y = sdsdup(x); sdsrange(y,1,-1); TEST_ASSERT_TRUE( sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0) sdsfree(y); y = sdsdup(x); sdsrange(y,-2,-1); TEST_ASSERT_TRUE( sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0) sdsfree(y); y = sdsdup(x); sdsrange(y,2,1); TEST_ASSERT_TRUE( sdslen(y) == 0 && memcmp(y,"\0",1) == 0) sdsfree(y); y = sdsdup(x); sdsrange(y,1,100); TEST_ASSERT_TRUE( sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0) sdsfree(y); y = sdsdup(x); sdsrange(y,100,100); TEST_ASSERT_TRUE( sdslen(y) == 0 && memcmp(y,"\0",1) == 0) sdsfree(y); sdsfree(x); x = sdsnew("foo"); y = sdsnew("foa"); TEST_ASSERT_TRUE( sdscmp(x,y) > 0) sdsfree(y); sdsfree(x); x = sdsnew("bar"); y = sdsnew("bar"); TEST_ASSERT_TRUE( sdscmp(x,y) == 0) sdsfree(y); sdsfree(x); x = sdsnew("aar"); y = sdsnew("bar"); TEST_ASSERT_TRUE( sdscmp(x,y) < 0) sdsfree(y); sdsfree(x); // x = sdsnewlen("\a\n\0foo\r",7); // y = sdscatrepr(sdsempty(),x,sdslen(x)); // TEST_ASSERT_TRUE( // memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0) #if 0 { int oldfree; sdsfree(x); x = sdsnew("0"); sh = (void*) (x-(sizeof(struct sdshdr))); TEST_ASSERT_TRUE( sh->len == 1 && sh->free == 0); x = sdsMakeRoomFor(x,1); sh = (void*) (x-(sizeof(struct sdshdr))); TEST_ASSERT_TRUE( sh->len == 1 && sh->free > 0); oldfree = sh->free; x[1] = '1'; sdsIncrLen(x,1); TEST_ASSERT_TRUE( x[0] == '0' && x[1] == '1'); TEST_ASSERT_TRUE( sh->len == 2); TEST_ASSERT_TRUE( sh->free == oldfree-1); } #endif }
int main(void) { { sdshdr *sh; sds x = sdsnew("foo"), y; test_cond("Create a string and obtain the length", sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0) sdsfree(x); x = sdsnewlen("foo",2); test_cond("Create a string with specified length", sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0) x = sdscat(x,"bar"); test_cond("Strings concatenation", sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0); x = sdscpy(x,"a"); test_cond("sdscpy() against an originally longer string", sdslen(x) == 1 && memcmp(x,"a\0",2) == 0) x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk"); test_cond("sdscpy() against an originally shorter string", sdslen(x) == 33 && memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0) sdsfree(x); x = sdscatprintf(sdsempty(),"%d",123); test_cond("sdscatprintf() seems working in the base case", sdslen(x) == 3 && memcmp(x,"123\0",4) ==0) sdsfree(x); x = sdsnew("xxciaoyyy"); sdstrim(x,"xy"); test_cond("sdstrim() correctly trims characters", sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0) y = sdsdup(x); sdsrange(y,1,1); test_cond("sdsrange(...,1,1)", sdslen(y) == 1 && memcmp(y,"i\0",2) == 0) sdsfree(y); y = sdsdup(x); sdsrange(y,1,-1); test_cond("sdsrange(...,1,-1)", sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0) sdsfree(y); y = sdsdup(x); sdsrange(y,-2,-1); test_cond("sdsrange(...,-2,-1)", sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0) sdsfree(y); y = sdsdup(x); sdsrange(y,2,1); test_cond("sdsrange(...,2,1)", sdslen(y) == 0 && memcmp(y,"\0",1) == 0) sdsfree(y); y = sdsdup(x); sdsrange(y,1,100); test_cond("sdsrange(...,1,100)", sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0) sdsfree(y); y = sdsdup(x); sdsrange(y,100,100); test_cond("sdsrange(...,100,100)", sdslen(y) == 0 && memcmp(y,"\0",1) == 0) sdsfree(y); sdsfree(x); x = sdsnew("foo"); y = sdsnew("foa"); test_cond("sdscmp(foo,foa)", sdscmp(x,y) > 0) sdsfree(y); sdsfree(x); x = sdsnew("bar"); y = sdsnew("bar"); test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0) sdsfree(y); sdsfree(x); x = sdsnew("aar"); y = sdsnew("bar"); test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0) sdsfree(y); sdsfree(x); x = sdsnewlen("\a\n\0foo\r",7); y = sdscatrepr(sdsempty(),x,sdslen(x)); test_cond("sdscatrepr(...data...)", memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0) sdsfree(y); { size_t oldfree; sdsfree(x); x = sdsnew("0"); sh = sds_start(x); test_cond("sdsnew() free/len buffers", sh->len == 1 && sh->free == 0); x = sdsMakeRoomFor(x,1); sh = sds_start(x); test_cond("sdsMakeRoomFor()", sh->len == 1 && sh->free > 0); oldfree = sh->free; x[1] = '1'; sdsIncrLen(x,1); test_cond("sdsIncrLen() -- content", x[0] == '0' && x[1] == '1'); test_cond("sdsIncrLen() -- len", sh->len == 2); test_cond("sdsIncrLen() -- free", sh->free == oldfree-1); sdsfree(x); } x = sdsnew("0FoO1bar\n"); sdstolower(x); test_cond("sdstolower(...)", memcmp(x,"0foo1bar\n\0",10) == 0) sdsfree(x); x = sdsnew("0FoO1bar\n"); sdstoupper(x); test_cond("sdstoupper(...)", memcmp(x,"0FOO1BAR\n\0",10) == 0) sdsfree(x); } test_report() return 0; }
/* sid = |flags(4byte)|client fd(4byte)| */ static int smrCbData (void *arg, long long seq, long long timestamp, short nid, int sid, int hash, smrData * smr_data, int size) { char *data = smr_data_get_data (smr_data); redisClient *c; short cmdflags; dlisth *node; /* Special commands */ if (size == 1 && data[0] == REDIS_SMR_CMD_CATCHUP_CHECK) { if (nid == smr_get_nid (server.smr_conn) && (server.smr_init_flags & SMR_INIT_CATCHUP_PHASE2)) checkSmrCatchup (); goto release_seq; } else if (size == 1 && data[0] == REDIS_SMR_CMD_DELIVER_OOM) { server.smr_oom_until = timestamp + REDIS_OOM_DURATION_MS; goto release_seq; } /* Normal command */ server.smr_mstime = timestamp; cmdflags = (0xFFFF0000 & sid) >> 16; /* Because we fixed the bug that causes timestamp be 0, * this warning log is not necessary and just an assert statement is enough after all. * But currently, there are nbase-arc clusters which have the bug. * So, we don't assert for now. */ if (timestamp == 0) { redisLog (REDIS_WARNING, "Timestamp of SMR callback is 0," "seq:%lld, nid:%d, sid:%d, hash:%d, size:%d", seq, nid, sid, hash, size); } if ((server.smr_init_flags & SMR_INIT_DONE) && nid == smr_get_nid (server.smr_conn)) { callbackInfo *cb; /* query from this server. get client from global callback list */ assert (!dlisth_is_empty (&server.global_callbacks)); /* global callback list shouldn't be empty */ node = server.global_callbacks.next; cb = (callbackInfo *) node; dlisth_delete (&cb->global_head); dlisth_delete (&cb->client_head); c = cb->client; assert (cb->hash == hash); assert (c->fd == -1 || c->fd == (0X0000FFFF & sid)); /* We already parsed querybuf because the query is requested from this * server before smr callback*/ c->argc = cb->argc; c->argv = cb->argv; cb->argc = 0; cb->argv = NULL; zfree (cb); server.current_client = c; /* fake client doesn't need to execute non-write query(read-only or admin) */ if (c->fd != -1 || cmdflags & REDIS_CMD_WRITE) { assert (!(c->flags & REDIS_CLOSE_AFTER_REPLY)); processCommand (c); } } else { /* replicated query from other servers, or catchup query during initialize */ c = server.smrlog_client; server.current_client = c; /* fake client doesn't need to execute non-write query(read-only or admin) */ if (cmdflags & REDIS_CMD_WRITE) { /* We need to parse querybuf because the query is from different server * or we are recovering without client */ sdsclear (c->querybuf); c->querybuf = sdsMakeRoomFor (c->querybuf, size); memcpy (c->querybuf, data, size); sdsIncrLen (c->querybuf, size); if (c->querybuf_peak < size) c->querybuf_peak = size; processInputBuffer (c); } } resetClient (c); zfree (c->argv); c->argv = NULL; server.current_client = NULL; release_seq: if (smr_release_seq_upto (server.smr_conn, seq + size) == -1) { redisLog (REDIS_WARNING, "smr_release_seq_upto error"); redisAssert (0); return REDIS_ERR; } server.smr_seqnum = seq + size; return REDIS_OK; }
static void redis_test_read_handler(aeEventLoop *el, int fd, void *privdata, int mask) { redis_test_client *c = (redis_test_client*) privdata; UNUSED(el); UNUSED(mask); static char buf[1024]; int ret = recv(fd, buf, 1024, 0); if (ret == 0) { serverLog(LL_WARNING, "%s %d %d: recv ret [%d] err [%d]", __FUNCTION__, __LINE__, fd, ret, errno); free_redis_test_client(c); return; } else if (ret < 0) { if (errno != EAGAIN && errno != EINTR) { serverLog(LL_WARNING, "%s %d %d: recv ret [%d] err [%d]", __FUNCTION__, __LINE__, fd, ret, errno); free_redis_test_client(c); return; } else { return; } } if (ret != send(fd, buf, ret, 0)) { serverLog(LL_WARNING, "%s %d %d: recv ret [%d] err [%d]", __FUNCTION__, __LINE__, fd, ret, errno); free_redis_test_client(c); } return; #if 0 redis_test_client *c = (redis_test_client*) privdata; int nread, readlen; size_t qblen; UNUSED(el); UNUSED(mask); readlen = PROTO_IOBUF_LEN; qblen = sdslen(c->querybuf); // if (c->querybuf_peak < qblen) c->querybuf_peak = qblen; c->querybuf = sdsMakeRoomFor(c->querybuf, readlen); nread = read(fd, c->querybuf+qblen, readlen); if (nread == -1) { if (errno == EAGAIN) { return; } else { serverLog(LL_VERBOSE, "Reading from client: %s",strerror(errno)); free_redis_test_client(c); return; } } else if (nread == 0) { serverLog(LL_VERBOSE, "Client closed connection"); free_redis_test_client(c); return; } sdsIncrLen(c->querybuf,nread); c->lastinteraction = server.unixtime; printf("%s %d: len = %zd, nread = %d, buf = %s\n", __FUNCTION__, __LINE__, sdslen(c->querybuf), nread, c->querybuf); // processInputBuffer(c); #endif }
int processMultibulkBuffer(client *c) { char *newline = NULL; int pos = 0, ok; long long ll; if (c->multibulklen == 0) { /* The client should have been reset */ serverAssertWithInfo(c,NULL,c->argc == 0); /* Multi bulk length cannot be read without a \r\n */ newline = strchr(c->querybuf,'\r'); if (newline == NULL) { if (sdslen(c->querybuf) > PROTO_INLINE_MAX_SIZE) { addReplyError(c,"Protocol error: too big mbulk count string"); setProtocolError(c,0); } return C_ERR; } /* Buffer should also contain \n */ if (newline-(c->querybuf) > ((signed)sdslen(c->querybuf)-2)) return C_ERR; /* We know for sure there is a whole line since newline != NULL, * so go ahead and find out the multi bulk length. */ serverAssertWithInfo(c,NULL,c->querybuf[0] == '*'); ok = string2ll(c->querybuf+1,newline-(c->querybuf+1),&ll); if (!ok || ll > 1024*1024) { addReplyError(c,"Protocol error: invalid multibulk length"); setProtocolError(c,pos); return C_ERR; } pos = (newline-c->querybuf)+2; if (ll <= 0) { sdsrange(c->querybuf,pos,-1); return C_OK; } c->multibulklen = ll; /* Setup argv array on client structure */ if (c->argv) free(c->argv); c->argv = malloc(sizeof(sds*)*c->multibulklen); } serverAssertWithInfo(c,NULL,c->multibulklen > 0); while(c->multibulklen) { /* Read bulk length if unknown */ if (c->bulklen == -1) { newline = strchr(c->querybuf+pos,'\r'); if (newline == NULL) { if (sdslen(c->querybuf) > PROTO_INLINE_MAX_SIZE) { addReplyError(c, "Protocol error: too big bulk count string"); setProtocolError(c,0); return C_ERR; } break; } /* Buffer should also contain \n */ if (newline-(c->querybuf) > ((signed)sdslen(c->querybuf)-2)) break; if (c->querybuf[pos] != '$') { addReplyErrorFormat(c, "Protocol error: expected '$', got '%c'", c->querybuf[pos]); setProtocolError(c,pos); return C_ERR; } ok = string2ll(c->querybuf+pos+1,newline-(c->querybuf+pos+1),&ll); if (!ok || ll < 0 || ll > 512*1024*1024) { addReplyError(c,"Protocol error: invalid bulk length"); setProtocolError(c,pos); return C_ERR; } pos += newline-(c->querybuf+pos)+2; if (ll >= PROTO_MBULK_BIG_ARG) { size_t qblen; /* If we are going to read a large object from network * try to make it likely that it will start at c->querybuf * boundary so that we can optimize object creation * avoiding a large copy of data. */ sdsrange(c->querybuf,pos,-1); pos = 0; qblen = sdslen(c->querybuf); /* Hint the sds library about the amount of bytes this string is * going to contain. */ if (qblen < (size_t)ll+2) c->querybuf = sdsMakeRoomFor(c->querybuf,ll+2-qblen); } c->bulklen = ll; } /* Read bulk argument */ if (sdslen(c->querybuf)-pos < (unsigned)(c->bulklen+2)) { /* Not enough data (+2 == trailing \r\n) */ break; } else { /* Optimization: if the buffer contains JUST our bulk element * instead of creating a new object by *copying* the sds we * just use the current sds string. */ if (pos == 0 && c->bulklen >= PROTO_MBULK_BIG_ARG && (signed) sdslen(c->querybuf) == c->bulklen+2) { c->argv[c->argc++] = c->querybuf; sdsIncrLen(c->querybuf,-2); /* remove CRLF */ c->querybuf = sdsempty(); /* Assume that if we saw a fat argument we'll see another one * likely... */ c->querybuf = sdsMakeRoomFor(c->querybuf,c->bulklen+2); pos = 0; } else { c->argv[c->argc++] = sdsnewlen(c->querybuf+pos,c->bulklen); pos += c->bulklen+2; } c->bulklen = -1; c->multibulklen--; } } /* Trim to pos */ if (pos) sdsrange(c->querybuf,pos,-1); /* We're done when c->multibulk == 0 */ if (c->multibulklen == 0) return C_OK; /* Still not read to process the command */ return C_ERR; }
static int se_try_read(lua_State *L, int fd, int size, sds *pcache) { char sbuf[4 << 10]; char *cache = *pcache; char *buf; int bufsize; int nread; if (cache) { bufsize = sdsavail(cache); buf = cache + sdslen(cache); printf("continue try read: %d / %d\n", bufsize, size); } else { // first try bufsize = size > 0 ? size : size < 0 ? -size : sizeof(sbuf); if (bufsize <= sizeof(sbuf)) { buf = sbuf; } else { cache = sdsnewlen(NULL, bufsize); oom_check(cache); sdsclear(cache); *pcache = cache; buf = cache; } printf("try read: %d / %d\n", bufsize, size); } nread = read(fd, buf, bufsize); if (nread > 0) { if (size <= 0 || nread == bufsize) { // done if (cache) { lua_pushlstring(L, cache, sdslen(cache) + nread); sdsfree(cache); *pcache = NULL; } else { lua_pushlstring(L, buf, nread); } printf("read done: %d / %d / %d\n", nread, bufsize, size); return 1; } // partial read if (!cache) { cache = sdsnewlen(NULL, bufsize); oom_check(cache); sdsclear(cache); *pcache = cache; memcpy(cache, buf, nread); } sdsIncrLen(cache, nread); printf("partial read: %d / %d / %d\n", nread, bufsize, size); return -1; } if (nread == 0) return se_read_error(L, pcache, "EOF"); if (errno == EAGAIN || errno == EWOULDBLOCK) return -1; se_assert(L, errno != EBADF, "read(%d) error", fd); return se_read_error(L, pcache, strerror(errno)); }
static void * clientThread (void *arg) { client_t *c = (client_t *) arg; fd_set rfds, wfds; int ret; c->querybuf = sdsMakeRoomFor (sdsempty (), DEFAULT_QUERY_BUF_SIZE); c->replybuf = sdsMakeRoomFor (sdsempty (), DEFAULT_QUERY_BUF_SIZE); c->argc = 0; c->argv = NULL; c->argvlen = NULL; c->reqtype = 0; c->multibulklen = 0; c->bulklen = -1; c->rqst = arc_create_request (); c->flags = 0; c->total_append_command = 0; FD_ZERO (&rfds); FD_ZERO (&wfds); while (1) { struct timeval timeout; FD_CLR (c->fd, &rfds); FD_CLR (c->fd, &wfds); if (!(c->flags & REDIS_CLOSE_AFTER_REPLY)) FD_SET (c->fd, &rfds); if (sdslen (c->replybuf) > 0) FD_SET (c->fd, &wfds); timeout.tv_sec = 1; timeout.tv_usec = 0; ret = select (c->fd + 1, &rfds, &wfds, NULL, &timeout); if (ret == -1) { perror ("select"); freeClient (c); } if (server.shutdown_signal) { c->flags |= REDIS_CLOSE_AFTER_REPLY; } /* readable */ if (FD_ISSET (c->fd, &rfds)) { int pos = sdslen (c->querybuf); int avail = sdsavail (c->querybuf); ssize_t nread; if (avail == 0) { c->querybuf = sdsMakeRoomFor (c->querybuf, sdslen (c->querybuf)); avail = sdsavail (c->querybuf); } nread = read (c->fd, c->querybuf + pos, avail); if (nread > 0) { sdsIncrLen (c->querybuf, nread); processInputBuffer (c); if (c->total_append_command) { int arc_errno, arc_be_errno, be_errno; arc_ref_t *arc_ref; arc_ref = acquire_arc_ref (); ret = arc_do_request (arc_ref->arc, c->rqst, server.query_timeout_millis, &be_errno); if (ret == -1) { arc_errno = errno; arc_be_errno = be_errno; } else { ret = processReply (c, &be_errno); if (ret == -1) { arc_errno = errno; arc_be_errno = be_errno; } } arc_free_request (c->rqst); release_arc_ref (arc_ref); c->rqst = arc_create_request (); if (ret == -1) { if (arc_errno == ARC_ERR_TIMEOUT || (arc_errno == ARC_ERR_BACKEND && arc_be_errno == ARC_ERR_TIMEOUT)) { addReplyStr (c, "-ERR Redis Timeout\r\n"); } else { addReplyStr (c, "-ERR Internal Error\r\n"); } c->flags |= REDIS_CLOSE_AFTER_REPLY; } } } else { if (nread == -1 && errno == EAGAIN) { /* Skip */ } else { freeClient (c); } } } /* writable */ if (FD_ISSET (c->fd, &wfds)) { int pos = 0; int avail = sdslen (c->replybuf); ssize_t nwritten; nwritten = write (c->fd, c->replybuf + pos, avail); if (nwritten > 0) { avail -= nwritten; pos += nwritten; sdsrange (c->replybuf, pos, -1); } else { if (nwritten == -1 && errno == EAGAIN) { /* Skip */ } else { freeClient (c); } } } if (sdslen (c->replybuf) == 0 && (c->flags & REDIS_CLOSE_AFTER_REPLY)) { freeClient (c); } } return NULL; }