Changeset 627

Show
Ignore:
Timestamp:
10/03/07 23:45:44 (1 year ago)
Author:
plindner
Message:

update for prepend operation, thread safe version from Maxim replacing Filipe's implementation

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/server/ChangeLog

    r624 r627  
    1515 
    1616        * Add append command support written by Filipe Laborde. 
    17           Tests/protocol doc updates by Paul Lindner. 
     17          Thread safe version plus prepend command from Maxim Dounin 
     18          <mdounin@mdounin.ru> 
    1819 
    1920        * The memcached-tool script can now display stats.  Patch 
  • trunk/server/doc/protocol.txt

    r620 r627  
    5454There are three types of commands.  
    5555 
    56 Storage commands (there are five: "set", "add", "replace", "append" 
    57 and "cas") ask the server to store some data identified by a key. The 
     56Storage commands (there are six: "set", "add", "replace", "append" 
     57"prepend" and "cas") ask the server to store some data identified by a key. The 
    5858client sends a command line, and then a data block; after that the 
    5959client expects one line of response, which will indicate success or 
     
    127127First, the client sends a command line which looks like this: 
    128128 
    129 <command name> <key> <flags> <exptime> <bytes> [<unqiue>]\r\n 
    130  
    131 - <command name> is "set", "add", "replace", "append", or "cas" 
     129<command name> <key> <flags> <exptime> <bytes> [<cas unqiue>]\r\n 
     130 
     131- <command name> is "set", "add", "replace", "append", "prepend", or "cas" 
    132132 
    133133  "set" means "store this data".   
     
    139139  already hold data for this key". 
    140140 
    141   "append" means "add this data to an existing key". 
     141  "append" means "add this data to an existing key after existing data". 
     142 
     143  "prepend" means "add this data to an existing key before existing data". 
    142144 
    143145  "cas" is a check and set operation which means "store this data but 
     
    166168 
    167169- <cas unique> is a unique 64-bit value of an existing entry. 
     170  Clients should use the value returned from the "gets" command 
     171  when issuing "cas" updates. 
    168172 
    169173After this line, the client sends the data block: 
  • trunk/server/memcached.c

    r624 r627  
    720720    int stored = 0; 
    721721 
     722    item *new_it = NULL; 
     723    int flags; 
     724 
    722725    if (old_it != NULL && comm == NREAD_ADD) { 
    723726        /* add only adds a nonexistent item, but promote to head of LRU */ 
    724727        do_item_update(old_it); 
    725     } else if (!old_it && comm == NREAD_REPLACE) { 
     728    } else if (!old_it && (comm == NREAD_REPLACE 
     729        || comm == NREAD_APPEND || comm == NREAD_PREPEND)) 
     730    { 
    726731        /* replace only replaces an existing value; don't store */ 
    727     } else if (delete_locked && (comm == NREAD_REPLACE || comm == NREAD_ADD)) { 
     732    } else if (delete_locked && (comm == NREAD_REPLACE || comm == NREAD_ADD 
     733        || comm == NREAD_APPEND || comm == NREAD_PREPEND)) 
     734    { 
    728735        /* replace and add can't override delete locks; don't store */ 
    729736    } else { 
     737 
     738        /* 
     739         * Append - combine new and old record into single one. Here it's 
     740         * atomic and thread-safe. 
     741         */ 
     742 
     743        if (comm == NREAD_APPEND || comm == NREAD_PREPEND) { 
     744 
     745            /* we have it and old_it here - alloc memory to hold both */ 
     746            /* flags was already lost - so recover them from ITEM_suffix(it) */ 
     747 
     748            flags = (int) strtol(ITEM_suffix(it), (char **) NULL, 10); 
     749 
     750            new_it = do_item_alloc(key, it->nkey, flags, it->exptime, it->nbytes + old_it->nbytes - 2 /* CRLF */); 
     751 
     752            if (new_it == NULL) { 
     753                /* SERVER_ERROR out of memory */ 
     754                return 0; 
     755            } 
     756 
     757            /* copy data from it and old_it to new_it */ 
     758 
     759            if (comm == NREAD_APPEND) { 
     760                memcpy(ITEM_data(new_it), ITEM_data(old_it), old_it->nbytes); 
     761                memcpy(ITEM_data(new_it) + old_it->nbytes - 2 /* CRLF */, ITEM_data(it), it->nbytes); 
     762            } else { 
     763                /* NREAD_PREPEND */  
     764                memcpy(ITEM_data(new_it), ITEM_data(it), it->nbytes); 
     765                memcpy(ITEM_data(new_it) + it->nbytes - 2 /* CRLF */, ITEM_data(old_it), old_it->nbytes); 
     766            } 
     767 
     768            it = new_it; 
     769        } 
     770 
    730771        /* "set" commands can override the delete lock 
    731772           window... in which case we have to find the old hidden item 
     
    743784    } 
    744785 
    745     if (old_it
     786    if (old_it != NULL
    746787        do_item_remove(old_it);         /* release our reference */ 
     788    if (new_it != NULL) 
     789        do_item_remove(new_it); 
     790 
    747791    return stored; 
    748792} 
     
    12091253    } 
    12101254 
    1211     /* Check if append -- if yes, search for previous entry, and allocate memory for both */ 
    1212     if( comm == NREAD_APPEND ){ 
    1213        old_it = assoc_find(key,nkey); 
    1214  
    1215        if( old_it && (old_it->nbytes)>2 ){ // previous must be more than \r\n 
    1216           old_vlen = old_it->nbytes - 2; 
    1217           vlen += old_vlen;                // append the length of old data 
    1218        } else { 
    1219           comm = NREAD_REPLACE;            // no old entry: treat as replace 
    1220        } 
    1221     } 
    1222  
    12231255    it = item_alloc(key, nkey, flags, realtime(exptime), vlen+2); 
    12241256 
     
    12691301    c->ritem = ITEM_data(it); 
    12701302    c->rlbytes = it->nbytes; 
    1271  
    1272  
    1273     /* If append, prepend old data before new - adjust item, rlbytes variables too 
    1274      * Now that data has been merged, treat simply as a replace command 
    1275      */ 
    1276     if (comm == NREAD_APPEND ){ 
    1277        memcpy( c->ritem, ITEM_data(old_it), old_vlen ); 
    1278        c->ritem += old_vlen; 
    1279        c->rlbytes -= old_vlen; 
    1280        comm = NREAD_REPLACE; 
    1281     } 
    1282  
    12831303    c->item_comm = comm; 
    12841304    conn_set_state(c, conn_nread); 
     
    15151535                (strcmp(tokens[COMMAND_TOKEN].value, "set") == 0 && (comm = NREAD_SET)) || 
    15161536                (strcmp(tokens[COMMAND_TOKEN].value, "replace") == 0 && (comm = NREAD_REPLACE)) || 
     1537                (strcmp(tokens[COMMAND_TOKEN].value, "prepend") == 0 && (comm = NREAD_PREPEND)) || 
    15171538                (strcmp(tokens[COMMAND_TOKEN].value, "append") == 0 && (comm = NREAD_APPEND)) )) { 
    15181539 
  • trunk/server/memcached.h

    r620 r627  
    139139#define NREAD_REPLACE 3 
    140140#define NREAD_APPEND 4 
     141#define NREAD_PREPEND 5 
    141142 
    142143typedef struct {