Revert "Using type-tags for test SingletonVaults"
[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   struct TestTag {};
130   Singleton<Watchdog, TestTag> named_watchdog(nullptr, nullptr, &vault);
131   EXPECT_EQ(vault.registeredSingletonCount(), 2);
132   vault.registrationComplete();
133
134   EXPECT_NE(watchdog.ptr(), nullptr);
135   EXPECT_EQ(watchdog.ptr(), Singleton<Watchdog>::get(&vault));
136   EXPECT_NE(watchdog.ptr(), named_watchdog.ptr());
137   EXPECT_EQ(watchdog->livingWatchdogCount(), 2);
138   EXPECT_EQ((*watchdog).livingWatchdogCount(), 2);
139 }
140
141 TEST(Singleton, NamedUsage) {
142   SingletonVault vault;
143
144   EXPECT_EQ(vault.registeredSingletonCount(), 0);
145
146   // Define two named Watchdog singletons and one unnamed singleton.
147   struct Watchdog1 {};
148   struct Watchdog2 {};
149   typedef detail::DefaultTag Watchdog3;
150   Singleton<Watchdog, Watchdog1> watchdog1_singleton(nullptr, nullptr, &vault);
151   EXPECT_EQ(vault.registeredSingletonCount(), 1);
152   Singleton<Watchdog, Watchdog2> watchdog2_singleton(nullptr, nullptr, &vault);
153   EXPECT_EQ(vault.registeredSingletonCount(), 2);
154   Singleton<Watchdog, Watchdog3> watchdog3_singleton(nullptr, nullptr, &vault);
155   EXPECT_EQ(vault.registeredSingletonCount(), 3);
156
157   vault.registrationComplete();
158
159   // Verify our three singletons are distinct and non-nullptr.
160   Watchdog* s1 = Singleton<Watchdog, Watchdog1>::get(&vault);
161   EXPECT_EQ(s1, watchdog1_singleton.ptr());
162   Watchdog* s2 = Singleton<Watchdog, Watchdog2>::get(&vault);
163   EXPECT_EQ(s2, watchdog2_singleton.ptr());
164   EXPECT_NE(s1, s2);
165   Watchdog* s3 = Singleton<Watchdog, Watchdog3>::get(&vault);
166   EXPECT_EQ(s3, watchdog3_singleton.ptr());
167   EXPECT_NE(s3, s1);
168   EXPECT_NE(s3, s2);
169
170   // Verify the "default" singleton is the same as the DefaultTag-tagged
171   // singleton.
172   Watchdog* s4 = Singleton<Watchdog>::get(&vault);
173   EXPECT_EQ(s4, watchdog3_singleton.ptr());
174 }
175
176 // Some pathological cases such as getting unregistered singletons,
177 // double registration, etc.
178 TEST(Singleton, NaughtyUsage) {
179   SingletonVault vault(SingletonVault::Type::Strict);
180   vault.registrationComplete();
181
182   // Unregistered.
183   EXPECT_THROW(Singleton<Watchdog>::get(), std::out_of_range);
184   EXPECT_THROW(Singleton<Watchdog>::get(&vault), std::out_of_range);
185
186   // Registring singletons after registrationComplete called.
187   EXPECT_THROW([&vault]() {
188                  Singleton<Watchdog> watchdog_singleton(
189                      nullptr, nullptr, &vault);
190                }(),
191                std::logic_error);
192
193   SingletonVault vault_2(SingletonVault::Type::Strict);
194   EXPECT_THROW(Singleton<Watchdog>::get(&vault_2), std::logic_error);
195   Singleton<Watchdog> watchdog_singleton(nullptr, nullptr, &vault_2);
196   // double registration
197   EXPECT_THROW([&vault_2]() {
198                  Singleton<Watchdog> watchdog_singleton(
199                      nullptr, nullptr, &vault_2);
200                }(),
201                std::logic_error);
202   vault_2.destroyInstances();
203   // double registration after destroy
204   EXPECT_THROW([&vault_2]() {
205                  Singleton<Watchdog> watchdog_singleton(
206                      nullptr, nullptr, &vault_2);
207                }(),
208                std::logic_error);
209 }
210
211 TEST(Singleton, SharedPtrUsage) {
212   SingletonVault vault;
213
214   EXPECT_EQ(vault.registeredSingletonCount(), 0);
215   Singleton<Watchdog> watchdog_singleton(nullptr, nullptr, &vault);
216   EXPECT_EQ(vault.registeredSingletonCount(), 1);
217
218   Singleton<ChildWatchdog> child_watchdog_singleton(nullptr, nullptr, &vault);
219   EXPECT_EQ(vault.registeredSingletonCount(), 2);
220
221   struct ATag {};
222   Singleton<Watchdog, ATag> named_watchdog_singleton(nullptr, nullptr, &vault);
223   vault.registrationComplete();
224
225   Watchdog* s1 = Singleton<Watchdog>::get(&vault);
226   EXPECT_NE(s1, nullptr);
227
228   Watchdog* s2 = Singleton<Watchdog>::get(&vault);
229   EXPECT_NE(s2, nullptr);
230
231   EXPECT_EQ(s1, s2);
232
233   auto weak_s1 = Singleton<Watchdog>::get_weak(&vault);
234   auto shared_s1 = weak_s1.lock();
235   EXPECT_EQ(shared_s1.get(), s1);
236   EXPECT_EQ(shared_s1.use_count(), 2);
237
238   {
239     auto named_weak_s1 = Singleton<Watchdog, ATag>::get_weak(&vault);
240     auto locked = named_weak_s1.lock();
241     EXPECT_NE(locked.get(), shared_s1.get());
242   }
243
244   LOG(ERROR) << "The following log message regarding shared_ptr is expected";
245   {
246     auto start_time = std::chrono::steady_clock::now();
247     vault.destroyInstances();
248     auto duration = std::chrono::steady_clock::now() - start_time;
249     EXPECT_TRUE(duration > std::chrono::seconds{4} &&
250                 duration < std::chrono::seconds{6});
251   }
252   EXPECT_EQ(vault.registeredSingletonCount(), 3);
253   EXPECT_EQ(vault.livingSingletonCount(), 0);
254
255   EXPECT_EQ(shared_s1.use_count(), 1);
256   EXPECT_EQ(shared_s1.get(), s1);
257
258   auto locked_s1 = weak_s1.lock();
259   EXPECT_EQ(locked_s1.get(), s1);
260   EXPECT_EQ(shared_s1.use_count(), 2);
261   locked_s1.reset();
262   EXPECT_EQ(shared_s1.use_count(), 1);
263
264   // Track serial number rather than pointer since the memory could be
265   // re-used when we create new_s1.
266   auto old_serial = shared_s1->serial_number;
267   shared_s1.reset();
268   locked_s1 = weak_s1.lock();
269   EXPECT_TRUE(weak_s1.expired());
270
271   auto empty_s1 = Singleton<Watchdog>::get_weak(&vault);
272   EXPECT_FALSE(empty_s1.lock());
273
274   vault.reenableInstances();
275
276   // Singleton should be re-created only after reenableInstances() was called.
277   Watchdog* new_s1 = Singleton<Watchdog>::get(&vault);
278   EXPECT_NE(new_s1->serial_number, old_serial);
279
280   auto new_s1_weak = Singleton<Watchdog>::get_weak(&vault);
281   auto new_s1_shared = new_s1_weak.lock();
282   std::thread t([new_s1_shared]() mutable {
283       std::this_thread::sleep_for(std::chrono::seconds{2});
284       new_s1_shared.reset();
285     });
286   new_s1_shared.reset();
287   {
288     auto start_time = std::chrono::steady_clock::now();
289     vault.destroyInstances();
290     auto duration = std::chrono::steady_clock::now() - start_time;
291     EXPECT_TRUE(duration > std::chrono::seconds{1} &&
292                 duration < std::chrono::seconds{3});
293   }
294   EXPECT_TRUE(new_s1_weak.expired());
295   t.join();
296 }
297
298 // Some classes to test singleton dependencies.  NeedySingleton has a
299 // dependency on NeededSingleton, which happens during its
300 // construction.
301 SingletonVault needy_vault;
302
303 struct NeededSingleton {};
304 struct NeedySingleton {
305   NeedySingleton() {
306     auto unused = Singleton<NeededSingleton>::get(&needy_vault);
307     EXPECT_NE(unused, nullptr);
308   }
309 };
310
311 // Ensure circular dependencies fail -- a singleton that needs itself, whoops.
312 SingletonVault self_needy_vault;
313 struct SelfNeedySingleton {
314   SelfNeedySingleton() {
315     auto unused = Singleton<SelfNeedySingleton>::get(&self_needy_vault);
316     EXPECT_NE(unused, nullptr);
317   }
318 };
319
320 TEST(Singleton, SingletonDependencies) {
321   Singleton<NeededSingleton> needed_singleton(nullptr, nullptr, &needy_vault);
322   Singleton<NeedySingleton> needy_singleton(nullptr, nullptr, &needy_vault);
323   needy_vault.registrationComplete();
324
325   EXPECT_EQ(needy_vault.registeredSingletonCount(), 2);
326   EXPECT_EQ(needy_vault.livingSingletonCount(), 0);
327
328   auto needy = Singleton<NeedySingleton>::get(&needy_vault);
329   EXPECT_EQ(needy_vault.livingSingletonCount(), 2);
330
331   Singleton<SelfNeedySingleton> self_needy_singleton(
332       nullptr, nullptr, &self_needy_vault);
333   self_needy_vault.registrationComplete();
334   EXPECT_THROW([]() {
335                  Singleton<SelfNeedySingleton>::get(&self_needy_vault);
336                }(),
337                std::out_of_range);
338 }
339
340 // A test to ensure multiple threads contending on singleton creation
341 // properly wait for creation rather than thinking it is a circular
342 // dependency.
343 class Slowpoke : public Watchdog {
344  public:
345   Slowpoke() { std::this_thread::sleep_for(std::chrono::milliseconds(10)); }
346 };
347
348 TEST(Singleton, SingletonConcurrency) {
349   SingletonVault vault;
350   Singleton<Slowpoke> slowpoke_singleton(nullptr, nullptr, &vault);
351   vault.registrationComplete();
352
353   std::mutex gatekeeper;
354   gatekeeper.lock();
355   auto func = [&vault, &gatekeeper]() {
356     gatekeeper.lock();
357     gatekeeper.unlock();
358     auto unused = Singleton<Slowpoke>::get(&vault);
359   };
360
361   EXPECT_EQ(vault.livingSingletonCount(), 0);
362   std::vector<std::thread> threads;
363   for (int i = 0; i < 100; ++i) {
364     threads.emplace_back(func);
365   }
366   // If circular dependency checks fail, the unlock would trigger a
367   // crash.  Instead, it succeeds, and we have exactly one living
368   // singleton.
369   gatekeeper.unlock();
370   for (auto& t : threads) {
371     t.join();
372   }
373   EXPECT_EQ(vault.livingSingletonCount(), 1);
374 }
375
376 TEST(Singleton, SingletonConcurrencyStress) {
377   SingletonVault vault;
378   Singleton<Slowpoke> slowpoke_singleton(nullptr, nullptr, &vault);
379
380   std::vector<std::thread> ts;
381   for (size_t i = 0; i < 100; ++i) {
382     ts.emplace_back([&]() {
383         slowpoke_singleton.get_weak(&vault).lock();
384       });
385   }
386
387   for (size_t i = 0; i < 100; ++i) {
388     std::chrono::milliseconds d(20);
389
390     std::this_thread::sleep_for(d);
391     vault.destroyInstances();
392     std::this_thread::sleep_for(d);
393     vault.destroyInstances();
394   }
395
396   for (auto& t : ts) {
397     t.join();
398   }
399 }
400
401 // Benchmarking a normal singleton vs a Meyers singleton vs a Folly
402 // singleton.  Meyers are insanely fast, but (hopefully) Folly
403 // singletons are fast "enough."
404 int* getMeyersSingleton() {
405   static auto ret = new int(0);
406   return ret;
407 }
408
409 int normal_singleton_value = 0;
410 int* getNormalSingleton() {
411   doNotOptimizeAway(&normal_singleton_value);
412   return &normal_singleton_value;
413 }
414
415 // Verify that existing Singleton's can be overridden
416 // using the make_mock functionality.
417 TEST(Singleton, make_mock) {
418   SingletonVault vault(SingletonVault::Type::Strict);
419   Singleton<Watchdog> watchdog_singleton(nullptr, nullptr, &vault);
420   vault.registrationComplete();
421
422   // Registring singletons after registrationComplete called works
423   // with make_mock (but not with Singleton ctor).
424   EXPECT_EQ(vault.registeredSingletonCount(), 1);
425   int serial_count_first = Singleton<Watchdog>::get(&vault)->serial_number;
426
427   // Override existing mock using make_mock.
428   Singleton<Watchdog>::make_mock(nullptr, nullptr, &vault);
429
430   EXPECT_EQ(vault.registeredSingletonCount(), 1);
431   int serial_count_mock = Singleton<Watchdog>::get(&vault)->serial_number;
432
433   // If serial_count value is the same, then singleton was not replaced.
434   EXPECT_NE(serial_count_first, serial_count_mock);
435 }
436
437 struct BenchmarkSingleton {
438   int val = 0;
439 };
440
441 BENCHMARK(NormalSingleton, n) {
442   for (size_t i = 0; i < n; ++i) {
443     doNotOptimizeAway(getNormalSingleton());
444   }
445 }
446
447 BENCHMARK_RELATIVE(MeyersSingleton, n) {
448   for (size_t i = 0; i < n; ++i) {
449     doNotOptimizeAway(getMeyersSingleton());
450   }
451 }
452
453 BENCHMARK_RELATIVE(FollySingletonSlow, n) {
454   SingletonVault benchmark_vault;
455   Singleton<BenchmarkSingleton> benchmark_singleton(
456       nullptr, nullptr, &benchmark_vault);
457   benchmark_vault.registrationComplete();
458
459   for (size_t i = 0; i < n; ++i) {
460     doNotOptimizeAway(Singleton<BenchmarkSingleton>::get(&benchmark_vault));
461   }
462 }
463
464 BENCHMARK_RELATIVE(FollySingletonFast, n) {
465   SingletonVault benchmark_vault;
466   Singleton<BenchmarkSingleton> benchmark_singleton(
467       nullptr, nullptr, &benchmark_vault);
468   benchmark_vault.registrationComplete();
469
470   for (size_t i = 0; i < n; ++i) {
471     doNotOptimizeAway(benchmark_singleton.get_fast());
472   }
473 }
474
475 BENCHMARK_RELATIVE(FollySingletonFastWeak, n) {
476   SingletonVault benchmark_vault;
477   Singleton<BenchmarkSingleton> benchmark_singleton(
478       nullptr, nullptr, &benchmark_vault);
479   benchmark_vault.registrationComplete();
480
481   for (size_t i = 0; i < n; ++i) {
482     benchmark_singleton.get_weak_fast();
483   }
484 }
485
486 int main(int argc, char* argv[]) {
487   testing::InitGoogleTest(&argc, argv);
488   google::InitGoogleLogging(argv[0]);
489   google::ParseCommandLineFlags(&argc, &argv, true);
490
491   SingletonVault::singleton()->registrationComplete();
492
493   auto ret = RUN_ALL_TESTS();
494   if (!ret) {
495     folly::runBenchmarksOnFlag();
496   }
497   return ret;
498 }