]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
shared_cache: add lookup_or_create, get_next, etc. and their unittests
authorDong Yuan <yuandong1222@gmail.com>
Wed, 12 Nov 2014 04:08:29 +0000 (04:08 +0000)
committerDong Yuan <yuandong1222@gmail.com>
Thu, 18 Dec 2014 10:52:24 +0000 (10:52 +0000)
These method has the same logic as SharePtrRegistry and will
be used for ReplicatedPG::object_contexts.

Signed-off-by: Dong Yuan <yuandong1222@gmail.com>
src/common/shared_cache.hpp
src/test/common/test_shared_cache.cc

index f7a8a74c369672f7753eecf628696fd596bce80b..8c24780439f990f13f4c77b2b4559d764df1d47f 100644 (file)
@@ -126,6 +126,22 @@ public:
     }
   }
 
+  //clear all strong reference from the lru.
+  void clear() {
+    VPtr val; // release any ref we have after we drop the lock
+    while (size > 0) {
+      Mutex::Locker l(lock);
+      if (size == 0) //check size again with lock
+        break;
+
+      K key = lru.back().first;
+      if (weak_refs.count(key)) {
+       val = weak_refs[key].first.lock();
+      }
+      lru_remove(key);
+    }
+  }
+
   void clear(const K& key) {
     VPtr val; // release any ref we have after we drop the lock
     {
@@ -192,6 +208,48 @@ public:
     }
     return val;
   }
+  bool get_next(const K &key, pair<K, VPtr> *next) {
+    pair<K, VPtr> r;
+    {
+      Mutex::Locker l(lock);
+      VPtr next_val;
+      typename map<K, pair<WeakVPtr, V*> >::iterator i = weak_refs.upper_bound(key);
+
+      while (i != weak_refs.end() &&
+            !(next_val = i->second.first.lock()))
+       ++i;
+
+      if (i == weak_refs.end())
+       return false;
+
+      if (next)
+       r = make_pair(i->first, next_val);
+    }
+    if (next)
+      *next = r;
+    return true;
+  }
+  bool get_next(const K &key, pair<K, V> *next) {
+    pair<K, V> r;
+    {
+      Mutex::Locker l(lock);
+      VPtr next_val;
+      typename map<K, pair<WeakVPtr, V*> >::iterator i = weak_refs.upper_bound(key);
+
+      while (i != weak_refs.end() &&
+            !(next_val = i->second.first.lock()))
+       ++i;
+
+      if (i == weak_refs.end())
+       return false;
+
+      if (next)
+       r = make_pair(i->first, *next_val);
+    }
+    if (next)
+      *next = r;
+    return true;
+  }
 
   VPtr lookup(const K& key) {
     VPtr val;
@@ -218,6 +276,40 @@ public:
     }
     return val;
   }
+  VPtr lookup_or_create(const K &key) {
+    VPtr val;
+    list<VPtr> to_release;
+    {
+      Mutex::Locker l(lock);
+      bool retry = false;
+      do {
+       retry = false;
+       typename map<K, pair<WeakVPtr, V*> >::iterator i = weak_refs.find(key);
+       if (i != weak_refs.end()) {
+         val = i->second.first.lock();
+         if (val) {
+           lru_add(key, val, &to_release);
+           return val;
+         } else {
+           retry = true;
+         }
+       }
+       if (retry)
+         cond.Wait(lock);
+      } while (retry);
+
+      V *new_value = new V();
+      VPtr new_val(new_value, Cleanup(this, key));
+      weak_refs.insert(make_pair(key, make_pair(new_val, new_value)));
+      lru_add(key, new_val, &to_release);
+      return new_val;
+    }
+  }
+
+  bool empty() {
+    Mutex::Locker l(lock);
+    return contents.empty();
+  }
 
   /***
    * Inserts a key if not present, or bumps it to the front of the LRU if
index 5947051edaa6b2516913af6397dfa4802286a55b..58853870834679432e9016cb080a54cb06fdd411 100644 (file)
@@ -118,6 +118,23 @@ TEST_F(SharedLRU_all, add) {
     ASSERT_TRUE(existed);
   }
 }
+TEST_F(SharedLRU_all, empty) {
+  SharedLRUTest cache;
+  unsigned int key = 1;
+  int value1 = 2;
+  bool existed = false;
+
+  ASSERT_TRUE(cache.empty());
+  {
+    shared_ptr<int> ptr = cache.add(key, new int(value1), &existed);
+    ASSERT_EQ(value1, *ptr);
+    ASSERT_FALSE(existed);
+  }
+  ASSERT_FALSE(cache.empty());
+
+  cache.clear(key);
+  ASSERT_TRUE(cache.empty());
+}
 
 TEST_F(SharedLRU_all, lookup) {
   SharedLRUTest cache;
@@ -130,6 +147,23 @@ TEST_F(SharedLRU_all, lookup) {
   }
   ASSERT_TRUE(cache.lookup(key));
 }
+TEST_F(SharedLRU_all, lookup_or_create) {
+  SharedLRUTest cache;
+  {
+    int value = 2;
+    unsigned int key = 1;
+    ASSERT_TRUE(cache.add(key, new int(value)));
+    ASSERT_TRUE(cache.lookup_or_create(key));
+    ASSERT_EQ(value, *cache.lookup(key));
+  }
+  {
+    unsigned int key = 2;
+    ASSERT_TRUE(cache.lookup_or_create(key));
+    ASSERT_EQ(0, *cache.lookup(key));
+  }
+  ASSERT_TRUE(cache.lookup(1));
+  ASSERT_TRUE(cache.lookup(2));
+}
 
 TEST_F(SharedLRU_all, wait_lookup) {
   SharedLRUTest cache;
@@ -157,6 +191,32 @@ TEST_F(SharedLRU_all, wait_lookup) {
   t.join();
   EXPECT_FALSE(t.ptr);
 }
+TEST_F(SharedLRU_all, wait_lookup_or_create) {
+  SharedLRUTest cache;
+  unsigned int key = 1;
+  int value = 2;
+
+  {
+    shared_ptr<int> ptr(new int);
+    cache.get_weak_refs()[key] = make_pair(ptr, &*ptr);
+  }
+  EXPECT_FALSE(cache.get_weak_refs()[key].first.lock());
+
+  Thread_wait t(cache, key, value, Thread_wait::LOOKUP);
+  t.create();
+  ASSERT_TRUE(wait_for(cache, 1));
+  EXPECT_EQ(value, *t.ptr);
+  // waiting on a key does not block lookups on other keys
+  EXPECT_TRUE(cache.lookup_or_create(key + 12345));
+  {
+    Mutex::Locker l(cache.get_lock());
+    cache.get_weak_refs().erase(key);
+    cache.get_cond().Signal();
+  }
+  ASSERT_TRUE(wait_for(cache, 0));
+  t.join();
+  EXPECT_FALSE(t.ptr);
+}
 
 TEST_F(SharedLRU_all, lower_bound) {
   SharedLRUTest cache;
@@ -202,6 +262,57 @@ TEST_F(SharedLRU_all, wait_lower_bound) {
   t.join();
   EXPECT_TRUE(t.ptr);
 }
+TEST_F(SharedLRU_all, get_next) {
+
+  {
+    SharedLRUTest cache;
+    const unsigned int key = 0;
+    pair<unsigned int, int> i;
+    EXPECT_FALSE(cache.get_next(key, &i));
+  }
+  {
+    SharedLRUTest cache;
+
+    const unsigned int key2 = 333;
+    shared_ptr<int> ptr2 = cache.lookup_or_create(key2);
+    const int value2 = *ptr2 = 400;
+
+    // entries with expired pointers are silently ignored
+    const unsigned int key_gone = 222;
+    cache.get_weak_refs()[key_gone] = make_pair(shared_ptr<int>(), (int*)0);
+
+    const unsigned int key1 = 111;
+    shared_ptr<int> ptr1 = cache.lookup_or_create(key1);
+    const int value1 = *ptr1 = 800;
+
+    pair<unsigned int, int> i;
+    EXPECT_TRUE(cache.get_next(i.first, &i));
+    EXPECT_EQ(key1, i.first);
+    EXPECT_EQ(value1, i.second);
+
+    EXPECT_TRUE(cache.get_next(i.first, &i));
+    EXPECT_EQ(key2, i.first);
+    EXPECT_EQ(value2, i.second);
+
+    EXPECT_FALSE(cache.get_next(i.first, &i));
+
+    cache.get_weak_refs().clear();
+  }
+  {
+    SharedLRUTest cache;
+    const unsigned int key1 = 111;
+    shared_ptr<int> *ptr1 = new shared_ptr<int>(cache.lookup_or_create(key1));
+    const unsigned int key2 = 222;
+    shared_ptr<int> ptr2 = cache.lookup_or_create(key2);
+
+    pair<unsigned int, shared_ptr<int> > i;
+    EXPECT_TRUE(cache.get_next(i.first, &i));
+    EXPECT_EQ(key1, i.first);
+    delete ptr1;
+    EXPECT_TRUE(cache.get_next(i.first, &i));
+    EXPECT_EQ(key2, i.first);
+  }
+}
 
 TEST_F(SharedLRU_all, clear) {
   SharedLRUTest cache;
@@ -222,6 +333,24 @@ TEST_F(SharedLRU_all, clear) {
   cache.clear(key);
   ASSERT_FALSE(cache.lookup(key));
 }
+TEST_F(SharedLRU_all, clear_all) {
+  SharedLRUTest cache;
+  unsigned int key = 1;
+  int value = 2;
+  {
+    ceph::shared_ptr<int> ptr = cache.add(key, new int(value));
+    ASSERT_EQ(value, *cache.lookup(key));
+  }
+  ASSERT_TRUE(cache.lookup(key));
+  cache.clear();
+  ASSERT_FALSE(cache.lookup(key));
+
+  ceph::shared_ptr<int> ptr2 = cache.add(key, new int(value));
+  ASSERT_TRUE(cache.lookup(key));
+  cache.clear();
+  ASSERT_TRUE(cache.lookup(key));
+  ASSERT_FALSE(cache.empty());
+}
 
 TEST(SharedCache_all, add) {
   SharedLRU<int, int> cache;