]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/common/test_sharedptr_registry.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / test / common / test_sharedptr_registry.cc
CommitLineData
7c673cae
FG
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 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library Public License for more details.
19 *
20 */
21
22#include <stdio.h>
23#include <signal.h>
24#include "gtest/gtest.h"
25#include "common/Thread.h"
26#include "common/sharedptr_registry.hpp"
27#include "common/ceph_argparse.h"
28
29class SharedPtrRegistryTest : public SharedPtrRegistry<unsigned int, int> {
30public:
11fdf7f2
TL
31 ceph::mutex &get_lock() { return lock; }
32 map<unsigned int, pair<std::weak_ptr<int>, int*> > &get_contents() {
7c673cae
FG
33 return contents;
34 }
35};
36
37class SharedPtrRegistry_all : public ::testing::Test {
38public:
39
40 class Thread_wait : public Thread {
41 public:
42 SharedPtrRegistryTest &registry;
43 unsigned int key;
44 int value;
11fdf7f2 45 std::shared_ptr<int> ptr;
7c673cae
FG
46 enum in_method_t { LOOKUP, LOOKUP_OR_CREATE } in_method;
47
48 Thread_wait(SharedPtrRegistryTest& _registry, unsigned int _key, int _value, in_method_t _in_method) :
49 registry(_registry),
50 key(_key),
51 value(_value),
52 in_method(_in_method)
53 {
54 }
55
56 void *entry() override {
57 switch(in_method) {
58 case LOOKUP_OR_CREATE:
59 if (value)
60 ptr = registry.lookup_or_create<int>(key, value);
61 else
62 ptr = registry.lookup_or_create(key);
63 break;
64 case LOOKUP:
11fdf7f2 65 ptr = std::shared_ptr<int>(new int);
7c673cae
FG
66 *ptr = value;
67 ptr = registry.lookup(key);
68 break;
69 }
70 return NULL;
71 }
72 };
73
74 static const useconds_t DELAY_MAX = 20 * 1000 * 1000;
75 static useconds_t delay;
76
77 bool wait_for(SharedPtrRegistryTest &registry, int waiting) {
78 do {
79 //
80 // the delay variable is supposed to be initialized to zero. It would be fine
81 // to usleep(0) but we take this opportunity to test the loop. It will try
82 // again and therefore show that the logic ( increasing the delay ) actually
83 // works.
84 //
85 if (delay > 0)
86 usleep(delay);
87 {
11fdf7f2 88 std::lock_guard l(registry.get_lock());
7c673cae
FG
89 if (registry.waiting == waiting)
90 break;
91 }
92 if (delay > 0)
93 cout << "delay " << delay << "us, is not long enough, try again\n";
94 } while (( delay = delay * 2 + 1) < DELAY_MAX);
95 return delay < DELAY_MAX;
96 }
97};
98
99useconds_t SharedPtrRegistry_all::delay = 0;
100
101TEST_F(SharedPtrRegistry_all, lookup_or_create) {
102 SharedPtrRegistryTest registry;
103 unsigned int key = 1;
104 int value = 2;
11fdf7f2 105 std::shared_ptr<int> ptr = registry.lookup_or_create(key);
7c673cae
FG
106 *ptr = value;
107 ASSERT_EQ(value, *registry.lookup_or_create(key));
108}
109
110TEST_F(SharedPtrRegistry_all, wait_lookup_or_create) {
111 SharedPtrRegistryTest registry;
112
113 //
114 // simulate the following: The last reference to a shared_ptr goes
115 // out of scope and the shared_ptr object is about to be removed and
116 // marked as such. The weak_ptr stored in the registry will show
117 // that it has expired(). However, the SharedPtrRegistry::OnRemoval
118 // object has not yet been called and did not get a chance to
119 // acquire the lock. The lookup_or_create and lookup methods must
120 // detect that situation and wait until the weak_ptr is removed from
121 // the registry.
122 //
123 {
124 unsigned int key = 1;
125 {
11fdf7f2 126 std::shared_ptr<int> ptr(new int);
7c673cae
FG
127 registry.get_contents()[key] = make_pair(ptr, ptr.get());
128 }
129 EXPECT_FALSE(registry.get_contents()[key].first.lock());
130
131 Thread_wait t(registry, key, 0, Thread_wait::LOOKUP_OR_CREATE);
132 t.create("wait_lookcreate");
133 ASSERT_TRUE(wait_for(registry, 1));
134 EXPECT_FALSE(t.ptr);
135 // waiting on a key does not block lookups on other keys
136 EXPECT_TRUE(registry.lookup_or_create(key + 12345).get());
137 registry.remove(key);
138 ASSERT_TRUE(wait_for(registry, 0));
139 t.join();
140 EXPECT_TRUE(t.ptr.get());
141 }
142 {
143 unsigned int key = 2;
144 int value = 3;
145 {
11fdf7f2 146 std::shared_ptr<int> ptr(new int);
7c673cae
FG
147 registry.get_contents()[key] = make_pair(ptr, ptr.get());
148 }
149 EXPECT_FALSE(registry.get_contents()[key].first.lock());
150
151 Thread_wait t(registry, key, value, Thread_wait::LOOKUP_OR_CREATE);
152 t.create("wait_lookcreate");
153 ASSERT_TRUE(wait_for(registry, 1));
154 EXPECT_FALSE(t.ptr);
155 // waiting on a key does not block lookups on other keys
156 {
157 int other_value = value + 1;
158 unsigned int other_key = key + 1;
11fdf7f2 159 std::shared_ptr<int> ptr = registry.lookup_or_create<int>(other_key, other_value);
7c673cae
FG
160 EXPECT_TRUE(ptr.get());
161 EXPECT_EQ(other_value, *ptr);
162 }
163 registry.remove(key);
164 ASSERT_TRUE(wait_for(registry, 0));
165 t.join();
166 EXPECT_TRUE(t.ptr.get());
167 EXPECT_EQ(value, *t.ptr);
168 }
169}
170
171TEST_F(SharedPtrRegistry_all, lookup) {
172 SharedPtrRegistryTest registry;
173 unsigned int key = 1;
174 {
11fdf7f2 175 std::shared_ptr<int> ptr = registry.lookup_or_create(key);
7c673cae
FG
176 int value = 2;
177 *ptr = value;
178 ASSERT_EQ(value, *registry.lookup(key));
179 }
180 ASSERT_FALSE(registry.lookup(key));
181}
182
183TEST_F(SharedPtrRegistry_all, wait_lookup) {
184 SharedPtrRegistryTest registry;
185
186 unsigned int key = 1;
187 int value = 2;
188 {
11fdf7f2 189 std::shared_ptr<int> ptr(new int);
7c673cae
FG
190 registry.get_contents()[key] = make_pair(ptr, ptr.get());
191 }
192 EXPECT_FALSE(registry.get_contents()[key].first.lock());
193
194 Thread_wait t(registry, key, value, Thread_wait::LOOKUP);
195 t.create("wait_lookup");
196 ASSERT_TRUE(wait_for(registry, 1));
197 EXPECT_EQ(value, *t.ptr);
198 // waiting on a key does not block lookups on other keys
199 EXPECT_FALSE(registry.lookup(key + 12345));
200 registry.remove(key);
201 ASSERT_TRUE(wait_for(registry, 0));
202 t.join();
203 EXPECT_FALSE(t.ptr);
204}
205
206TEST_F(SharedPtrRegistry_all, get_next) {
207
208 {
209 SharedPtrRegistry<unsigned int,int> registry;
210 const unsigned int key = 0;
211 pair<unsigned int, int> i;
212 EXPECT_FALSE(registry.get_next(key, &i));
213 }
214 {
215 SharedPtrRegistryTest registry;
216
217 const unsigned int key2 = 333;
11fdf7f2 218 std::shared_ptr<int> ptr2 = registry.lookup_or_create(key2);
7c673cae
FG
219 const int value2 = *ptr2 = 400;
220
221 // entries with expired pointers are silentely ignored
222 const unsigned int key_gone = 222;
11fdf7f2 223 registry.get_contents()[key_gone] = make_pair(std::shared_ptr<int>(), (int*)0);
7c673cae
FG
224
225 const unsigned int key1 = 111;
11fdf7f2 226 std::shared_ptr<int> ptr1 = registry.lookup_or_create(key1);
7c673cae
FG
227 const int value1 = *ptr1 = 800;
228
229 pair<unsigned int, int> i;
230 EXPECT_TRUE(registry.get_next(i.first, &i));
231 EXPECT_EQ(key1, i.first);
232 EXPECT_EQ(value1, i.second);
233
234 EXPECT_TRUE(registry.get_next(i.first, &i));
235 EXPECT_EQ(key2, i.first);
236 EXPECT_EQ(value2, i.second);
237
238 EXPECT_FALSE(registry.get_next(i.first, &i));
239 }
240 {
241 //
242 // http://tracker.ceph.com/issues/6117
243 // reproduce the issue.
244 //
245 SharedPtrRegistryTest registry;
246 const unsigned int key1 = 111;
11fdf7f2 247 std::shared_ptr<int> *ptr1 = new std::shared_ptr<int>(registry.lookup_or_create(key1));
7c673cae 248 const unsigned int key2 = 222;
11fdf7f2 249 std::shared_ptr<int> ptr2 = registry.lookup_or_create(key2);
7c673cae 250
11fdf7f2 251 pair<unsigned int, std::shared_ptr<int> > i;
7c673cae
FG
252 EXPECT_TRUE(registry.get_next(i.first, &i));
253 EXPECT_EQ(key1, i.first);
254 delete ptr1;
255 EXPECT_TRUE(registry.get_next(i.first, &i));
256 EXPECT_EQ(key2, i.first);
257 }
258}
259
260TEST_F(SharedPtrRegistry_all, remove) {
261 {
262 SharedPtrRegistryTest registry;
263 const unsigned int key1 = 1;
11fdf7f2 264 std::shared_ptr<int> ptr1 = registry.lookup_or_create(key1);
7c673cae
FG
265 *ptr1 = 400;
266 registry.remove(key1);
267
11fdf7f2 268 std::shared_ptr<int> ptr2 = registry.lookup_or_create(key1);
7c673cae
FG
269 *ptr2 = 500;
270
11fdf7f2
TL
271 ptr1 = std::shared_ptr<int>();
272 std::shared_ptr<int> res = registry.lookup(key1);
273 ceph_assert(res);
274 ceph_assert(res == ptr2);
275 ceph_assert(*res == 500);
7c673cae
FG
276 }
277 {
278 SharedPtrRegistryTest registry;
279 const unsigned int key1 = 1;
11fdf7f2 280 std::shared_ptr<int> ptr1 = registry.lookup_or_create(key1, 400);
7c673cae
FG
281 registry.remove(key1);
282
11fdf7f2 283 std::shared_ptr<int> ptr2 = registry.lookup_or_create(key1, 500);
7c673cae 284
11fdf7f2
TL
285 ptr1 = std::shared_ptr<int>();
286 std::shared_ptr<int> res = registry.lookup(key1);
287 ceph_assert(res);
288 ceph_assert(res == ptr2);
289 ceph_assert(*res == 500);
7c673cae
FG
290 }
291}
292
293class SharedPtrRegistry_destructor : public ::testing::Test {
294public:
295
296 typedef enum { UNDEFINED, YES, NO } DieEnum;
297 static DieEnum died;
298
299 struct TellDie {
300 TellDie() { died = NO; }
301 ~TellDie() { died = YES; }
302
11fdf7f2 303 int value = 0;
7c673cae
FG
304 };
305
306 void SetUp() override {
307 died = UNDEFINED;
308 }
309};
310
311SharedPtrRegistry_destructor::DieEnum SharedPtrRegistry_destructor::died = SharedPtrRegistry_destructor::UNDEFINED;
312
313TEST_F(SharedPtrRegistry_destructor, destructor) {
314 SharedPtrRegistry<int,TellDie> registry;
315 EXPECT_EQ(UNDEFINED, died);
316 int key = 101;
317 {
11fdf7f2 318 std::shared_ptr<TellDie> a = registry.lookup_or_create(key);
7c673cae
FG
319 EXPECT_EQ(NO, died);
320 EXPECT_TRUE(a.get());
321 }
322 EXPECT_EQ(YES, died);
323 EXPECT_FALSE(registry.lookup(key));
324}
325
326// Local Variables:
327// compile-command: "cd ../.. ; make unittest_sharedptr_registry && ./unittest_sharedptr_registry # --gtest_filter=*.* --log-to-stderr=true"
328// End: