[memcached] sgrimm, r439: Fix for flush_all 1-second window bug. Y...

commits at code.sixapart.com commits at code.sixapart.com
Mon Nov 20 22:13:31 UTC 2006


Fix for flush_all 1-second window bug. You can now do a "set" immediately
after a "flush_all" without the newly set data getting expired. (Ported
from trunk.)


U   branches/multithreaded/server/items.c
U   branches/multithreaded/server/memcached.c
U   branches/multithreaded/server/memcached.h
U   branches/multithreaded/server/t/flush-all.t


Modified: branches/multithreaded/server/items.c
===================================================================
--- branches/multithreaded/server/items.c	2006-11-20 22:05:31 UTC (rev 438)
+++ branches/multithreaded/server/items.c	2006-11-20 22:13:30 UTC (rev 439)
@@ -391,3 +391,29 @@
     }
     return it;
 }
+
+/* expires items that are more recent than the oldest_live setting. */
+void item_flush_expired() {
+    int i;
+    item *iter, *next;
+    if (! settings.oldest_live)
+        return;
+    for (i = 0; i < LARGEST_ID; i++) {
+        /* The LRU is sorted in decreasing time order, and an item's timestamp
+         * is never newer than its last access time, so we only need to walk
+         * back until we hit an item older than the oldest_live time.
+         * The oldest_live checking will auto-expire the remaining items.
+         */
+        for (iter = heads[i]; iter != NULL; iter = next) {
+            if (iter->time >= settings.oldest_live) {
+                next = iter->next;
+                if ((iter->it_flags & ITEM_SLABBED) == 0) {
+                    item_unlink(iter);
+                }
+            } else {
+                /* We've hit the first old item. Continue to the next queue. */
+                break;
+            }
+        }
+    }
+}

Modified: branches/multithreaded/server/memcached.c
===================================================================
--- branches/multithreaded/server/memcached.c	2006-11-20 22:05:31 UTC (rev 438)
+++ branches/multithreaded/server/memcached.c	2006-11-20 22:13:30 UTC (rev 439)
@@ -90,11 +90,11 @@
     stats.get_cmds = stats.set_cmds = stats.get_hits = stats.get_misses = 0;
     stats.curr_bytes = stats.bytes_read = stats.bytes_written = 0;
 
-    /* make the time we started always be 1 second before we really
+    /* make the time we started always be 2 seconds before we really
        did, so time(0) - time.started is never zero.  if so, things
        like 'settings.oldest_live' which act as booleans as well as
        values are now false in boolean context... */
-    stats.started = time(0) - 1;
+    stats.started = time(0) - 2;
 }
 
 void stats_reset(void) {
@@ -1323,7 +1323,8 @@
         set_current_time();
 
         if(ntokens == 2) {
-            settings.oldest_live = current_time;
+            settings.oldest_live = current_time - 1;
+            item_flush_expired();
             out_string(c, "OK");
             return;
         }
@@ -1334,7 +1335,8 @@
             return;
         }
 
-        settings.oldest_live = realtime(exptime);
+        settings.oldest_live = realtime(exptime) - 1;
+        item_flush_expired();
         out_string(c, "OK");
         return;
  

Modified: branches/multithreaded/server/memcached.h
===================================================================
--- branches/multithreaded/server/memcached.h	2006-11-20 22:05:31 UTC (rev 438)
+++ branches/multithreaded/server/memcached.h	2006-11-20 22:13:30 UTC (rev 439)
@@ -289,6 +289,7 @@
 item *item_get_notedeleted(char *key, size_t nkey, int *delete_locked);
 item *item_get_nocheck(char *key, size_t nkey);
 item *item_get(char *key, size_t nkey);
+void item_flush_expired(void);
 
 /* time handling */
 void set_current_time ();  /* update the global variable holding

Modified: branches/multithreaded/server/t/flush-all.t
===================================================================
--- branches/multithreaded/server/t/flush-all.t	2006-11-20 22:05:31 UTC (rev 438)
+++ branches/multithreaded/server/t/flush-all.t	2006-11-20 22:13:30 UTC (rev 439)
@@ -1,7 +1,7 @@
 #!/usr/bin/perl
 
 use strict;
-use Test::More tests => 11;
+use Test::More tests => 10;
 use FindBin qw($Bin);
 use lib "$Bin/lib";
 use MemcachedTest;
@@ -16,19 +16,13 @@
 mem_get_is($sock, "foo", "fooval");
 print $sock "flush_all\r\n";
 is(scalar <$sock>, "OK\r\n", "did flush_all");
-
 mem_get_is($sock, "foo", undef);
-SKIP: {
-    skip "flush_all is still only second-granularity.  need atomic counter on flush_all.", 2 unless 0;
 
-    print $sock "set foo 0 0 3\r\nnew\r\n";
-    is(scalar <$sock>, "STORED\r\n", "stored foo = 'new'");
-    mem_get_is($sock, "foo", 'new');
-}
+# check that flush_all doesn't blow away items that immediately get set
+print $sock "set foo 0 0 3\r\nnew\r\n";
+is(scalar <$sock>, "STORED\r\n", "stored foo = 'new'");
+mem_get_is($sock, "foo", 'new');
 
-sleep 1;
-mem_get_is($sock, "foo", undef);
-
 # and the other form, specifying a flush_all time...
 my $expire = time() + 2;
 print $sock "flush_all $expire\r\n";




More information about the memcached-commits mailing list