in thread pools, take factory as shared ptr
[folly.git] / folly / experimental / test / SingletonTest.cpp
1 /*
2  * Copyright 2014 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <thread>
18
19 #include <folly/experimental/Singleton.h>
20
21 #include <folly/Benchmark.h>
22
23 #include <glog/logging.h>
24 #include <gtest/gtest.h>
25
26 using namespace folly;
27
28 // A simple class that tracks how often instances of the class and
29 // subclasses are created, and the ordering.  Also tracks a global
30 // unique counter for each object.
31 std::atomic<size_t> global_counter(19770326);
32 struct Watchdog {
33   static std::vector<Watchdog*> creation_order;
34   Watchdog() : serial_number(++global_counter) {
35     creation_order.push_back(this);
36   }
37
38   ~Watchdog() {
39     if (creation_order.back() != this) {
40       throw std::out_of_range("Watchdog destruction order mismatch");
41     }
42     creation_order.pop_back();
43   }
44
45   const size_t serial_number;
46   size_t livingWatchdogCount() const { return creation_order.size(); }
47
48   Watchdog(const Watchdog&) = delete;
49   Watchdog& operator=(const Watchdog&) = delete;
50   Watchdog(Watchdog&&) noexcept = default;
51 };
52
53 std::vector<Watchdog*> Watchdog::creation_order;
54
55 // Some basic types we use for tracking.
56 struct ChildWatchdog : public Watchdog {};
57 struct GlobalWatchdog : public Watchdog {};
58 struct UnregisteredWatchdog : public Watchdog {};
59
60 namespace {
61 Singleton<GlobalWatchdog> global_watchdog;
62 }
63
64 // Test basic global usage (the default way singletons will generally
65 // be used).
66 TEST(Singleton, BasicGlobalUsage) {
67   EXPECT_EQ(Watchdog::creation_order.size(), 0);
68   EXPECT_EQ(SingletonVault::singleton()->registeredSingletonCount(), 1);
69   EXPECT_EQ(SingletonVault::singleton()->livingSingletonCount(), 0);
70   auto wd1 = Singleton<GlobalWatchdog>::get();
71   EXPECT_NE(wd1, nullptr);
72   EXPECT_EQ(Watchdog::creation_order.size(), 1);
73   auto wd2 = Singleton<GlobalWatchdog>::get();
74   EXPECT_NE(wd2, nullptr);
75   EXPECT_EQ(wd1, wd2);
76   EXPECT_EQ(Watchdog::creation_order.size(), 1);
77   SingletonVault::singleton()->destroyInstances();
78   EXPECT_EQ(Watchdog::creation_order.size(), 0);
79 }
80
81 TEST(Singleton, MissingSingleton) {
82   EXPECT_THROW([]() { auto u = Singleton<UnregisteredWatchdog>::get(); }(),
83                std::out_of_range);
84 }
85
86 // Exercise some basic codepaths ensuring registration order and
87 // destruction order happen as expected, that instances are created
88 // when expected, etc etc.
89 TEST(Singleton, BasicUsage) {
90   SingletonVault vault;
91
92   EXPECT_EQ(vault.registeredSingletonCount(), 0);
93   Singleton<Watchdog> watchdog_singleton(nullptr, nullptr, &vault);
94   EXPECT_EQ(vault.registeredSingletonCount(), 1);
95
96   Singleton<ChildWatchdog> child_watchdog_singleton(nullptr, nullptr, &vault);
97   EXPECT_EQ(vault.registeredSingletonCount(), 2);
98
99   vault.registrationComplete();
100
101   Watchdog* s1 = Singleton<Watchdog>::get(&vault);
102   EXPECT_NE(s1, nullptr);
103
104   Watchdog* s2 = Singleton<Watchdog>::get(&vault);
105   EXPECT_NE(s2, nullptr);
106
107   EXPECT_EQ(s1, s2);
108
109   auto s3 = Singleton<ChildWatchdog>::get(&vault);
110   EXPECT_NE(s3, nullptr);
111   EXPECT_NE(s2, s3);
112
113   EXPECT_EQ(vault.registeredSingletonCount(), 2);
114   EXPECT_EQ(vault.livingSingletonCount(), 2);
115
116   vault.destroyInstances();
117   EXPECT_EQ(vault.registeredSingletonCount(), 2);
118   EXPECT_EQ(vault.livingSingletonCount(), 0);
119 }
120
121 TEST(Singleton, DirectUsage) {
122   SingletonVault vault;
123
124   EXPECT_EQ(vault.registeredSingletonCount(), 0);
125
126   // Verify we can get to the underlying singletons via directly using
127   // the singleton definition.
128   Singleton<Watchdog> watchdog(nullptr, nullptr, &vault);
129   Singleton<Watchdog> named_watchdog("named", nullptr, nullptr, &vault);
130   EXPECT_EQ(vault.registeredSingletonCount(), 2);
131   vault.registrationComplete();
132
133   EXPECT_NE(watchdog.ptr(), nullptr);
134   EXPECT_EQ(watchdog.ptr(), Singleton<Watchdog>::get(&vault));
135   EXPECT_NE(watchdog.ptr(), named_watchdog.ptr());
136   EXPECT_EQ(watchdog->livingWatchdogCount(), 2);
137   EXPECT_EQ((*watchdog).livingWatchdogCount(), 2);
138 }
139
140 TEST(Singleton, NamedUsage) {
141   SingletonVault vault;
142
143   EXPECT_EQ(vault.registeredSingletonCount(), 0);
144
145   // Define two named Watchdog singletons and one unnamed singleton.
146   Singleton<Watchdog> watchdog1_singleton(
147       "watchdog1", nullptr, nullptr, &vault);
148   EXPECT_EQ(vault.registeredSingletonCount(), 1);
149   Singleton<Watchdog> watchdog2_singleton(
150       "watchdog2", nullptr, nullptr, &vault);
151   EXPECT_EQ(vault.registeredSingletonCount(), 2);
152   Singleton<Watchdog> watchdog3_singleton(nullptr, nullptr, &vault);
153   EXPECT_EQ(vault.registeredSingletonCount(), 3);
154
155   vault.registrationComplete();
156
157   // Verify our three singletons are distinct and non-nullptr.
158   Watchdog* s1 = Singleton<Watchdog>::get("watchdog1", &vault);
159   EXPECT_EQ(s1, watchdog1_singleton.ptr());
160   Watchdog* s2 = Singleton<Watchdog>::get("watchdog2", &vault);
161   EXPECT_EQ(s2, watchdog2_singleton.ptr());
162   EXPECT_NE(s1, s2);
163   Watchdog* s3 = Singleton<Watchdog>::get(&vault);
164   EXPECT_EQ(s3, watchdog3_singleton.ptr());
165   EXPECT_NE(s3, s1);
166   EXPECT_NE(s3, s2);
167
168   // Verify the "default" singleton is the same as the empty string
169   // singleton.
170   Watchdog* s4 = Singleton<Watchdog>::get("", &vault);
171   EXPECT_EQ(s4, watchdog3_singleton.ptr());
172 }
173
174 // Some pathological cases such as getting unregistered singletons,
175 // double registration, etc.
176 TEST(Singleton, NaughtyUsage) {
177   SingletonVault vault(SingletonVault::Type::Strict);
178   vault.registrationComplete();
179
180   // Unregistered.
181   EXPECT_THROW(Singleton<Watchdog>::get(), std::out_of_range);
182   EXPECT_THROW(Singleton<Watchdog>::get(&vault), std::out_of_range);
183
184   // Registring singletons after registrationComplete called.
185   EXPECT_THROW([&vault]() {
186                  Singleton<Watchdog> watchdog_singleton(
187                      nullptr, nullptr, &vault);
188                }(),
189                std::logic_error);
190
191   // Default vault is non-strict; this should work.
192   Singleton<Watchdog> global_watchdog_singleton;
193
194   SingletonVault vault_2(SingletonVault::Type::Strict);
195   EXPECT_THROW(Singleton<Watchdog>::get(&vault_2), std::logic_error);
196   Singleton<Watchdog> watchdog_singleton(nullptr, nullptr, &vault_2);
197   // double registration
198   EXPECT_THROW([&vault_2]() {
199                  Singleton<Watchdog> watchdog_singleton(
200                      nullptr, nullptr, &vault_2);
201                }(),
202                std::logic_error);
203   vault_2.destroyInstances();
204   // double registration after destroy
205   EXPECT_THROW([&vault_2]() {
206                  Singleton<Watchdog> watchdog_singleton(
207                      nullptr, nullptr, &vault_2);
208                }(),
209                std::logic_error);
210 }
211
212 TEST(Singleton, SharedPtrUsage) {
213   SingletonVault vault;
214
215   EXPECT_EQ(vault.registeredSingletonCount(), 0);
216   Singleton<Watchdog> watchdog_singleton(nullptr, nullptr, &vault);
217   EXPECT_EQ(vault.registeredSingletonCount(), 1);
218
219   Singleton<ChildWatchdog> child_watchdog_singleton(nullptr, nullptr, &vault);
220   EXPECT_EQ(vault.registeredSingletonCount(), 2);
221
222   Singleton<Watchdog> named_watchdog_singleton(
223       "a_name", nullptr, nullptr, &vault);
224   vault.registrationComplete();
225
226   Watchdog* s1 = Singleton<Watchdog>::get(&vault);
227   EXPECT_NE(s1, nullptr);
228
229   Watchdog* s2 = Singleton<Watchdog>::get(&vault);
230   EXPECT_NE(s2, nullptr);
231
232   EXPECT_EQ(s1, s2);
233
234   auto weak_s1 = Singleton<Watchdog>::get_weak(&vault);
235   auto shared_s1 = weak_s1.lock();
236   EXPECT_EQ(shared_s1.get(), s1);
237   EXPECT_EQ(shared_s1.use_count(), 2);
238
239   {
240     auto named_weak_s1 = Singleton<Watchdog>::get_weak("a_name", &vault);
241     auto locked = named_weak_s1.lock();
242     EXPECT_NE(locked.get(), shared_s1.get());
243   }
244
245   LOG(ERROR) << "The following log message regarding ref counts is expected";
246   vault.destroyInstances();
247   EXPECT_EQ(vault.registeredSingletonCount(), 3);
248   EXPECT_EQ(vault.livingSingletonCount(), 0);
249
250   EXPECT_EQ(shared_s1.use_count(), 1);
251   EXPECT_EQ(shared_s1.get(), s1);
252
253   auto locked_s1 = weak_s1.lock();
254   EXPECT_EQ(locked_s1.get(), s1);
255   EXPECT_EQ(shared_s1.use_count(), 2);
256   locked_s1.reset();
257   EXPECT_EQ(shared_s1.use_count(), 1);
258
259   // Track serial number rather than pointer since the memory could be
260   // re-used when we create new_s1.
261   auto old_serial = shared_s1->serial_number;
262   shared_s1.reset();
263   locked_s1 = weak_s1.lock();
264   EXPECT_TRUE(weak_s1.expired());
265
266   Watchdog* new_s1 = Singleton<Watchdog>::get(&vault);
267   EXPECT_NE(new_s1->serial_number, old_serial);
268 }
269
270 // Some classes to test singleton dependencies.  NeedySingleton has a
271 // dependency on NeededSingleton, which happens during its
272 // construction.
273 SingletonVault needy_vault;
274
275 struct NeededSingleton {};
276 struct NeedySingleton {
277   NeedySingleton() {
278     auto unused = Singleton<NeededSingleton>::get(&needy_vault);
279     EXPECT_NE(unused, nullptr);
280   }
281 };
282
283 // Ensure circular dependencies fail -- a singleton that needs itself, whoops.
284 SingletonVault self_needy_vault;
285 struct SelfNeedySingleton {
286   SelfNeedySingleton() {
287     auto unused = Singleton<SelfNeedySingleton>::get(&self_needy_vault);
288     EXPECT_NE(unused, nullptr);
289   }
290 };
291
292 TEST(Singleton, SingletonDependencies) {
293   Singleton<NeededSingleton> needed_singleton(nullptr, nullptr, &needy_vault);
294   Singleton<NeedySingleton> needy_singleton(nullptr, nullptr, &needy_vault);
295   needy_vault.registrationComplete();
296
297   EXPECT_EQ(needy_vault.registeredSingletonCount(), 2);
298   EXPECT_EQ(needy_vault.livingSingletonCount(), 0);
299
300   auto needy = Singleton<NeedySingleton>::get(&needy_vault);
301   EXPECT_EQ(needy_vault.livingSingletonCount(), 2);
302
303   Singleton<SelfNeedySingleton> self_needy_singleton(
304       nullptr, nullptr, &self_needy_vault);
305   self_needy_vault.registrationComplete();
306   EXPECT_THROW([]() {
307                  Singleton<SelfNeedySingleton>::get(&self_needy_vault);
308                }(),
309                std::out_of_range);
310 }
311
312 // A test to ensure multiple threads contending on singleton creation
313 // properly wait for creation rather than thinking it is a circular
314 // dependency.
315 class Slowpoke {
316  public:
317   Slowpoke() { std::this_thread::sleep_for(std::chrono::seconds(1)); }
318 };
319
320 TEST(Singleton, SingletonConcurrency) {
321   SingletonVault vault;
322   Singleton<Slowpoke> slowpoke_singleton(nullptr, nullptr, &vault);
323   vault.registrationComplete();
324
325   std::mutex gatekeeper;
326   gatekeeper.lock();
327   auto func = [&vault, &gatekeeper]() {
328     gatekeeper.lock();
329     gatekeeper.unlock();
330     auto unused = Singleton<Slowpoke>::get(&vault);
331   };
332
333   EXPECT_EQ(vault.livingSingletonCount(), 0);
334   std::vector<std::thread> threads;
335   for (int i = 0; i < 100; ++i) {
336     threads.emplace_back(func);
337   }
338   // If circular dependency checks fail, the unlock would trigger a
339   // crash.  Instead, it succeeds, and we have exactly one living
340   // singleton.
341   gatekeeper.unlock();
342   for (auto& t : threads) {
343     t.join();
344   }
345   EXPECT_EQ(vault.livingSingletonCount(), 1);
346 }
347
348 // Benchmarking a normal singleton vs a Meyers singleton vs a Folly
349 // singleton.  Meyers are insanely fast, but (hopefully) Folly
350 // singletons are fast "enough."
351 int* getMeyersSingleton() {
352   static auto ret = new int(0);
353   return ret;
354 }
355
356 int normal_singleton_value = 0;
357 int* getNormalSingleton() {
358   doNotOptimizeAway(&normal_singleton_value);
359   return &normal_singleton_value;
360 }
361
362 struct BenchmarkSingleton {
363   int val = 0;
364 };
365
366 BENCHMARK(NormalSingleton, n) {
367   for (int i = 0; i < n; ++i) {
368     doNotOptimizeAway(getNormalSingleton());
369   }
370 }
371
372 BENCHMARK_RELATIVE(MeyersSingleton, n) {
373   for (int i = 0; i < n; ++i) {
374     doNotOptimizeAway(getMeyersSingleton());
375   }
376 }
377
378 BENCHMARK_RELATIVE(FollySingleton, n) {
379   SingletonVault benchmark_vault;
380   Singleton<BenchmarkSingleton> benchmark_singleton(
381       nullptr, nullptr, &benchmark_vault);
382   benchmark_vault.registrationComplete();
383
384   for (int i = 0; i < n; ++i) {
385     doNotOptimizeAway(Singleton<BenchmarkSingleton>::get(&benchmark_vault));
386   }
387 }
388
389 int main(int argc, char* argv[]) {
390   testing::InitGoogleTest(&argc, argv);
391   google::InitGoogleLogging(argv[0]);
392   google::ParseCommandLineFlags(&argc, &argv, true);
393
394   SingletonVault::singleton()->registrationComplete();
395
396   auto ret = RUN_ALL_TESTS();
397   if (!ret) {
398     folly::runBenchmarksOnFlag();
399   }
400   return ret;
401 }