[patch] test command

Jacob Coby jcoby at listingbook.com
Tue Feb 15 14:43:04 PST 2005


It seems like it would be nice to be able to test to see if a key is 
cached, its flags, how big the data is, and when it expires.  I needed 
the extension to make memcached compatible with our current caching system.

I've attached a patch -u against 1.1.11 to add the "test" command.  A 
typical "test" response looks something like:

test key [key [...]]
foreach key
on success, print "EXISTS flag size expires"
on failure, print nothing (behavior similar to the "get" command")
print END

set foo 0 600 1
1
STORED
get foo
VALUE foo 0 1
1
END
test foo
EXISTS foo 0 1 1108506400
END
quit

The patch is mostly feature complete, but I expect it to need some 
formatting, a protocol version bump, and a nod to me if included ;). 
Stats could also use cmd_test, test_hits, test_misses added.  I can add 
the stats entries no problem if there is interest in this patch.

-- 
-Jacob
-------------- next part --------------
diff -u memcached-1.1.11/memcached.c memcached-1.1.12/memcached.c
--- memcached-1.1.11/memcached.c	Mon Apr 26 17:26:48 2004
+++ memcached-1.1.12/memcached.c	Tue Feb 15 17:16:07 2005
@@ -667,7 +667,60 @@
         out_string(c, "DELETED");
         return;
     }
-        
+
+    if (strncmp(command, "test ", 5) == 0) {
+
+        char *start = command + 4;
+        char key[251];
+        int next;
+        int i = 0;
+        item *it;
+        time_t now = time(0);
+
+        while(sscanf(start, " %250s%n", key, &next) >= 1) {
+            start+=next;
+            stats.get_cmds++;
+            it = assoc_find(key);
+            if (it && (it->it_flags & ITEM_DELETED)) {
+                it = 0;
+            }
+            if (settings.oldest_live && it && 
+                it->time <= settings.oldest_live) {
+                it = 0;
+            }
+            if (it && it->exptime && it->exptime < now) {
+                item_unlink(it);
+                it = 0;
+            }
+
+            if (it) {
+                stats.get_hits++;
+                it->refcount++;
+                item_update(it);
+                *(c->ilist + i) = it;
+                i++;
+                if (i > c->isize) {
+                    c->isize *= 2;
+                    c->ilist = realloc(c->ilist, sizeof(item *)*c->isize);
+                }
+            } else stats.get_misses++;
+        }
+        c->icurr = c->ilist;
+        c->ileft = i;
+	c->item_comm = NREAD_TEST;
+
+        if (c->ileft) {
+            c->ipart = 0;
+            c->state = conn_mwrite;
+            c->ibytes = 0;
+            return;
+        } else {
+            out_string(c, "END");
+            return;
+        }
+    }
+
+       
     if (strncmp(command, "stats", 5) == 0) {
         process_stat(c, command);
         return;
@@ -1014,14 +1067,17 @@
                 item *it;
                 /* we finished a chunk, decide what to do next */
                 switch (c->ipart) {
-                case 1:
+                case 1: /* write out the item data chunk */
                     it = *(c->icurr);
                     assert((it->it_flags & ITEM_SLABBED) == 0);
-                    c->iptr = ITEM_data(it);
-                    c->ibytes = it->nbytes;
+		    /* if we're not in TEST mode, write out the item's data */
+		    if(c->item_comm != NREAD_TEST) {
+                        c->iptr = ITEM_data(it);
+                        c->ibytes = it->nbytes;
+		    }
                     c->ipart = 2;
                     break;
-                case 2:
+                case 2: /* pop the written item off of the list */
                     it = *(c->icurr);
                     item_remove(it);
                     c->ileft--;
@@ -1032,17 +1088,21 @@
                         c->icurr++;
                     }
                     /* FALL THROUGH */
-                case 0:
+                case 0: /* generate the header chunk */
                     it = *(c->icurr);
                     assert((it->it_flags & ITEM_SLABBED) == 0);
-                    sprintf(c->ibuf, "VALUE %s %u %u\r\n", ITEM_key(it), it->flags, it->nbytes - 2);
-                    if (settings.verbose > 1)
+		    if(c->item_comm == NREAD_TEST)
+                        sprintf(c->ibuf, "EXISTS %s %u %u %u\r\n", ITEM_key(it), it->flags, it->nbytes - 2, it->exptime);
+		    else
+                        sprintf(c->ibuf, "VALUE %s %u %u\r\n", ITEM_key(it), it->flags, it->nbytes - 2);
+ 
+ 		    if (settings.verbose > 1)
                         fprintf(stderr, ">%d sending key %s\n", c->sfd, ITEM_key(it));
                     c->iptr = c->ibuf;
                     c->ibytes = strlen(c->iptr);
                     c->ipart = 1;
                     break;
-                case 3:
+                case 3: /* end of list */
                     out_string(c, "END");
                     break;
                 }
diff -u memcached-1.1.11/memcached.h memcached-1.1.12/memcached.h
--- memcached-1.1.11/memcached.h	Mon Apr 26 17:26:48 2004
+++ memcached-1.1.12/memcached.h	Tue Feb 15 17:09:10 2005
@@ -77,6 +77,7 @@
 #define NREAD_ADD 1
 #define NREAD_SET 2
 #define NREAD_REPLACE 3
+#define NREAD_TEST 4
 
 typedef struct {
     int    sfd;


More information about the memcached mailing list