From: Dong Yuan Date: Wed, 12 Nov 2014 04:08:29 +0000 (+0000) Subject: shared_cache: add lookup_or_create, get_next, etc. and their unittests X-Git-Tag: v0.93~163^2~9 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=d61b1d926cf9d3a7c3f7e7ae79cf16c8d7979e5b;p=ceph.git shared_cache: add lookup_or_create, get_next, etc. and their unittests These method has the same logic as SharePtrRegistry and will be used for ReplicatedPG::object_contexts. Signed-off-by: Dong Yuan --- diff --git a/src/common/shared_cache.hpp b/src/common/shared_cache.hpp index f7a8a74c369..8c24780439f 100644 --- a/src/common/shared_cache.hpp +++ b/src/common/shared_cache.hpp @@ -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 *next) { + pair r; + { + Mutex::Locker l(lock); + VPtr next_val; + typename map >::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 *next) { + pair r; + { + Mutex::Locker l(lock); + VPtr next_val; + typename map >::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 to_release; + { + Mutex::Locker l(lock); + bool retry = false; + do { + retry = false; + typename map >::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 diff --git a/src/test/common/test_shared_cache.cc b/src/test/common/test_shared_cache.cc index 5947051edaa..58853870834 100644 --- a/src/test/common/test_shared_cache.cc +++ b/src/test/common/test_shared_cache.cc @@ -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 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 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 i; + EXPECT_FALSE(cache.get_next(key, &i)); + } + { + SharedLRUTest cache; + + const unsigned int key2 = 333; + shared_ptr 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*)0); + + const unsigned int key1 = 111; + shared_ptr ptr1 = cache.lookup_or_create(key1); + const int value1 = *ptr1 = 800; + + pair 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 *ptr1 = new shared_ptr(cache.lookup_or_create(key1)); + const unsigned int key2 = 222; + shared_ptr ptr2 = cache.lookup_or_create(key2); + + pair > 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 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 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 cache;