comparison memcached.c @ 2:e28ab6bd21fa

Append/prepend commands. Introduce new storage commands "append" and "prepend" for atomic value modification. They follow generic storage commands interface as described in doc/protocol.txt: <command name> <key> <flags> <exptime> <bytes>\r\n <data block>\r\n Current implementation involves memcpy() twice to combine values on writing (i.e. full resulting value are copied), but truly atomic (and even threadsafe).
author Maxim Dounin <mdounin@mdounin.ru>
date Sun, 30 Sep 2007 04:14:57 +0400
parents 30782bb1fc04
children 0b6ac95a09bb
comparison
equal deleted inserted replaced
1:7ba3a424d509 2:e28ab6bd21fa
715 char *key = ITEM_key(it); 715 char *key = ITEM_key(it);
716 bool delete_locked = false; 716 bool delete_locked = false;
717 item *old_it = do_item_get_notedeleted(key, it->nkey, &delete_locked); 717 item *old_it = do_item_get_notedeleted(key, it->nkey, &delete_locked);
718 int stored = 0; 718 int stored = 0;
719 719
720 item *new_it = NULL;
721 int flags;
722
720 if (old_it != NULL && comm == NREAD_ADD) { 723 if (old_it != NULL && comm == NREAD_ADD) {
721 /* add only adds a nonexistent item, but promote to head of LRU */ 724 /* add only adds a nonexistent item, but promote to head of LRU */
722 do_item_update(old_it); 725 do_item_update(old_it);
723 } else if (!old_it && comm == NREAD_REPLACE) { 726 } else if (!old_it && (comm == NREAD_REPLACE
727 || comm == NREAD_APPEND || comm == NREAD_PREPEND))
728 {
724 /* replace only replaces an existing value; don't store */ 729 /* replace only replaces an existing value; don't store */
725 } else if (delete_locked && (comm == NREAD_REPLACE || comm == NREAD_ADD)) { 730 } else if (delete_locked && (comm == NREAD_REPLACE || comm == NREAD_ADD
731 || comm == NREAD_APPEND || comm == NREAD_PREPEND))
732 {
726 /* replace and add can't override delete locks; don't store */ 733 /* replace and add can't override delete locks; don't store */
727 } else { 734 } else {
735
736 /*
737 * Append - combine new and old record into single one. Here it's
738 * atomic and thread-safe.
739 */
740
741 if (comm == NREAD_APPEND || comm == NREAD_PREPEND) {
742
743 /* we have it and old_it here - alloc memory to hold both */
744 /* flags was already lost - so recover them from ITEM_suffix(it) */
745
746 flags = (int) strtol(ITEM_suffix(it), (char **) NULL, 10);
747
748 new_it = do_item_alloc(key, it->nkey, flags, it->exptime, it->nbytes + old_it->nbytes - 2 /* CRLF */);
749
750 if (new_it == NULL) {
751 /* SERVER_ERROR out of memory */
752 return 0;
753 }
754
755 /* copy data from it and old_it to new_it */
756
757 if (comm == NREAD_APPEND) {
758 memcpy(ITEM_data(new_it), ITEM_data(old_it), old_it->nbytes);
759 memcpy(ITEM_data(new_it) + old_it->nbytes - 2 /* CRLF */, ITEM_data(it), it->nbytes);
760 } else {
761 /* NREAD_PREPEND */
762 memcpy(ITEM_data(new_it), ITEM_data(it), it->nbytes);
763 memcpy(ITEM_data(new_it) + it->nbytes - 2 /* CRLF */, ITEM_data(old_it), old_it->nbytes);
764 }
765
766 it = new_it;
767 }
768
728 /* "set" commands can override the delete lock 769 /* "set" commands can override the delete lock
729 window... in which case we have to find the old hidden item 770 window... in which case we have to find the old hidden item
730 that's in the namespace/LRU but wasn't returned by 771 that's in the namespace/LRU but wasn't returned by
731 item_get.... because we need to replace it */ 772 item_get.... because we need to replace it */
732 if (delete_locked) 773 if (delete_locked)
740 stored = 1; 781 stored = 1;
741 } 782 }
742 783
743 if (old_it) 784 if (old_it)
744 do_item_remove(old_it); /* release our reference */ 785 do_item_remove(old_it); /* release our reference */
786 if (new_it)
787 do_item_remove(new_it);
788
745 return stored; 789 return stored;
746 } 790 }
747 791
748 typedef struct token_s { 792 typedef struct token_s {
749 char *value; 793 char *value;
1454 process_get_command(c, tokens, ntokens); 1498 process_get_command(c, tokens, ntokens);
1455 1499
1456 } else if (ntokens == 6 && 1500 } else if (ntokens == 6 &&
1457 ((strcmp(tokens[COMMAND_TOKEN].value, "add") == 0 && (comm = NREAD_ADD)) || 1501 ((strcmp(tokens[COMMAND_TOKEN].value, "add") == 0 && (comm = NREAD_ADD)) ||
1458 (strcmp(tokens[COMMAND_TOKEN].value, "set") == 0 && (comm = NREAD_SET)) || 1502 (strcmp(tokens[COMMAND_TOKEN].value, "set") == 0 && (comm = NREAD_SET)) ||
1503 (strcmp(tokens[COMMAND_TOKEN].value, "append") == 0 && (comm = NREAD_APPEND)) ||
1504 (strcmp(tokens[COMMAND_TOKEN].value, "prepend") == 0 && (comm = NREAD_PREPEND)) ||
1459 (strcmp(tokens[COMMAND_TOKEN].value, "replace") == 0 && (comm = NREAD_REPLACE)))) { 1505 (strcmp(tokens[COMMAND_TOKEN].value, "replace") == 0 && (comm = NREAD_REPLACE)))) {
1460 1506
1461 process_update_command(c, tokens, ntokens, comm); 1507 process_update_command(c, tokens, ntokens, comm);
1462 1508
1463 } else if (ntokens == 4 && (strcmp(tokens[COMMAND_TOKEN].value, "incr") == 0)) { 1509 } else if (ntokens == 4 && (strcmp(tokens[COMMAND_TOKEN].value, "incr") == 0)) {