Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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
3 /*
4  * Ceph - scalable distributed file system
5  *
6  * Copyright (C) 2013 Cloudwatt <libre.licensing@cloudwatt.com>
7  *
8  * Author: Loic Dachary <loic@dachary.org>
9  *         Cheng Cheng <ccheng.leo@gmail.com>
10  *
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)
14  * any later version.
15  *
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.
20  *
21  */
22
23 #include <stdio.h>
24 #include <signal.h>
25 #include "gtest/gtest.h"
26 #include "common/Thread.h"
27 #include "common/shared_cache.hpp"
28
29 class SharedLRUTest : public SharedLRU<unsigned int, int> {
30 public:
31   Mutex &get_lock() { return lock; }
32   Cond &get_cond() { return cond; }
33   map<unsigned int, pair< ceph::weak_ptr<int>, int* > > &get_weak_refs() {
34     return weak_refs;
35   }
36 };
37
38 class SharedLRU_all : public ::testing::Test {
39 public:
40
41   class Thread_wait : public Thread {
42   public:
43     SharedLRUTest &cache;
44     unsigned int key;
45     int value;
46     ceph::shared_ptr<int> ptr;
47     enum in_method_t { LOOKUP, LOWER_BOUND } in_method;
48
49     Thread_wait(SharedLRUTest& _cache, unsigned int _key, 
50                 int _value, in_method_t _in_method) :
51       cache(_cache),
52       key(_key),
53       value(_value),
54       in_method(_in_method) { }
55
56     void * entry() override {
57       switch (in_method) {
58       case LOWER_BOUND:
59         ptr = cache.lower_bound(key);
60         break;
61       case LOOKUP:
62         ptr = ceph::shared_ptr<int>(new int);
63         *ptr = value;
64         ptr = cache.lookup(key);
65         break;
66       }
67       return NULL;
68     }
69   };
70
71   static const useconds_t DELAY_MAX = 20 * 1000 * 1000;
72   static useconds_t delay;
73
74   bool wait_for(SharedLRUTest &cache, int waitting) {
75     do {
76       //
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
80       // works. 
81       //
82       if (delay > 0)
83         usleep(delay);
84       {
85         Mutex::Locker l(cache.get_lock());
86         if (cache.waiting == waitting) {
87           break;
88         }
89       }
90       if (delay > 0) {
91         cout << "delay " << delay << "us, is not long enough, try again\n";
92       }
93     } while ((delay = delay * 2 + 1) < DELAY_MAX); 
94     return delay < DELAY_MAX;
95   }
96 };
97
98 useconds_t SharedLRU_all::delay = 0;
99
100 TEST_F(SharedLRU_all, add) {
101   SharedLRUTest cache;
102   unsigned int key = 1;
103   int value1 = 2;
104   bool existed = false;
105   {
106     ceph::shared_ptr<int> ptr = cache.add(key, new int(value1), &existed);
107     ASSERT_EQ(value1, *ptr);
108     ASSERT_FALSE(existed);
109   }
110   {
111     int value2 = 3;
112     ceph::shared_ptr<int> ptr = cache.add(key, new int(value2), &existed);
113     ASSERT_EQ(value1, *ptr);
114     ASSERT_TRUE(existed);
115   }
116 }
117 TEST_F(SharedLRU_all, empty) {
118   SharedLRUTest cache;
119   unsigned int key = 1;
120   bool existed = false;
121
122   ASSERT_TRUE(cache.empty());
123   {
124     int value1 = 2;
125     ceph::shared_ptr<int> ptr = cache.add(key, new int(value1), &existed);
126     ASSERT_EQ(value1, *ptr);
127     ASSERT_FALSE(existed);
128   }
129   ASSERT_FALSE(cache.empty());
130
131   cache.clear(key);
132   ASSERT_TRUE(cache.empty());
133 }
134
135 TEST_F(SharedLRU_all, lookup) {
136   SharedLRUTest cache;
137   unsigned int key = 1;
138   {
139     int value = 2;
140     ASSERT_TRUE(cache.add(key, new int(value)).get());
141     ASSERT_TRUE(cache.lookup(key).get());
142     ASSERT_EQ(value, *cache.lookup(key));
143   }
144   ASSERT_TRUE(cache.lookup(key).get());
145 }
146 TEST_F(SharedLRU_all, lookup_or_create) {
147   SharedLRUTest cache;
148   {
149     int value = 2;
150     unsigned int key = 1;
151     ASSERT_TRUE(cache.add(key, new int(value)).get());
152     ASSERT_TRUE(cache.lookup_or_create(key).get());
153     ASSERT_EQ(value, *cache.lookup(key));
154   }
155   {
156     unsigned int key = 2;
157     ASSERT_TRUE(cache.lookup_or_create(key).get());
158     ASSERT_EQ(0, *cache.lookup(key));
159   }
160   ASSERT_TRUE(cache.lookup(1).get());
161   ASSERT_TRUE(cache.lookup(2).get());
162 }
163
164 TEST_F(SharedLRU_all, wait_lookup) {
165   SharedLRUTest cache;
166   unsigned int key = 1;
167   int value = 2;
168
169   {
170     ceph::shared_ptr<int> ptr(new int);
171     cache.get_weak_refs()[key] = make_pair(ptr, &*ptr);
172   }
173   EXPECT_FALSE(cache.get_weak_refs()[key].first.lock());
174
175   Thread_wait t(cache, key, value, Thread_wait::LOOKUP);
176   t.create("wait_lookup_1");
177   ASSERT_TRUE(wait_for(cache, 1));
178   EXPECT_EQ(value, *t.ptr);
179   // waiting on a key does not block lookups on other keys
180   EXPECT_FALSE(cache.lookup(key + 12345));
181   {
182     Mutex::Locker l(cache.get_lock());
183     cache.get_weak_refs().erase(key);
184     cache.get_cond().Signal();
185   }
186   ASSERT_TRUE(wait_for(cache, 0));
187   t.join();
188   EXPECT_FALSE(t.ptr);
189 }
190 TEST_F(SharedLRU_all, wait_lookup_or_create) {
191   SharedLRUTest cache;
192   unsigned int key = 1;
193   int value = 2;
194
195   {
196     ceph::shared_ptr<int> ptr(new int);
197     cache.get_weak_refs()[key] = make_pair(ptr, &*ptr);
198   }
199   EXPECT_FALSE(cache.get_weak_refs()[key].first.lock());
200
201   Thread_wait t(cache, key, value, Thread_wait::LOOKUP);
202   t.create("wait_lookup_2");
203   ASSERT_TRUE(wait_for(cache, 1));
204   EXPECT_EQ(value, *t.ptr);
205   // waiting on a key does not block lookups on other keys
206   EXPECT_TRUE(cache.lookup_or_create(key + 12345).get());
207   {
208     Mutex::Locker l(cache.get_lock());
209     cache.get_weak_refs().erase(key);
210     cache.get_cond().Signal();
211   }
212   ASSERT_TRUE(wait_for(cache, 0));
213   t.join();
214   EXPECT_FALSE(t.ptr);
215 }
216
217 TEST_F(SharedLRU_all, lower_bound) {
218   SharedLRUTest cache;
219
220   {
221     unsigned int key = 1;
222     ASSERT_FALSE(cache.lower_bound(key));
223     int value = 2;
224
225     ASSERT_TRUE(cache.add(key, new int(value)).get());
226     ASSERT_TRUE(cache.lower_bound(key).get());
227     EXPECT_EQ(value, *cache.lower_bound(key));
228   }
229 }
230
231 TEST_F(SharedLRU_all, wait_lower_bound) {
232   SharedLRUTest cache;
233   unsigned int key = 1;
234   int value = 2;
235   unsigned int other_key = key + 1;
236   int other_value = value + 1;
237
238   ASSERT_TRUE(cache.add(other_key, new int(other_value)).get());
239
240   {
241     ceph::shared_ptr<int> ptr(new int);
242     cache.get_weak_refs()[key] = make_pair(ptr, &*ptr);
243   }
244   EXPECT_FALSE(cache.get_weak_refs()[key].first.lock());
245
246   Thread_wait t(cache, key, value, Thread_wait::LOWER_BOUND);
247   t.create("wait_lower_bnd");
248   ASSERT_TRUE(wait_for(cache, 1));
249   EXPECT_FALSE(t.ptr);
250   // waiting on a key does not block getting lower_bound on other keys
251   EXPECT_TRUE(cache.lower_bound(other_key).get());
252   {
253     Mutex::Locker l(cache.get_lock());
254     cache.get_weak_refs().erase(key);
255     cache.get_cond().Signal();
256   }
257   ASSERT_TRUE(wait_for(cache, 0));
258   t.join();
259   EXPECT_TRUE(t.ptr.get());
260 }
261 TEST_F(SharedLRU_all, get_next) {
262
263   {
264     SharedLRUTest cache;
265     const unsigned int key = 0;
266     pair<unsigned int, int> i;
267     EXPECT_FALSE(cache.get_next(key, &i));
268   }
269   {
270     SharedLRUTest cache;
271
272     const unsigned int key2 = 333;
273     ceph::shared_ptr<int> ptr2 = cache.lookup_or_create(key2);
274     const int value2 = *ptr2 = 400;
275
276     // entries with expired pointers are silently ignored
277     const unsigned int key_gone = 222;
278     cache.get_weak_refs()[key_gone] = make_pair(ceph::shared_ptr<int>(), (int*)0);
279
280     const unsigned int key1 = 111;
281     ceph::shared_ptr<int> ptr1 = cache.lookup_or_create(key1);
282     const int value1 = *ptr1 = 800;
283
284     pair<unsigned int, int> i;
285     EXPECT_TRUE(cache.get_next(0, &i));
286     EXPECT_EQ(key1, i.first);
287     EXPECT_EQ(value1, i.second);
288
289     EXPECT_TRUE(cache.get_next(i.first, &i));
290     EXPECT_EQ(key2, i.first);
291     EXPECT_EQ(value2, i.second);
292
293     EXPECT_FALSE(cache.get_next(i.first, &i));
294
295     cache.get_weak_refs().clear();
296   }
297   {
298     SharedLRUTest cache;
299     const unsigned int key1 = 111;
300     ceph::shared_ptr<int> *ptr1 = new shared_ptr<int>(cache.lookup_or_create(key1));
301     const unsigned int key2 = 222;
302     ceph::shared_ptr<int> ptr2 = cache.lookup_or_create(key2);
303
304     pair<unsigned int, ceph::shared_ptr<int> > i;
305     EXPECT_TRUE(cache.get_next(i.first, &i));
306     EXPECT_EQ(key1, i.first);
307     delete ptr1;
308     EXPECT_TRUE(cache.get_next(i.first, &i));
309     EXPECT_EQ(key2, i.first);
310   }
311 }
312
313 TEST_F(SharedLRU_all, clear) {
314   SharedLRUTest cache;
315   unsigned int key = 1;
316   int value = 2;
317   {
318     ceph::shared_ptr<int> ptr = cache.add(key, new int(value));
319     ASSERT_EQ(value, *cache.lookup(key));
320   }
321   ASSERT_TRUE(cache.lookup(key).get());
322   cache.clear(key);
323   ASSERT_FALSE(cache.lookup(key));
324
325   {
326     ceph::shared_ptr<int> ptr = cache.add(key, new int(value));
327   }
328   ASSERT_TRUE(cache.lookup(key).get());
329   cache.clear(key);
330   ASSERT_FALSE(cache.lookup(key));
331 }
332 TEST_F(SharedLRU_all, clear_all) {
333   SharedLRUTest cache;
334   unsigned int key = 1;
335   int value = 2;
336   {
337     ceph::shared_ptr<int> ptr = cache.add(key, new int(value));
338     ASSERT_EQ(value, *cache.lookup(key));
339   }
340   ASSERT_TRUE(cache.lookup(key).get());
341   cache.clear();
342   ASSERT_FALSE(cache.lookup(key));
343
344   ceph::shared_ptr<int> ptr2 = cache.add(key, new int(value));
345   ASSERT_TRUE(cache.lookup(key).get());
346   cache.clear();
347   ASSERT_TRUE(cache.lookup(key).get());
348   ASSERT_FALSE(cache.empty());
349 }
350
351 TEST(SharedCache_all, add) {
352   SharedLRU<int, int> cache;
353   unsigned int key = 1;
354   int value = 2;
355   ceph::shared_ptr<int> ptr = cache.add(key, new int(value));
356   ASSERT_EQ(ptr, cache.lookup(key));
357   ASSERT_EQ(value, *cache.lookup(key));
358 }
359
360 TEST(SharedCache_all, lru) {
361   const size_t SIZE = 5;
362   SharedLRU<int, int> cache(NULL, SIZE);
363
364   bool existed = false;
365   ceph::shared_ptr<int> ptr = cache.add(0, new int(0), &existed);
366   ASSERT_FALSE(existed);
367   {
368     int *tmpint = new int(0);
369     ceph::shared_ptr<int> ptr2 = cache.add(0, tmpint, &existed);
370     ASSERT_TRUE(existed);
371     delete tmpint;
372   }
373   for (size_t i = 1; i < 2*SIZE; ++i) {
374     cache.add(i, new int(i), &existed);
375     ASSERT_FALSE(existed);
376   }
377
378   ASSERT_TRUE(cache.lookup(0).get());
379   ASSERT_EQ(0, *cache.lookup(0));
380
381   ASSERT_FALSE(cache.lookup(SIZE-1));
382   ASSERT_FALSE(cache.lookup(SIZE));
383   ASSERT_TRUE(cache.lookup(SIZE+1).get());
384   ASSERT_EQ((int)SIZE+1, *cache.lookup(SIZE+1));
385
386   cache.purge(0);
387   ASSERT_FALSE(cache.lookup(0));
388   ceph::shared_ptr<int> ptr2 = cache.add(0, new int(0), &existed);
389   ASSERT_FALSE(ptr == ptr2);
390   ptr = ceph::shared_ptr<int>();
391   ASSERT_TRUE(cache.lookup(0).get());
392 }
393
394 // Local Variables:
395 // compile-command: "cd ../.. ; make unittest_shared_cache && ./unittest_shared_cache # --gtest_filter=*.* --log-to-stderr=true"
396 // End: