]> git.saurik.com Git - redis.git/blob - src/networking.c
Object approximated LRU algorithm enhanced / fixed / refactored. This is used for...
[redis.git] / src / networking.c
1 #include "redis.h"
2 #include <sys/uio.h>
3
4 void *dupClientReplyValue(void *o) {
5 incrRefCount((robj*)o);
6 return o;
7 }
8
9 int listMatchObjects(void *a, void *b) {
10 return equalStringObjects(a,b);
11 }
12
13 redisClient *createClient(int fd) {
14 redisClient *c = zmalloc(sizeof(redisClient));
15 c->bufpos = 0;
16
17 anetNonBlock(NULL,fd);
18 anetTcpNoDelay(NULL,fd);
19 if (!c) return NULL;
20 if (aeCreateFileEvent(server.el,fd,AE_READABLE,
21 readQueryFromClient, c) == AE_ERR)
22 {
23 close(fd);
24 zfree(c);
25 return NULL;
26 }
27
28 selectDb(c,0);
29 c->fd = fd;
30 c->querybuf = sdsempty();
31 c->newline = NULL;
32 c->argc = 0;
33 c->argv = NULL;
34 c->bulklen = -1;
35 c->multibulk = 0;
36 c->mbargc = 0;
37 c->mbargv = NULL;
38 c->sentlen = 0;
39 c->flags = 0;
40 c->lastinteraction = time(NULL);
41 c->authenticated = 0;
42 c->replstate = REDIS_REPL_NONE;
43 c->reply = listCreate();
44 listSetFreeMethod(c->reply,decrRefCount);
45 listSetDupMethod(c->reply,dupClientReplyValue);
46 c->blocking_keys = NULL;
47 c->blocking_keys_num = 0;
48 c->io_keys = listCreate();
49 c->watched_keys = listCreate();
50 listSetFreeMethod(c->io_keys,decrRefCount);
51 c->pubsub_channels = dictCreate(&setDictType,NULL);
52 c->pubsub_patterns = listCreate();
53 listSetFreeMethod(c->pubsub_patterns,decrRefCount);
54 listSetMatchMethod(c->pubsub_patterns,listMatchObjects);
55 listAddNodeTail(server.clients,c);
56 initClientMultiState(c);
57 return c;
58 }
59
60 int _installWriteEvent(redisClient *c) {
61 if (c->fd <= 0) return REDIS_ERR;
62 if (c->bufpos == 0 && listLength(c->reply) == 0 &&
63 (c->replstate == REDIS_REPL_NONE ||
64 c->replstate == REDIS_REPL_ONLINE) &&
65 aeCreateFileEvent(server.el, c->fd, AE_WRITABLE,
66 sendReplyToClient, c) == AE_ERR) return REDIS_ERR;
67 return REDIS_OK;
68 }
69
70 /* Create a duplicate of the last object in the reply list when
71 * it is not exclusively owned by the reply list. */
72 robj *dupLastObjectIfNeeded(list *reply) {
73 robj *new, *cur;
74 listNode *ln;
75 redisAssert(listLength(reply) > 0);
76 ln = listLast(reply);
77 cur = listNodeValue(ln);
78 if (cur->refcount > 1) {
79 new = dupStringObject(cur);
80 decrRefCount(cur);
81 listNodeValue(ln) = new;
82 }
83 return listNodeValue(ln);
84 }
85
86 int _addReplyToBuffer(redisClient *c, char *s, size_t len) {
87 size_t available = sizeof(c->buf)-c->bufpos;
88
89 /* If there already are entries in the reply list, we cannot
90 * add anything more to the static buffer. */
91 if (listLength(c->reply) > 0) return REDIS_ERR;
92
93 /* Check that the buffer has enough space available for this string. */
94 if (len > available) return REDIS_ERR;
95
96 memcpy(c->buf+c->bufpos,s,len);
97 c->bufpos+=len;
98 return REDIS_OK;
99 }
100
101 void _addReplyObjectToList(redisClient *c, robj *o) {
102 robj *tail;
103 if (listLength(c->reply) == 0) {
104 incrRefCount(o);
105 listAddNodeTail(c->reply,o);
106 } else {
107 tail = listNodeValue(listLast(c->reply));
108
109 /* Append to this object when possible. */
110 if (tail->ptr != NULL &&
111 sdslen(tail->ptr)+sdslen(o->ptr) <= REDIS_REPLY_CHUNK_BYTES)
112 {
113 tail = dupLastObjectIfNeeded(c->reply);
114 tail->ptr = sdscatlen(tail->ptr,o->ptr,sdslen(o->ptr));
115 } else {
116 incrRefCount(o);
117 listAddNodeTail(c->reply,o);
118 }
119 }
120 }
121
122 /* This method takes responsibility over the sds. When it is no longer
123 * needed it will be free'd, otherwise it ends up in a robj. */
124 void _addReplySdsToList(redisClient *c, sds s) {
125 robj *tail;
126 if (listLength(c->reply) == 0) {
127 listAddNodeTail(c->reply,createObject(REDIS_STRING,s));
128 } else {
129 tail = listNodeValue(listLast(c->reply));
130
131 /* Append to this object when possible. */
132 if (tail->ptr != NULL &&
133 sdslen(tail->ptr)+sdslen(s) <= REDIS_REPLY_CHUNK_BYTES)
134 {
135 tail = dupLastObjectIfNeeded(c->reply);
136 tail->ptr = sdscatlen(tail->ptr,s,sdslen(s));
137 sdsfree(s);
138 } else {
139 listAddNodeTail(c->reply,createObject(REDIS_STRING,s));
140 }
141 }
142 }
143
144 void _addReplyStringToList(redisClient *c, char *s, size_t len) {
145 robj *tail;
146 if (listLength(c->reply) == 0) {
147 listAddNodeTail(c->reply,createStringObject(s,len));
148 } else {
149 tail = listNodeValue(listLast(c->reply));
150
151 /* Append to this object when possible. */
152 if (tail->ptr != NULL &&
153 sdslen(tail->ptr)+len <= REDIS_REPLY_CHUNK_BYTES)
154 {
155 tail = dupLastObjectIfNeeded(c->reply);
156 tail->ptr = sdscatlen(tail->ptr,s,len);
157 } else {
158 listAddNodeTail(c->reply,createStringObject(s,len));
159 }
160 }
161 }
162
163 void addReply(redisClient *c, robj *obj) {
164 if (_installWriteEvent(c) != REDIS_OK) return;
165 redisAssert(!server.vm_enabled || obj->storage == REDIS_VM_MEMORY);
166
167 /* This is an important place where we can avoid copy-on-write
168 * when there is a saving child running, avoiding touching the
169 * refcount field of the object if it's not needed.
170 *
171 * If the encoding is RAW and there is room in the static buffer
172 * we'll be able to send the object to the client without
173 * messing with its page. */
174 if (obj->encoding == REDIS_ENCODING_RAW) {
175 if (_addReplyToBuffer(c,obj->ptr,sdslen(obj->ptr)) != REDIS_OK)
176 _addReplyObjectToList(c,obj);
177 } else {
178 obj = getDecodedObject(obj);
179 if (_addReplyToBuffer(c,obj->ptr,sdslen(obj->ptr)) != REDIS_OK)
180 _addReplyObjectToList(c,obj);
181 decrRefCount(obj);
182 }
183 }
184
185 void addReplySds(redisClient *c, sds s) {
186 if (_installWriteEvent(c) != REDIS_OK) {
187 /* The caller expects the sds to be free'd. */
188 sdsfree(s);
189 return;
190 }
191 if (_addReplyToBuffer(c,s,sdslen(s)) == REDIS_OK) {
192 sdsfree(s);
193 } else {
194 /* This method free's the sds when it is no longer needed. */
195 _addReplySdsToList(c,s);
196 }
197 }
198
199 void addReplyString(redisClient *c, char *s, size_t len) {
200 if (_installWriteEvent(c) != REDIS_OK) return;
201 if (_addReplyToBuffer(c,s,len) != REDIS_OK)
202 _addReplyStringToList(c,s,len);
203 }
204
205 void _addReplyError(redisClient *c, char *s, size_t len) {
206 addReplyString(c,"-ERR ",5);
207 addReplyString(c,s,len);
208 addReplyString(c,"\r\n",2);
209 }
210
211 void addReplyError(redisClient *c, char *err) {
212 _addReplyError(c,err,strlen(err));
213 }
214
215 void addReplyErrorFormat(redisClient *c, const char *fmt, ...) {
216 va_list ap;
217 va_start(ap,fmt);
218 sds s = sdscatvprintf(sdsempty(),fmt,ap);
219 va_end(ap);
220 _addReplyError(c,s,sdslen(s));
221 sdsfree(s);
222 }
223
224 void _addReplyStatus(redisClient *c, char *s, size_t len) {
225 addReplyString(c,"+",1);
226 addReplyString(c,s,len);
227 addReplyString(c,"\r\n",2);
228 }
229
230 void addReplyStatus(redisClient *c, char *status) {
231 _addReplyStatus(c,status,strlen(status));
232 }
233
234 void addReplyStatusFormat(redisClient *c, const char *fmt, ...) {
235 va_list ap;
236 va_start(ap,fmt);
237 sds s = sdscatvprintf(sdsempty(),fmt,ap);
238 va_end(ap);
239 _addReplyStatus(c,s,sdslen(s));
240 sdsfree(s);
241 }
242
243 /* Adds an empty object to the reply list that will contain the multi bulk
244 * length, which is not known when this function is called. */
245 void *addDeferredMultiBulkLength(redisClient *c) {
246 /* Note that we install the write event here even if the object is not
247 * ready to be sent, since we are sure that before returning to the
248 * event loop setDeferredMultiBulkLength() will be called. */
249 if (_installWriteEvent(c) != REDIS_OK) return NULL;
250 listAddNodeTail(c->reply,createObject(REDIS_STRING,NULL));
251 return listLast(c->reply);
252 }
253
254 /* Populate the length object and try glueing it to the next chunk. */
255 void setDeferredMultiBulkLength(redisClient *c, void *node, long length) {
256 listNode *ln = (listNode*)node;
257 robj *len, *next;
258
259 /* Abort when *node is NULL (see addDeferredMultiBulkLength). */
260 if (node == NULL) return;
261
262 len = listNodeValue(ln);
263 len->ptr = sdscatprintf(sdsempty(),"*%ld\r\n",length);
264 if (ln->next != NULL) {
265 next = listNodeValue(ln->next);
266
267 /* Only glue when the next node is non-NULL (an sds in this case) */
268 if (next->ptr != NULL) {
269 len->ptr = sdscatlen(len->ptr,next->ptr,sdslen(next->ptr));
270 listDelNode(c->reply,ln->next);
271 }
272 }
273 }
274
275 void addReplyDouble(redisClient *c, double d) {
276 char dbuf[128], sbuf[128];
277 int dlen, slen;
278 dlen = snprintf(dbuf,sizeof(dbuf),"%.17g",d);
279 slen = snprintf(sbuf,sizeof(sbuf),"$%d\r\n%s\r\n",dlen,dbuf);
280 addReplyString(c,sbuf,slen);
281 }
282
283 void _addReplyLongLong(redisClient *c, long long ll, char prefix) {
284 char buf[128];
285 int len;
286 buf[0] = prefix;
287 len = ll2string(buf+1,sizeof(buf)-1,ll);
288 buf[len+1] = '\r';
289 buf[len+2] = '\n';
290 addReplyString(c,buf,len+3);
291 }
292
293 void addReplyLongLong(redisClient *c, long long ll) {
294 _addReplyLongLong(c,ll,':');
295 }
296
297 void addReplyMultiBulkLen(redisClient *c, long length) {
298 _addReplyLongLong(c,length,'*');
299 }
300
301 void addReplyBulkLen(redisClient *c, robj *obj) {
302 size_t len;
303
304 if (obj->encoding == REDIS_ENCODING_RAW) {
305 len = sdslen(obj->ptr);
306 } else {
307 long n = (long)obj->ptr;
308
309 /* Compute how many bytes will take this integer as a radix 10 string */
310 len = 1;
311 if (n < 0) {
312 len++;
313 n = -n;
314 }
315 while((n = n/10) != 0) {
316 len++;
317 }
318 }
319 _addReplyLongLong(c,len,'$');
320 }
321
322 void addReplyBulk(redisClient *c, robj *obj) {
323 addReplyBulkLen(c,obj);
324 addReply(c,obj);
325 addReply(c,shared.crlf);
326 }
327
328 /* In the CONFIG command we need to add vanilla C string as bulk replies */
329 void addReplyBulkCString(redisClient *c, char *s) {
330 if (s == NULL) {
331 addReply(c,shared.nullbulk);
332 } else {
333 robj *o = createStringObject(s,strlen(s));
334 addReplyBulk(c,o);
335 decrRefCount(o);
336 }
337 }
338
339 void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
340 int cport, cfd;
341 char cip[128];
342 redisClient *c;
343 REDIS_NOTUSED(el);
344 REDIS_NOTUSED(mask);
345 REDIS_NOTUSED(privdata);
346
347 cfd = anetAccept(server.neterr, fd, cip, &cport);
348 if (cfd == AE_ERR) {
349 redisLog(REDIS_VERBOSE,"Accepting client connection: %s", server.neterr);
350 return;
351 }
352 redisLog(REDIS_VERBOSE,"Accepted %s:%d", cip, cport);
353 if ((c = createClient(cfd)) == NULL) {
354 redisLog(REDIS_WARNING,"Error allocating resoures for the client");
355 close(cfd); /* May be already closed, just ingore errors */
356 return;
357 }
358 /* If maxclient directive is set and this is one client more... close the
359 * connection. Note that we create the client instead to check before
360 * for this condition, since now the socket is already set in nonblocking
361 * mode and we can send an error for free using the Kernel I/O */
362 if (server.maxclients && listLength(server.clients) > server.maxclients) {
363 char *err = "-ERR max number of clients reached\r\n";
364
365 /* That's a best effort error message, don't check write errors */
366 if (write(c->fd,err,strlen(err)) == -1) {
367 /* Nothing to do, Just to avoid the warning... */
368 }
369 freeClient(c);
370 return;
371 }
372 server.stat_numconnections++;
373 }
374
375 static void freeClientArgv(redisClient *c) {
376 int j;
377
378 for (j = 0; j < c->argc; j++)
379 decrRefCount(c->argv[j]);
380 for (j = 0; j < c->mbargc; j++)
381 decrRefCount(c->mbargv[j]);
382 c->argc = 0;
383 c->mbargc = 0;
384 }
385
386 void freeClient(redisClient *c) {
387 listNode *ln;
388
389 /* Note that if the client we are freeing is blocked into a blocking
390 * call, we have to set querybuf to NULL *before* to call
391 * unblockClientWaitingData() to avoid processInputBuffer() will get
392 * called. Also it is important to remove the file events after
393 * this, because this call adds the READABLE event. */
394 sdsfree(c->querybuf);
395 c->querybuf = NULL;
396 if (c->flags & REDIS_BLOCKED)
397 unblockClientWaitingData(c);
398
399 /* UNWATCH all the keys */
400 unwatchAllKeys(c);
401 listRelease(c->watched_keys);
402 /* Unsubscribe from all the pubsub channels */
403 pubsubUnsubscribeAllChannels(c,0);
404 pubsubUnsubscribeAllPatterns(c,0);
405 dictRelease(c->pubsub_channels);
406 listRelease(c->pubsub_patterns);
407 /* Obvious cleanup */
408 aeDeleteFileEvent(server.el,c->fd,AE_READABLE);
409 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
410 listRelease(c->reply);
411 freeClientArgv(c);
412 close(c->fd);
413 /* Remove from the list of clients */
414 ln = listSearchKey(server.clients,c);
415 redisAssert(ln != NULL);
416 listDelNode(server.clients,ln);
417 /* Remove from the list of clients waiting for swapped keys, or ready
418 * to be restarted, but not yet woken up again. */
419 if (c->flags & REDIS_IO_WAIT) {
420 redisAssert(server.vm_enabled);
421 if (listLength(c->io_keys) == 0) {
422 ln = listSearchKey(server.io_ready_clients,c);
423
424 /* When this client is waiting to be woken up (REDIS_IO_WAIT),
425 * it should be present in the list io_ready_clients */
426 redisAssert(ln != NULL);
427 listDelNode(server.io_ready_clients,ln);
428 } else {
429 while (listLength(c->io_keys)) {
430 ln = listFirst(c->io_keys);
431 dontWaitForSwappedKey(c,ln->value);
432 }
433 }
434 server.vm_blocked_clients--;
435 }
436 listRelease(c->io_keys);
437 /* Master/slave cleanup.
438 * Case 1: we lost the connection with a slave. */
439 if (c->flags & REDIS_SLAVE) {
440 if (c->replstate == REDIS_REPL_SEND_BULK && c->repldbfd != -1)
441 close(c->repldbfd);
442 list *l = (c->flags & REDIS_MONITOR) ? server.monitors : server.slaves;
443 ln = listSearchKey(l,c);
444 redisAssert(ln != NULL);
445 listDelNode(l,ln);
446 }
447
448 /* Case 2: we lost the connection with the master. */
449 if (c->flags & REDIS_MASTER) {
450 server.master = NULL;
451 server.replstate = REDIS_REPL_CONNECT;
452 /* Since we lost the connection with the master, we should also
453 * close the connection with all our slaves if we have any, so
454 * when we'll resync with the master the other slaves will sync again
455 * with us as well. Note that also when the slave is not connected
456 * to the master it will keep refusing connections by other slaves. */
457 while (listLength(server.slaves)) {
458 ln = listFirst(server.slaves);
459 freeClient((redisClient*)ln->value);
460 }
461 }
462 /* Release memory */
463 zfree(c->argv);
464 zfree(c->mbargv);
465 freeClientMultiState(c);
466 zfree(c);
467 }
468
469 void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
470 redisClient *c = privdata;
471 int nwritten = 0, totwritten = 0, objlen;
472 robj *o;
473 REDIS_NOTUSED(el);
474 REDIS_NOTUSED(mask);
475
476 /* Use writev() if we have enough buffers to send */
477 if (!server.glueoutputbuf &&
478 listLength(c->reply) > REDIS_WRITEV_THRESHOLD &&
479 !(c->flags & REDIS_MASTER))
480 {
481 sendReplyToClientWritev(el, fd, privdata, mask);
482 return;
483 }
484
485 while(c->bufpos > 0 || listLength(c->reply)) {
486 if (c->bufpos > 0) {
487 if (c->flags & REDIS_MASTER) {
488 /* Don't reply to a master */
489 nwritten = c->bufpos - c->sentlen;
490 } else {
491 nwritten = write(fd,c->buf+c->sentlen,c->bufpos-c->sentlen);
492 if (nwritten <= 0) break;
493 }
494 c->sentlen += nwritten;
495 totwritten += nwritten;
496
497 /* If the buffer was sent, set bufpos to zero to continue with
498 * the remainder of the reply. */
499 if (c->sentlen == c->bufpos) {
500 c->bufpos = 0;
501 c->sentlen = 0;
502 }
503 } else {
504 o = listNodeValue(listFirst(c->reply));
505 objlen = sdslen(o->ptr);
506
507 if (objlen == 0) {
508 listDelNode(c->reply,listFirst(c->reply));
509 continue;
510 }
511
512 if (c->flags & REDIS_MASTER) {
513 /* Don't reply to a master */
514 nwritten = objlen - c->sentlen;
515 } else {
516 nwritten = write(fd, ((char*)o->ptr)+c->sentlen,objlen-c->sentlen);
517 if (nwritten <= 0) break;
518 }
519 c->sentlen += nwritten;
520 totwritten += nwritten;
521
522 /* If we fully sent the object on head go to the next one */
523 if (c->sentlen == objlen) {
524 listDelNode(c->reply,listFirst(c->reply));
525 c->sentlen = 0;
526 }
527 }
528 /* Note that we avoid to send more thank REDIS_MAX_WRITE_PER_EVENT
529 * bytes, in a single threaded server it's a good idea to serve
530 * other clients as well, even if a very large request comes from
531 * super fast link that is always able to accept data (in real world
532 * scenario think about 'KEYS *' against the loopback interfae) */
533 if (totwritten > REDIS_MAX_WRITE_PER_EVENT) break;
534 }
535 if (nwritten == -1) {
536 if (errno == EAGAIN) {
537 nwritten = 0;
538 } else {
539 redisLog(REDIS_VERBOSE,
540 "Error writing to client: %s", strerror(errno));
541 freeClient(c);
542 return;
543 }
544 }
545 if (totwritten > 0) c->lastinteraction = time(NULL);
546 if (listLength(c->reply) == 0) {
547 c->sentlen = 0;
548 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
549 }
550 }
551
552 void sendReplyToClientWritev(aeEventLoop *el, int fd, void *privdata, int mask)
553 {
554 redisClient *c = privdata;
555 int nwritten = 0, totwritten = 0, objlen, willwrite;
556 robj *o;
557 struct iovec iov[REDIS_WRITEV_IOVEC_COUNT];
558 int offset, ion = 0;
559 REDIS_NOTUSED(el);
560 REDIS_NOTUSED(mask);
561
562 listNode *node;
563 while (listLength(c->reply)) {
564 offset = c->sentlen;
565 ion = 0;
566 willwrite = 0;
567
568 /* fill-in the iov[] array */
569 for(node = listFirst(c->reply); node; node = listNextNode(node)) {
570 o = listNodeValue(node);
571 objlen = sdslen(o->ptr);
572
573 if (totwritten + objlen - offset > REDIS_MAX_WRITE_PER_EVENT)
574 break;
575
576 if(ion == REDIS_WRITEV_IOVEC_COUNT)
577 break; /* no more iovecs */
578
579 iov[ion].iov_base = ((char*)o->ptr) + offset;
580 iov[ion].iov_len = objlen - offset;
581 willwrite += objlen - offset;
582 offset = 0; /* just for the first item */
583 ion++;
584 }
585
586 if(willwrite == 0)
587 break;
588
589 /* write all collected blocks at once */
590 if((nwritten = writev(fd, iov, ion)) < 0) {
591 if (errno != EAGAIN) {
592 redisLog(REDIS_VERBOSE,
593 "Error writing to client: %s", strerror(errno));
594 freeClient(c);
595 return;
596 }
597 break;
598 }
599
600 totwritten += nwritten;
601 offset = c->sentlen;
602
603 /* remove written robjs from c->reply */
604 while (nwritten && listLength(c->reply)) {
605 o = listNodeValue(listFirst(c->reply));
606 objlen = sdslen(o->ptr);
607
608 if(nwritten >= objlen - offset) {
609 listDelNode(c->reply, listFirst(c->reply));
610 nwritten -= objlen - offset;
611 c->sentlen = 0;
612 } else {
613 /* partial write */
614 c->sentlen += nwritten;
615 break;
616 }
617 offset = 0;
618 }
619 }
620
621 if (totwritten > 0)
622 c->lastinteraction = time(NULL);
623
624 if (listLength(c->reply) == 0) {
625 c->sentlen = 0;
626 aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
627 }
628 }
629
630 /* resetClient prepare the client to process the next command */
631 void resetClient(redisClient *c) {
632 freeClientArgv(c);
633 c->bulklen = -1;
634 c->multibulk = 0;
635 c->newline = NULL;
636 }
637
638 void closeTimedoutClients(void) {
639 redisClient *c;
640 listNode *ln;
641 time_t now = time(NULL);
642 listIter li;
643
644 listRewind(server.clients,&li);
645 while ((ln = listNext(&li)) != NULL) {
646 c = listNodeValue(ln);
647 if (server.maxidletime &&
648 !(c->flags & REDIS_SLAVE) && /* no timeout for slaves */
649 !(c->flags & REDIS_MASTER) && /* no timeout for masters */
650 !(c->flags & REDIS_BLOCKED) && /* no timeout for BLPOP */
651 dictSize(c->pubsub_channels) == 0 && /* no timeout for pubsub */
652 listLength(c->pubsub_patterns) == 0 &&
653 (now - c->lastinteraction > server.maxidletime))
654 {
655 redisLog(REDIS_VERBOSE,"Closing idle client");
656 freeClient(c);
657 } else if (c->flags & REDIS_BLOCKED) {
658 if (c->blockingto != 0 && c->blockingto < now) {
659 addReply(c,shared.nullmultibulk);
660 unblockClientWaitingData(c);
661 }
662 }
663 }
664 }
665
666 void processInputBuffer(redisClient *c) {
667 int seeknewline = 0;
668
669 again:
670 /* Before to process the input buffer, make sure the client is not
671 * waitig for a blocking operation such as BLPOP. Note that the first
672 * iteration the client is never blocked, otherwise the processInputBuffer
673 * would not be called at all, but after the execution of the first commands
674 * in the input buffer the client may be blocked, and the "goto again"
675 * will try to reiterate. The following line will make it return asap. */
676 if (c->flags & REDIS_BLOCKED || c->flags & REDIS_IO_WAIT) return;
677
678 if (seeknewline && c->bulklen == -1) c->newline = strchr(c->querybuf,'\n');
679 seeknewline = 1;
680 if (c->bulklen == -1) {
681 /* Read the first line of the query */
682 size_t querylen;
683
684 if (c->newline) {
685 char *p = c->newline;
686 sds query, *argv;
687 int argc, j;
688
689 c->newline = NULL;
690 query = c->querybuf;
691 c->querybuf = sdsempty();
692 querylen = 1+(p-(query));
693 if (sdslen(query) > querylen) {
694 /* leave data after the first line of the query in the buffer */
695 c->querybuf = sdscatlen(c->querybuf,query+querylen,sdslen(query)-querylen);
696 }
697 *p = '\0'; /* remove "\n" */
698 if (*(p-1) == '\r') *(p-1) = '\0'; /* and "\r" if any */
699 sdsupdatelen(query);
700
701 /* Now we can split the query in arguments */
702 argv = sdssplitlen(query,sdslen(query)," ",1,&argc);
703 sdsfree(query);
704
705 if (c->argv) zfree(c->argv);
706 c->argv = zmalloc(sizeof(robj*)*argc);
707
708 for (j = 0; j < argc; j++) {
709 if (sdslen(argv[j])) {
710 c->argv[c->argc] = createObject(REDIS_STRING,argv[j]);
711 c->argc++;
712 } else {
713 sdsfree(argv[j]);
714 }
715 }
716 zfree(argv);
717 if (c->argc) {
718 /* Execute the command. If the client is still valid
719 * after processCommand() return and there is something
720 * on the query buffer try to process the next command. */
721 if (processCommand(c) && sdslen(c->querybuf)) goto again;
722 } else {
723 /* Nothing to process, argc == 0. Just process the query
724 * buffer if it's not empty or return to the caller */
725 if (sdslen(c->querybuf)) goto again;
726 }
727 return;
728 } else if (sdslen(c->querybuf) >= REDIS_REQUEST_MAX_SIZE) {
729 redisLog(REDIS_VERBOSE, "Client protocol error");
730 freeClient(c);
731 return;
732 }
733 } else {
734 /* Bulk read handling. Note that if we are at this point
735 the client already sent a command terminated with a newline,
736 we are reading the bulk data that is actually the last
737 argument of the command. */
738 int qbl = sdslen(c->querybuf);
739
740 if (c->bulklen <= qbl) {
741 /* Copy everything but the final CRLF as final argument */
742 c->argv[c->argc] = createStringObject(c->querybuf,c->bulklen-2);
743 c->argc++;
744 c->querybuf = sdsrange(c->querybuf,c->bulklen,-1);
745 /* Process the command. If the client is still valid after
746 * the processing and there is more data in the buffer
747 * try to parse it. */
748 if (processCommand(c) && sdslen(c->querybuf)) goto again;
749 return;
750 }
751 }
752 }
753
754 void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
755 redisClient *c = (redisClient*) privdata;
756 char buf[REDIS_IOBUF_LEN];
757 int nread;
758 REDIS_NOTUSED(el);
759 REDIS_NOTUSED(mask);
760
761 nread = read(fd, buf, REDIS_IOBUF_LEN);
762 if (nread == -1) {
763 if (errno == EAGAIN) {
764 nread = 0;
765 } else {
766 redisLog(REDIS_VERBOSE, "Reading from client: %s",strerror(errno));
767 freeClient(c);
768 return;
769 }
770 } else if (nread == 0) {
771 redisLog(REDIS_VERBOSE, "Client closed connection");
772 freeClient(c);
773 return;
774 }
775 if (nread) {
776 size_t oldlen = sdslen(c->querybuf);
777 c->querybuf = sdscatlen(c->querybuf, buf, nread);
778 c->lastinteraction = time(NULL);
779 /* Scan this new piece of the query for the newline. We do this
780 * here in order to make sure we perform this scan just one time
781 * per piece of buffer, leading to an O(N) scan instead of O(N*N) */
782 if (c->bulklen == -1 && c->newline == NULL)
783 c->newline = strchr(c->querybuf+oldlen,'\n');
784 } else {
785 return;
786 }
787 processInputBuffer(c);
788 }