]>
git.proxmox.com Git - ceph.git/blob - ceph/src/test/common/test_shared_cache.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2013 Cloudwatt <libre.licensing@cloudwatt.com>
8 * Author: Loic Dachary <loic@dachary.org>
9 * Cheng Cheng <ccheng.leo@gmail.com>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library Public License for more details.
25 #include "gtest/gtest.h"
26 #include "common/Thread.h"
27 #include "common/shared_cache.hpp"
29 class SharedLRUTest
: public SharedLRU
<unsigned int, int> {
31 auto& get_lock() { return lock
; }
32 auto& get_cond() { return cond
; }
33 map
<unsigned int, pair
< std::weak_ptr
<int>, int* > > &get_weak_refs() {
38 class SharedLRU_all
: public ::testing::Test
{
41 class Thread_wait
: public Thread
{
46 std::shared_ptr
<int> ptr
;
47 enum in_method_t
{ LOOKUP
, LOWER_BOUND
} in_method
;
49 Thread_wait(SharedLRUTest
& _cache
, unsigned int _key
,
50 int _value
, in_method_t _in_method
) :
54 in_method(_in_method
) { }
56 void * entry() override
{
59 ptr
= cache
.lower_bound(key
);
62 ptr
= std::shared_ptr
<int>(new int);
64 ptr
= cache
.lookup(key
);
71 static const useconds_t DELAY_MAX
= 20 * 1000 * 1000;
72 static useconds_t delay
;
74 bool wait_for(SharedLRUTest
&cache
, int waitting
) {
77 // the delay variable is supposed to be initialized to zero. It would be fine
78 // to usleep(0) but we take this opportunity to test the loop. It will try
79 // again and therefore show that the logic ( increasing the delay ) actually
85 std::lock_guard l
{cache
.get_lock()};
86 if (cache
.waiting
== waitting
) {
91 cout
<< "delay " << delay
<< "us, is not long enough, try again\n";
93 } while ((delay
= delay
* 2 + 1) < DELAY_MAX
);
94 return delay
< DELAY_MAX
;
98 useconds_t
SharedLRU_all::delay
= 0;
100 TEST_F(SharedLRU_all
, add
) {
102 unsigned int key
= 1;
104 bool existed
= false;
106 std::shared_ptr
<int> ptr
= cache
.add(key
, new int(value1
), &existed
);
107 ASSERT_EQ(value1
, *ptr
);
108 ASSERT_FALSE(existed
);
112 auto p
= new int(value2
);
113 std::shared_ptr
<int> ptr
= cache
.add(key
, p
, &existed
);
114 ASSERT_EQ(value1
, *ptr
);
115 ASSERT_TRUE(existed
);
119 TEST_F(SharedLRU_all
, empty
) {
121 unsigned int key
= 1;
122 bool existed
= false;
124 ASSERT_TRUE(cache
.empty());
127 std::shared_ptr
<int> ptr
= cache
.add(key
, new int(value1
), &existed
);
128 ASSERT_EQ(value1
, *ptr
);
129 ASSERT_FALSE(existed
);
131 ASSERT_FALSE(cache
.empty());
134 ASSERT_TRUE(cache
.empty());
137 TEST_F(SharedLRU_all
, lookup
) {
139 unsigned int key
= 1;
142 ASSERT_TRUE(cache
.add(key
, new int(value
)).get());
143 ASSERT_TRUE(cache
.lookup(key
).get());
144 ASSERT_EQ(value
, *cache
.lookup(key
));
146 ASSERT_TRUE(cache
.lookup(key
).get());
148 TEST_F(SharedLRU_all
, lookup_or_create
) {
152 unsigned int key
= 1;
153 ASSERT_TRUE(cache
.add(key
, new int(value
)).get());
154 ASSERT_TRUE(cache
.lookup_or_create(key
).get());
155 ASSERT_EQ(value
, *cache
.lookup(key
));
158 unsigned int key
= 2;
159 ASSERT_TRUE(cache
.lookup_or_create(key
).get());
160 ASSERT_EQ(0, *cache
.lookup(key
));
162 ASSERT_TRUE(cache
.lookup(1).get());
163 ASSERT_TRUE(cache
.lookup(2).get());
166 TEST_F(SharedLRU_all
, wait_lookup
) {
168 unsigned int key
= 1;
172 std::shared_ptr
<int> ptr(new int);
173 cache
.get_weak_refs()[key
] = make_pair(ptr
, &*ptr
);
175 EXPECT_FALSE(cache
.get_weak_refs()[key
].first
.lock());
177 Thread_wait
t(cache
, key
, value
, Thread_wait::LOOKUP
);
178 t
.create("wait_lookup_1");
179 ASSERT_TRUE(wait_for(cache
, 1));
180 EXPECT_EQ(value
, *t
.ptr
);
181 // waiting on a key does not block lookups on other keys
182 EXPECT_FALSE(cache
.lookup(key
+ 12345));
184 std::lock_guard l
{cache
.get_lock()};
185 cache
.get_weak_refs().erase(key
);
186 cache
.get_cond().notify_one();
188 ASSERT_TRUE(wait_for(cache
, 0));
192 TEST_F(SharedLRU_all
, wait_lookup_or_create
) {
194 unsigned int key
= 1;
198 std::shared_ptr
<int> ptr(new int);
199 cache
.get_weak_refs()[key
] = make_pair(ptr
, &*ptr
);
201 EXPECT_FALSE(cache
.get_weak_refs()[key
].first
.lock());
203 Thread_wait
t(cache
, key
, value
, Thread_wait::LOOKUP
);
204 t
.create("wait_lookup_2");
205 ASSERT_TRUE(wait_for(cache
, 1));
206 EXPECT_EQ(value
, *t
.ptr
);
207 // waiting on a key does not block lookups on other keys
208 EXPECT_TRUE(cache
.lookup_or_create(key
+ 12345).get());
210 std::lock_guard l
{cache
.get_lock()};
211 cache
.get_weak_refs().erase(key
);
212 cache
.get_cond().notify_one();
214 ASSERT_TRUE(wait_for(cache
, 0));
219 TEST_F(SharedLRU_all
, lower_bound
) {
223 unsigned int key
= 1;
224 ASSERT_FALSE(cache
.lower_bound(key
));
227 ASSERT_TRUE(cache
.add(key
, new int(value
)).get());
228 ASSERT_TRUE(cache
.lower_bound(key
).get());
229 EXPECT_EQ(value
, *cache
.lower_bound(key
));
233 TEST_F(SharedLRU_all
, wait_lower_bound
) {
235 unsigned int key
= 1;
237 unsigned int other_key
= key
+ 1;
238 int other_value
= value
+ 1;
240 ASSERT_TRUE(cache
.add(other_key
, new int(other_value
)).get());
243 std::shared_ptr
<int> ptr(new int);
244 cache
.get_weak_refs()[key
] = make_pair(ptr
, &*ptr
);
246 EXPECT_FALSE(cache
.get_weak_refs()[key
].first
.lock());
248 Thread_wait
t(cache
, key
, value
, Thread_wait::LOWER_BOUND
);
249 t
.create("wait_lower_bnd");
250 ASSERT_TRUE(wait_for(cache
, 1));
252 // waiting on a key does not block getting lower_bound on other keys
253 EXPECT_TRUE(cache
.lower_bound(other_key
).get());
255 std::lock_guard l
{cache
.get_lock()};
256 cache
.get_weak_refs().erase(key
);
257 cache
.get_cond().notify_one();
259 ASSERT_TRUE(wait_for(cache
, 0));
261 EXPECT_TRUE(t
.ptr
.get());
263 TEST_F(SharedLRU_all
, get_next
) {
267 const unsigned int key
= 0;
268 pair
<unsigned int, int> i
;
269 EXPECT_FALSE(cache
.get_next(key
, &i
));
274 const unsigned int key2
= 333;
275 std::shared_ptr
<int> ptr2
= cache
.lookup_or_create(key2
);
276 const int value2
= *ptr2
= 400;
278 // entries with expired pointers are silently ignored
279 const unsigned int key_gone
= 222;
280 cache
.get_weak_refs()[key_gone
] = make_pair(std::shared_ptr
<int>(), (int*)0);
282 const unsigned int key1
= 111;
283 std::shared_ptr
<int> ptr1
= cache
.lookup_or_create(key1
);
284 const int value1
= *ptr1
= 800;
286 pair
<unsigned int, int> i
;
287 EXPECT_TRUE(cache
.get_next(0, &i
));
288 EXPECT_EQ(key1
, i
.first
);
289 EXPECT_EQ(value1
, i
.second
);
291 EXPECT_TRUE(cache
.get_next(i
.first
, &i
));
292 EXPECT_EQ(key2
, i
.first
);
293 EXPECT_EQ(value2
, i
.second
);
295 EXPECT_FALSE(cache
.get_next(i
.first
, &i
));
297 cache
.get_weak_refs().clear();
301 const unsigned int key1
= 111;
302 std::shared_ptr
<int> *ptr1
= new shared_ptr
<int>(cache
.lookup_or_create(key1
));
303 const unsigned int key2
= 222;
304 std::shared_ptr
<int> ptr2
= cache
.lookup_or_create(key2
);
306 pair
<unsigned int, std::shared_ptr
<int> > i
;
307 EXPECT_TRUE(cache
.get_next(i
.first
, &i
));
308 EXPECT_EQ(key1
, i
.first
);
310 EXPECT_TRUE(cache
.get_next(i
.first
, &i
));
311 EXPECT_EQ(key2
, i
.first
);
315 TEST_F(SharedLRU_all
, clear
) {
317 unsigned int key
= 1;
320 std::shared_ptr
<int> ptr
= cache
.add(key
, new int(value
));
321 ASSERT_EQ(value
, *cache
.lookup(key
));
323 ASSERT_TRUE(cache
.lookup(key
).get());
325 ASSERT_FALSE(cache
.lookup(key
));
328 std::shared_ptr
<int> ptr
= cache
.add(key
, new int(value
));
330 ASSERT_TRUE(cache
.lookup(key
).get());
332 ASSERT_FALSE(cache
.lookup(key
));
334 TEST_F(SharedLRU_all
, clear_all
) {
336 unsigned int key
= 1;
339 std::shared_ptr
<int> ptr
= cache
.add(key
, new int(value
));
340 ASSERT_EQ(value
, *cache
.lookup(key
));
342 ASSERT_TRUE(cache
.lookup(key
).get());
344 ASSERT_FALSE(cache
.lookup(key
));
346 std::shared_ptr
<int> ptr2
= cache
.add(key
, new int(value
));
347 ASSERT_TRUE(cache
.lookup(key
).get());
349 ASSERT_TRUE(cache
.lookup(key
).get());
350 ASSERT_FALSE(cache
.empty());
353 TEST(SharedCache_all
, add
) {
354 SharedLRU
<int, int> cache
;
355 unsigned int key
= 1;
357 std::shared_ptr
<int> ptr
= cache
.add(key
, new int(value
));
358 ASSERT_EQ(ptr
, cache
.lookup(key
));
359 ASSERT_EQ(value
, *cache
.lookup(key
));
362 TEST(SharedCache_all
, lru
) {
363 const size_t SIZE
= 5;
364 SharedLRU
<int, int> cache(NULL
, SIZE
);
366 bool existed
= false;
367 std::shared_ptr
<int> ptr
= cache
.add(0, new int(0), &existed
);
368 ASSERT_FALSE(existed
);
370 int *tmpint
= new int(0);
371 std::shared_ptr
<int> ptr2
= cache
.add(0, tmpint
, &existed
);
372 ASSERT_TRUE(existed
);
375 for (size_t i
= 1; i
< 2*SIZE
; ++i
) {
376 cache
.add(i
, new int(i
), &existed
);
377 ASSERT_FALSE(existed
);
380 ASSERT_TRUE(cache
.lookup(0).get());
381 ASSERT_EQ(0, *cache
.lookup(0));
383 ASSERT_FALSE(cache
.lookup(SIZE
-1));
384 ASSERT_FALSE(cache
.lookup(SIZE
));
385 ASSERT_TRUE(cache
.lookup(SIZE
+1).get());
386 ASSERT_EQ((int)SIZE
+1, *cache
.lookup(SIZE
+1));
389 ASSERT_FALSE(cache
.lookup(0));
390 std::shared_ptr
<int> ptr2
= cache
.add(0, new int(0), &existed
);
391 ASSERT_FALSE(ptr
== ptr2
);
392 ptr
= std::shared_ptr
<int>();
393 ASSERT_TRUE(cache
.lookup(0).get());
397 // compile-command: "cd ../.. ; make unittest_shared_cache && ./unittest_shared_cache # --gtest_filter=*.* --log-to-stderr=true"