* connection. Note that we create the client instead to check before
* for this condition, since now the socket is already set in nonblocking
* mode and we can send an error for free using the Kernel I/O */
- if (server.maxclients && listLength(server.clients) > server.maxclients) {
+ if (listLength(server.clients) > server.maxclients) {
char *err = "-ERR max number of clients reached\r\n";
/* That's a best effort error message, don't check write errors */
}
pos += newline-(c->querybuf+pos)+2;
+#ifdef REDIS_MBULK_BIG_ARG
+ if (ll >= REDIS_MBULK_BIG_ARG) {
+ /* 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 optimized object creation
+ * avoiding a large copy of data. */
+ c->querybuf = sdsrange(c->querybuf,pos,-1);
+ pos = 0;
+ }
+ /* Hint the sds library about the amount of bytes this string is
+ * going to contain. */
+ if (ll >= REDIS_MBULK_BIG_ARG)
+ c->querybuf = sdsMakeRoomFor(c->querybuf,ll+2);
+#endif
c->bulklen = ll;
}
/* Not enough data (+2 == trailing \r\n) */
break;
} else {
- c->argv[c->argc++] = createStringObject(c->querybuf+pos,c->bulklen);
- pos += c->bulklen+2;
+ /* Optimization: if the buffer contanins JUST our bulk element
+ * instead of creating a new object by *copying* the sds we
+ * just use the current sds string. */
+#ifdef REDIS_MBULK_BIG_ARG
+ if (pos == 0 &&
+ c->bulklen >= REDIS_MBULK_BIG_ARG &&
+ (signed) sdslen(c->querybuf) == c->bulklen+2)
+ {
+ // printf("HERE (arg %d)\n",c->argc);
+ c->argv[c->argc++] = createObject(REDIS_STRING,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 {
+#endif
+ // printf("NOT HERE (arg %d) (pos %d)\n",c->argc, pos);
+ c->argv[c->argc++] =
+ createStringObject(c->querybuf+pos,c->bulklen);
+ pos += c->bulklen+2;
+#ifdef REDIS_MBULK_BIG_ARG
+ }
+#endif
c->bulklen = -1;
c->multibulklen--;
}
}
/* Trim to pos */
- c->querybuf = sdsrange(c->querybuf,pos,-1);
+ if (pos) c->querybuf = sdsrange(c->querybuf,pos,-1);
/* We're done when c->multibulk == 0 */
if (c->multibulklen == 0) {
void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
redisClient *c = (redisClient*) privdata;
- char buf[REDIS_IOBUF_LEN];
- int nread;
+ int nread, readlen;
+ size_t qblen;
REDIS_NOTUSED(el);
REDIS_NOTUSED(mask);
- nread = read(fd, buf, REDIS_IOBUF_LEN);
+ readlen = REDIS_IOBUF_LEN;
+#if REDIS_MBULK_BIG_ARG
+ /* If this is a multi bulk request, and we are processing a bulk reply
+ * that is large enough, try to maximize the probabilty that the query
+ * buffer contains excatly the SDS string representing the object, even
+ * at the risk of requring more read(2) calls. This way the function
+ * processMultiBulkBuffer() can avoid copying buffers to create the
+ * Redis Object representing the argument. */
+ if (c->reqtype == REDIS_REQ_MULTIBULK && c->multibulklen && c->bulklen != -1
+ && c->bulklen >= REDIS_MBULK_BIG_ARG)
+ {
+ int remaining = (unsigned)(c->bulklen+2)-sdslen(c->querybuf);
+
+ if (remaining < readlen) readlen = remaining;
+ }
+#endif
+
+ 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;
return;
}
if (nread) {
- c->querybuf = sdscatlen(c->querybuf,buf,nread);
+ sdsIncrLen(c->querybuf,nread);
c->lastinteraction = time(NULL);
} else {
return;