Switch folly::Singleton to ReadMostlySharedPtr
[folly.git] / folly / experimental / test / ReadMostlySharedPtrTest.cpp
1 /*
2  * Copyright 2015 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 /* -*- Mode: C++; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
17
18 #include <atomic>
19 #include <thread>
20 #include <mutex>
21 #include <folly/Memory.h>
22 #include <condition_variable>
23 #include <gtest/gtest.h>
24
25 #include <folly/Baton.h>
26 #include <folly/experimental/RCURefCount.h>
27 #include <folly/experimental/ReadMostlySharedPtr.h>
28
29 using folly::ReadMostlyMainPtr;
30 using folly::ReadMostlyWeakPtr;
31 using folly::ReadMostlySharedPtr;
32
33 // send SIGALRM to test process after this many seconds
34 const unsigned int TEST_TIMEOUT = 10;
35
36 class ReadMostlySharedPtrTest : public ::testing::Test {
37  public:
38   ReadMostlySharedPtrTest() {
39     alarm(TEST_TIMEOUT);
40   }
41 };
42
43 struct TestObject {
44   int value;
45   std::atomic<int>& counter;
46
47   TestObject(int value, std::atomic<int>& counter)
48       : value(value), counter(counter) {
49     ++counter;
50   }
51
52   ~TestObject() {
53     assert(counter.load() > 0);
54     --counter;
55   }
56 };
57
58 // One side calls requestAndWait(), the other side calls waitForRequest(),
59 // does something and calls completed().
60 class Coordinator {
61  public:
62   void requestAndWait() {
63     requestBaton_.post();
64     completeBaton_.wait();
65   }
66
67   void waitForRequest() {
68     folly::RCURegisterThread();
69     requestBaton_.wait();
70   }
71
72   void completed() {
73     completeBaton_.post();
74   }
75
76  private:
77   folly::Baton<> requestBaton_;
78   folly::Baton<> completeBaton_;
79 };
80
81 TEST_F(ReadMostlySharedPtrTest, BasicStores) {
82   ReadMostlyMainPtr<TestObject> ptr;
83
84   // Store 1.
85   std::atomic<int> cnt1{0};
86   ptr.reset(folly::make_unique<TestObject>(1, cnt1));
87   EXPECT_EQ(1, cnt1.load());
88
89   // Store 2, check that 1 is destroyed.
90   std::atomic<int> cnt2{0};
91   ptr.reset(folly::make_unique<TestObject>(2, cnt2));
92   EXPECT_EQ(1, cnt2.load());
93   EXPECT_EQ(0, cnt1.load());
94
95   // Store nullptr, check that 2 is destroyed.
96   ptr.reset(nullptr);
97   EXPECT_EQ(0, cnt2.load());
98 }
99
100 TEST_F(ReadMostlySharedPtrTest, BasicLoads) {
101   std::atomic<int> cnt2{0};
102   ReadMostlySharedPtr<TestObject> x;
103
104   {
105     ReadMostlyMainPtr<TestObject> ptr;
106
107     // Check that ptr is initially nullptr.
108     EXPECT_EQ(ptr.get(), nullptr);
109
110     std::atomic<int> cnt1{0};
111     ptr.reset(folly::make_unique<TestObject>(1, cnt1));
112     EXPECT_EQ(1, cnt1.load());
113
114     x = ptr;
115     EXPECT_EQ(1, x->value);
116
117     ptr.reset(folly::make_unique<TestObject>(2, cnt2));
118     EXPECT_EQ(1, cnt2.load());
119     EXPECT_EQ(1, cnt1.load());
120
121     x = ptr;
122     EXPECT_EQ(2, x->value);
123     EXPECT_EQ(0, cnt1.load());
124
125     ptr.reset(nullptr);
126     EXPECT_EQ(1, cnt2.load());
127   }
128
129   EXPECT_EQ(1, cnt2.load());
130
131   x.reset();
132   EXPECT_EQ(0, cnt2.load());
133 }
134
135 TEST_F(ReadMostlySharedPtrTest, LoadsFromThreads) {
136   std::atomic<int> cnt{0};
137
138   {
139     ReadMostlyMainPtr<TestObject> ptr;
140     Coordinator loads[7];
141
142     std::thread t1([&] {
143       loads[0].waitForRequest();
144       EXPECT_EQ(ptr.getShared(), nullptr);
145       loads[0].completed();
146
147       loads[3].waitForRequest();
148       EXPECT_EQ(2, ptr.getShared()->value);
149       loads[3].completed();
150
151       loads[4].waitForRequest();
152       EXPECT_EQ(4, ptr.getShared()->value);
153       loads[4].completed();
154
155       loads[5].waitForRequest();
156       EXPECT_EQ(5, ptr.getShared()->value);
157       loads[5].completed();
158     });
159
160     std::thread t2([&] {
161       loads[1].waitForRequest();
162       EXPECT_EQ(1, ptr.getShared()->value);
163       loads[1].completed();
164
165       loads[2].waitForRequest();
166       EXPECT_EQ(2, ptr.getShared()->value);
167       loads[2].completed();
168
169       loads[6].waitForRequest();
170       EXPECT_EQ(5, ptr.getShared()->value);
171       loads[6].completed();
172     });
173
174     loads[0].requestAndWait();
175
176     ptr.reset(folly::make_unique<TestObject>(1, cnt));
177     loads[1].requestAndWait();
178
179     ptr.reset(folly::make_unique<TestObject>(2, cnt));
180     loads[2].requestAndWait();
181     loads[3].requestAndWait();
182
183     ptr.reset(folly::make_unique<TestObject>(3, cnt));
184     ptr.reset(folly::make_unique<TestObject>(4, cnt));
185     loads[4].requestAndWait();
186
187     ptr.reset(folly::make_unique<TestObject>(5, cnt));
188     loads[5].requestAndWait();
189     loads[6].requestAndWait();
190
191     EXPECT_EQ(1, cnt.load());
192
193     t1.join();
194     t2.join();
195   }
196
197   EXPECT_EQ(0, cnt.load());
198 }
199
200 TEST_F(ReadMostlySharedPtrTest, Ctor) {
201   std::atomic<int> cnt1{0};
202   {
203     ReadMostlyMainPtr<TestObject> ptr(
204       folly::make_unique<TestObject>(1, cnt1));
205
206     EXPECT_EQ(1, ptr.getShared()->value);
207   }
208
209   EXPECT_EQ(0, cnt1.load());
210 }
211
212 TEST_F(ReadMostlySharedPtrTest, ClearingCache) {
213   ReadMostlyMainPtr<TestObject> ptr;
214
215   // Store 1.
216   std::atomic<int> cnt1{0};
217   ptr.reset(folly::make_unique<TestObject>(1, cnt1));
218
219   Coordinator c;
220
221   std::thread t([&] {
222     // Cache the pointer for this thread.
223     ptr.getShared();
224     c.requestAndWait();
225   });
226
227   // Wait for the thread to cache pointer.
228   c.waitForRequest();
229   EXPECT_EQ(1, cnt1.load());
230
231   // Store 2 and check that 1 is destroyed.
232   std::atomic<int> cnt2{0};
233   ptr.reset(folly::make_unique<TestObject>(2, cnt2));
234   EXPECT_EQ(0, cnt1.load());
235
236   // Unblock thread.
237   c.completed();
238   t.join();
239 }