From 941c9fa2859cc4ce68911a1b5a8f88b53d802f77 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Wed, 13 Oct 2010 11:25:40 +0200 Subject: [PATCH] Return OK on QUIT --- src/networking.c | 7 +++++++ src/redis.c | 10 +++++++--- src/redis.h | 1 + tests/support/redis.tcl | 8 ++++++++ tests/support/server.tcl | 16 ++++++---------- tests/test_helper.tcl | 22 ++++++++++++++++++++++ 6 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/networking.c b/src/networking.c index 632fd047..a1d8f564 100644 --- a/src/networking.c +++ b/src/networking.c @@ -546,6 +546,9 @@ void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) { if (listLength(c->reply) == 0) { c->sentlen = 0; aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE); + + /* Close connection after entire reply has been sent. */ + if (c->flags & REDIS_QUIT) freeClient(c); } } @@ -675,6 +678,10 @@ again: * will try to reiterate. The following line will make it return asap. */ if (c->flags & REDIS_BLOCKED || c->flags & REDIS_IO_WAIT) return; + /* Never continue to process the input buffer after QUIT. After the output + * buffer is flushed (with the OK), the connection will be dropped. */ + if (c->flags & REDIS_QUIT) return; + if (seeknewline && c->bulklen == -1) c->newline = strchr(c->querybuf,'\n'); seeknewline = 1; if (c->bulklen == -1) { diff --git a/src/redis.c b/src/redis.c index 27a855d9..a1ac2a15 100644 --- a/src/redis.c +++ b/src/redis.c @@ -962,10 +962,14 @@ int processCommand(redisClient *c) { } /* -- end of multi bulk commands processing -- */ - /* The QUIT command is handled as a special case. Normal command - * procs are unable to close the client connection safely */ + /* The QUIT command is handled separately. Normal command procs will + * go through checking for replication and QUIT will cause trouble + * when FORCE_REPLICATION is enabled and would be implemented in + * a regular command proc. */ + redisAssert(!(c->flags & REDIS_QUIT)); if (!strcasecmp(c->argv[0]->ptr,"quit")) { - freeClient(c); + c->flags |= REDIS_QUIT; + addReply(c,shared.ok); return 0; } diff --git a/src/redis.h b/src/redis.h index 3e9fc236..e525a99b 100644 --- a/src/redis.h +++ b/src/redis.h @@ -144,6 +144,7 @@ #define REDIS_BLOCKED 16 /* The client is waiting in a blocking operation */ #define REDIS_IO_WAIT 32 /* The client is waiting for Virtual Memory I/O */ #define REDIS_DIRTY_CAS 64 /* Watched keys modified. EXEC will fail. */ +#define REDIS_QUIT 128 /* Client will be disconnected after reply is sent */ /* Slave replication state - slave side */ #define REDIS_REPL_NONE 0 /* No active replication */ diff --git a/tests/support/redis.tcl b/tests/support/redis.tcl index 7c7c65c6..98cf86f0 100644 --- a/tests/support/redis.tcl +++ b/tests/support/redis.tcl @@ -123,6 +123,14 @@ proc ::redis::__method__read {id fd} { ::redis::redis_read_reply $fd } +proc ::redis::__method__write {id fd buf} { + ::redis::redis_write $fd $buf +} + +proc ::redis::__method__flush {id fd} { + flush $fd +} + proc ::redis::__method__close {id fd} { catch {close $fd} catch {unset ::redis::fd($id)} diff --git a/tests/support/server.tcl b/tests/support/server.tcl index e5ca6c6c..1507088e 100644 --- a/tests/support/server.tcl +++ b/tests/support/server.tcl @@ -215,7 +215,8 @@ proc start_server {options {code undefined}} { if {[dict exists $config port]} { set port [dict get $config port] } # setup config dict - dict set srv "config" $config_file + dict set srv "config_file" $config_file + dict set srv "config" $config dict set srv "pid" $pid dict set srv "host" $host dict set srv "port" $port @@ -238,17 +239,12 @@ proc start_server {options {code undefined}} { after 10 } - set client [redis $host $port] - dict set srv "client" $client - - # select the right db when we don't have to authenticate - if {![dict exists $config requirepass]} { - $client select 9 - } - # append the server to the stack lappend ::servers $srv - + + # connect client (after server dict is put on the stack) + reconnect + # execute provided block set curnum $::testnum if {![catch { uplevel 1 $code } err]} { diff --git a/tests/test_helper.tcl b/tests/test_helper.tcl index f427fabc..a6c3e833 100644 --- a/tests/test_helper.tcl +++ b/tests/test_helper.tcl @@ -50,6 +50,28 @@ proc r {args} { [srv $level "client"] {*}$args } +proc reconnect {args} { + set level [lindex $args 0] + if {[string length $level] == 0 || ![string is integer $level]} { + set level 0 + } + + set srv [lindex $::servers end+$level] + set host [dict get $srv "host"] + set port [dict get $srv "port"] + set config [dict get $srv "config"] + set client [redis $host $port] + dict set srv "client" $client + + # select the right db when we don't have to authenticate + if {![dict exists $config "requirepass"]} { + $client select 9 + } + + # re-set $srv in the servers list + set ::servers [lreplace $::servers end+$level 1 $srv] +} + proc redis_deferring_client {args} { set level 0 if {[llength $args] > 0 && [string is integer [lindex $args 0]]} { -- 2.47.2