Changeset 722

Show
Ignore:
Timestamp:
02/25/08 07:55:50 (6 months ago)
Author:
dsallings
Message:

Merged through r712

Conflicts:

server/memcached.h

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/binary/api/perl/ChangeLog

    r605 r722  
     1        * 'noreply' support from Tomash Brechko <tomash.brechko@gmail.com> 
     2 
    13        * various test updates from Ronald J Kimball <rkimball@pangeamedia.com> 
    24 
  • branches/binary/api/perl/lib/Cache/Memcached.pm

    r634 r722  
    336336sub _write_and_read { 
    337337    my Cache::Memcached $self = shift; 
    338     my ($sock, $line, $check_complete) = @_; 
     338    my ($sock, $line, $check_complete, $noreply) = @_; 
    339339    my $res; 
    340340    my ($ret, $offset) = (undef, 0); 
     
    376376            } 
    377377            if ($res == length($line)) { # all sent 
    378                 $state = 1; 
     378                $state = $noreply ? 2 : 1; 
    379379            } else { # we only succeeded in sending some of it 
    380380                substr($line, 0, $res, ''); # delete the part we sent 
     
    411411    return 0 unless $sock; 
    412412 
     413    my @params; 
     414    my $noreply = not defined wantarray; 
     415    push @params, "noreply" if $noreply; 
     416 
    413417    $self->{'stats'}->{"delete"}++; 
    414418    $key = ref $key ? $key->[1] : $key; 
    415419    $time = $time ? " $time" : ""; 
    416     my $cmd = "delete $self->{namespace}$key$time\r\n"; 
    417     my $res = _write_and_read($self, $sock, $cmd); 
     420    my $cmd = "delete $self->{namespace}$key$time @params\r\n"; 
     421    my $res = _write_and_read($self, $sock, $cmd, undef, $noreply); 
    418422 
    419423    if ($self->{'stat_callback'}) { 
     
    447451    return 0 unless $sock; 
    448452 
     453    my @params; 
     454    my $noreply = not defined wantarray; 
     455    push @params, "noreply" if $noreply; 
     456 
    449457    use bytes; # return bytes from length() 
    450458 
     
    478486 
    479487    local $SIG{'PIPE'} = "IGNORE" unless $FLAG_NOSIGNAL; 
    480     my $line = "$cmdname $self->{namespace}$key $flags $exptime $len\r\n$val\r\n"; 
    481  
    482     my $res = _write_and_read($self, $sock, $line); 
     488    my $line = "$cmdname $self->{namespace}$key $flags $exptime $len @params\r\n$val\r\n"; 
     489 
     490    my $res = _write_and_read($self, $sock, $line, undef, $noreply); 
    483491 
    484492    if ($self->{'debug'} && $line) { 
     
    515523    $value = 1 unless defined $value; 
    516524 
    517     my $line = "$cmdname $self->{namespace}$key $value\r\n"; 
    518     my $res = _write_and_read($self, $sock, $line); 
     525    my @params; 
     526    my $noreply = not defined wantarray; 
     527    push @params, "noreply" if $noreply; 
     528 
     529    my $line = "$cmdname $self->{namespace}$key $value @params\r\n"; 
     530    my $res = _write_and_read($self, $sock, $line, undef, $noreply); 
    519531 
    520532    if ($self->{'stat_callback'}) { 
     
    777789sub flush_all { 
    778790    my Cache::Memcached $self = shift; 
     791    my ($time) = @_; 
     792 
     793    $time = 0 unless defined $time; 
    779794 
    780795    my $success = 1; 
    781796 
     797    my @params; 
     798    my $noreply = not defined wantarray; 
     799    push @params, "noreply" if $noreply; 
     800 
    782801    my @hosts = @{$self->{'buckets'}}; 
     802 
     803    # Distribute the delay among the servers.  For instance, if $time 
     804    # is 30 seconds, and we have 3 servers, they will get 30, 15, 0. 
     805    my $delay_step = 0; 
     806    if (@hosts > 1) { 
     807        $delay_step = $time / (@hosts - 1); 
     808    } 
     809 
    783810    foreach my $host (@hosts) { 
     811        my $delay = int($time); 
     812        $time -= $delay_step; 
     813        my $line = "flush_all $delay @params\r\n"; 
    784814        my $sock = $self->sock_to_host($host); 
    785         my @res = $self->run_command($sock, "flush_all\r\n"); 
    786         $success = 0 unless (@res); 
     815        my $res = _write_and_read($self, $sock, $line, undef, $noreply); 
     816        $success = 0 unless ($noreply or $res eq "OK\r\n"); 
    787817    } 
    788818 
     
    791821 
    792822# returns array of lines, or () on failure. 
     823# FIXME: current implementation is broken. 
    793824sub run_command { 
    794825    my Cache::Memcached $self = shift; 
     
    798829    my $line = $cmd; 
    799830    while (my $res = _write_and_read($self, $sock, $line)) { 
     831        # FIXME: _write_and_read() won't handle undefined $line. 
    800832        undef $line; 
    801833        $ret .= $res; 
     834        # FIXME: end condition is not correct. 
    802835        last if $ret =~ /(?:OK|END|ERROR)\r\n$/; 
    803836    } 
  • branches/binary/server/ChangeLog

    r717 r722  
    1 2008-12-17 
     1       * 'noreply' support (Tomash Brechko) 
    22 
    33       * IPv6 support, and IPv6 multi-interface support (brian@tangent.org) 
     
    99 
    1010       * Use gettimeofday(2) instead of time(2). 
    11  
    12 2008-02-10 
    1311 
    1412       * Make -k option work (Tomash Brechko) 
  • branches/binary/server/doc/protocol.txt

    r717 r722  
    127127First, the client sends a command line which looks like this: 
    128128 
    129 <command name> <key> <flags> <exptime> <bytes> [<cas unqiue>]\r\n 
    130  
    131 - <command name> is "set", "add", "replace", "append", "prepend", or "cas" 
     129<command name> <key> <flags> <exptime> <bytes> [noreply]\r\n 
     130cas <key> <flags> <exptime> <bytes> <cas unqiue> [noreply]\r\n 
     131 
     132- <command name> is "set", "add", "replace", "append" or "prepend" 
    132133 
    133134  "set" means "store this data".   
     
    175176  when issuing "cas" updates. 
    176177 
     178- "noreply" optional parameter instructs the server to not send the 
     179  reply.  NOTE: if the request line is malformed, the server can't 
     180  parse "noreply" option reliably.  In this case it may send the error 
     181  to the client, and not reading it on the client side will break 
     182  things.  Client should construct only valid requests. 
     183 
    177184After this line, the client sends the data block: 
    178185 
     
    246253The command "delete" allows for explicit deletion of items: 
    247254 
    248 delete <key> <time>\r\n 
     255delete <key> [<time>] [noreply]\r\n 
    249256 
    250257- <key> is the key of the item the client wishes the server to delete 
     
    262269  storage commands with this key will succeed). 
    263270 
     271- "noreply" optional parameter instructs the server to not send the 
     272  reply.  See the note in Storage commands regarding malformed 
     273  requests. 
     274 
    264275The response line to this command can be one of: 
    265276 
     
    286297The client sends the command line: 
    287298 
    288 incr <key> <value>\r\n 
     299incr <key> <value> [noreply]\r\n 
    289300 
    290301or 
    291302 
    292 decr <key> <value>\r\n 
     303decr <key> <value> [noreply]\r\n 
    293304 
    294305- <key> is the key of the item the client wishes to change 
     
    296307- <value> is the amount by which the client wants to increase/decrease 
    297308the item. It is a decimal representation of a 64-bit unsigned integer. 
     309 
     310- "noreply" optional parameter instructs the server to not send the 
     311  reply.  See the note in Storage commands regarding malformed 
     312  requests. 
    298313 
    299314The response will be one of: 
     
    400415 
    401416"flush_all" is a command with an optional numeric argument. It always 
    402 succeeds, and the server sends "OK\r\n" in response. Its effect is to 
    403 invalidate all existing items immediately (by default) or after the 
    404 expiration specified.  After invalidation none of the items will be returned 
    405 in response to a retrieval command (unless it's stored again under the 
    406 same key *after* flush_all has invalidated the items). flush_all doesn't 
    407 actually free all the memory taken up by existing items; that will 
    408 happen gradually as new items are stored. The most precise definition 
    409 of what flush_all does is the following: it causes all items whose 
    410 update time is earlier than the time at which flush_all was set to be 
    411 executed to be ignored for retrieval purposes. 
     417succeeds, and the server sends "OK\r\n" in response (unless "noreply" 
     418is given as the last parameter). Its effect is to invalidate all 
     419existing items immediately (by default) or after the expiration 
     420specified.  After invalidation none of the items will be returned in 
     421response to a retrieval command (unless it's stored again under the 
     422same key *after* flush_all has invalidated the items). flush_all 
     423doesn't actually free all the memory taken up by existing items; that 
     424will happen gradually as new items are stored. The most precise 
     425definition of what flush_all does is the following: it causes all 
     426items whose update time is earlier than the time at which flush_all 
     427was set to be executed to be ignored for retrieval purposes. 
    412428 
    413429The intent of flush_all with a delay, was that in a setting where you 
     
    432448server. 
    433449 
    434 "verbosity" is a command with a numeric argument. It always                                                   
    435 succeeds, and the server sends "OK\r\n" in response. Its effect is to                                         
    436 set the verbosity level of the logging output.                                                                
     450"verbosity" is a command with a numeric argument. It always succeeds, 
     451and the server sends "OK\r\n" in response (unless "noreply" is given 
     452as the last parameter). Its effect is to set the verbosity level of 
     453the logging output. 
    437454 
    438455"quit" is a command with no arguments: 
  • branches/binary/server/memcached.c

    r721 r722  
    410410    c->gen = 0; 
    411411 
     412    c->noreply = false; 
     413 
    412414    event_set(&c->event, sfd, event_flags, event_handler, (void *)c); 
    413415    event_base_set(base, &c->event); 
     
    791793 
    792794    assert(c != NULL); 
     795 
     796    if (c->noreply) { 
     797        if (settings.verbose > 1) 
     798            fprintf(stderr, ">%d NOREPLY %s\n", c->sfd, str); 
     799        c->noreply = false; 
     800        conn_set_state(c, conn_read); 
     801        return; 
     802    } 
    793803 
    794804    if (settings.verbose > 1) 
     
    14811491#define KEY_MAX_LENGTH 250 
    14821492 
    1483 #define MAX_TOKENS 7 
     1493#define MAX_TOKENS 8 
    14841494 
    14851495/* 
     
    15481558    } else { 
    15491559        out_string(c, "SERVER_ERROR out of memory"); 
     1560    } 
     1561} 
     1562 
     1563static inline void set_noreply_maybe(conn *c, token_t *tokens, size_t ntokens) 
     1564{ 
     1565    int noreply_index = ntokens - 2; 
     1566 
     1567    /* 
     1568      NOTE: this function is not the first place where we are going to 
     1569      send the reply.  We could send it instead from process_command() 
     1570      if the request line has wrong number of tokens.  However parsing 
     1571      malformed line for "noreply" option is not reliable anyway, so 
     1572      it can't be helped. 
     1573    */ 
     1574    if (tokens[noreply_index].value 
     1575        && strcmp(tokens[noreply_index].value, "noreply") == 0) { 
     1576        c->noreply = true; 
    15501577    } 
    15511578} 
     
    19301957    assert(c != NULL); 
    19311958 
     1959    set_noreply_maybe(c, tokens, ntokens); 
     1960 
    19321961    if (tokens[KEY_TOKEN].length > KEY_MAX_LENGTH) { 
    19331962        out_string(c, "CLIENT_ERROR bad command line format"); 
     
    20002029 
    20012030    assert(c != NULL); 
     2031 
     2032    set_noreply_maybe(c, tokens, ntokens); 
    20022033 
    20032034    if(tokens[KEY_TOKEN].length > KEY_MAX_LENGTH) { 
     
    20992130    assert(c != NULL); 
    21002131 
     2132    set_noreply_maybe(c, tokens, ntokens); 
     2133 
    21012134    if (settings.managed) { 
    21022135        int bucket = c->bucket; 
     
    21202153    } 
    21212154 
    2122     if(ntokens == 4) { 
     2155    if(ntokens == (c->noreply ? 5 : 4)) { 
    21232156        exptime = strtol(tokens[2].value, NULL, 10); 
    21242157 
     
    21832216    assert(c != NULL); 
    21842217 
     2218    set_noreply_maybe(c, tokens, ntokens); 
     2219 
    21852220    level = strtoul(tokens[1].value, NULL, 10); 
    21862221    settings.verbose = level > MAX_VERBOSITY_LEVEL ? MAX_VERBOSITY_LEVEL : level; 
     
    22202255        process_get_command(c, tokens, ntokens, false); 
    22212256 
    2222     } else if (ntokens == 6 && 
     2257    } else if ((ntokens == 6 || ntokens == 7) && 
    22232258               ((strcmp(tokens[COMMAND_TOKEN].value, "add") == 0 && (comm = NREAD_ADD)) || 
    22242259                (strcmp(tokens[COMMAND_TOKEN].value, "set") == 0 && (comm = NREAD_SET)) || 
     
    22292264        process_update_command(c, tokens, ntokens, comm, false); 
    22302265 
    2231     } else if (ntokens == 7 && (strcmp(tokens[COMMAND_TOKEN].value, "cas") == 0 && (comm = NREAD_CAS))) { 
     2266    } else if ((ntokens == 7 || ntokens == 8) && (strcmp(tokens[COMMAND_TOKEN].value, "cas") == 0 && (comm = NREAD_CAS))) { 
    22322267 
    22332268        process_update_command(c, tokens, ntokens, comm, true); 
    22342269 
    2235     } else if (ntokens == 4 && (strcmp(tokens[COMMAND_TOKEN].value, "incr") == 0)) { 
     2270    } else if ((ntokens == 4 || ntokens == 5) && (strcmp(tokens[COMMAND_TOKEN].value, "incr") == 0)) { 
    22362271 
    22372272        process_arithmetic_command(c, tokens, ntokens, 1); 
     
    22412276        process_get_command(c, tokens, ntokens, true); 
    22422277 
    2243     } else if (ntokens == 4 && (strcmp(tokens[COMMAND_TOKEN].value, "decr") == 0)) { 
     2278    } else if ((ntokens == 4 || ntokens == 5) && (strcmp(tokens[COMMAND_TOKEN].value, "decr") == 0)) { 
    22442279 
    22452280        process_arithmetic_command(c, tokens, ntokens, 0); 
    22462281 
    2247     } else if (ntokens >= 3 && ntokens <= 4 && (strcmp(tokens[COMMAND_TOKEN].value, "delete") == 0)) { 
     2282    } else if (ntokens >= 3 && ntokens <= 5 && (strcmp(tokens[COMMAND_TOKEN].value, "delete") == 0)) { 
    22482283 
    22492284        process_delete_command(c, tokens, ntokens); 
     
    23142349        process_stat(c, tokens, ntokens); 
    23152350 
    2316     } else if (ntokens >= 2 && ntokens <= 3 && (strcmp(tokens[COMMAND_TOKEN].value, "flush_all") == 0)) { 
     2351    } else if (ntokens >= 2 && ntokens <= 4 && (strcmp(tokens[COMMAND_TOKEN].value, "flush_all") == 0)) { 
    23172352        time_t exptime = 0; 
    23182353        set_current_time(); 
    23192354 
    2320         if(ntokens == 2) { 
     2355        set_noreply_maybe(c, tokens, ntokens); 
     2356 
     2357        if(ntokens == (c->noreply ? 3 : 2)) { 
    23212358            settings.oldest_live = current_time - 1; 
    23222359            item_flush_expired(); 
     
    23832420        out_string(c, "CLIENT_ERROR Slab reassignment not supported"); 
    23842421#endif 
    2385     } else if (ntokens == 3 && (strcmp(tokens[COMMAND_TOKEN].value, "verbosity") == 0)) { 
     2422    } else if ((ntokens == 3 || ntokens == 4) && (strcmp(tokens[COMMAND_TOKEN].value, "verbosity") == 0)) { 
    23862423        process_verbosity_command(c, tokens, ntokens); 
    23872424    } else { 
     
    25162553        if (res == -1) { 
    25172554            if (errno == EAGAIN || errno == EWOULDBLOCK) break; 
    2518             else return 0; 
     2555            /* Should close on unhandled errors. */ 
     2556            conn_set_state(c, conn_closing); 
     2557            return 1; 
    25192558        } 
    25202559    } 
  • branches/binary/server/memcached.h

    r717 r722  
    285285                         a managed instance. -1 (_not_ 0) means invalid. */ 
    286286    int    gen;       /* generation requested for the bucket */ 
    287  
     287    bool   noreply;   /* True if the reply should not be sent. */ 
    288288    /* Binary protocol stuff */ 
    289289    /* This is where the binary header goes */