1 //  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 
6 #include <functional>
7 
8 #include "port/port.h"
9 #include "port/stack_trace.h"
10 #include "rocksdb/iostats_context.h"
11 #include "rocksdb/perf_context.h"
12 #include "test_util/testharness.h"
13 #include "test_util/testutil.h"
14 
15 namespace ROCKSDB_NAMESPACE {
16 
17 class CleanableTest : public testing::Test {};
18 
19 // Use this to keep track of the cleanups that were actually performed
Multiplier(void * arg1,void * arg2)20 void Multiplier(void* arg1, void* arg2) {
21   int* res = reinterpret_cast<int*>(arg1);
22   int* num = reinterpret_cast<int*>(arg2);
23   *res *= *num;
24 }
25 
26 // the first Cleanup is on stack and the rest on heap, so test with both cases
TEST_F(CleanableTest,Register)27 TEST_F(CleanableTest, Register) {
28   int n2 = 2, n3 = 3;
29   int res = 1;
30   { Cleanable c1; }
31   // ~Cleanable
32   ASSERT_EQ(1, res);
33 
34   res = 1;
35   {
36     Cleanable c1;
37     c1.RegisterCleanup(Multiplier, &res, &n2);  // res = 2;
38   }
39   // ~Cleanable
40   ASSERT_EQ(2, res);
41 
42   res = 1;
43   {
44     Cleanable c1;
45     c1.RegisterCleanup(Multiplier, &res, &n2);  // res = 2;
46     c1.RegisterCleanup(Multiplier, &res, &n3);  // res = 2 * 3;
47   }
48   // ~Cleanable
49   ASSERT_EQ(6, res);
50 
51   // Test the Reset does cleanup
52   res = 1;
53   {
54     Cleanable c1;
55     c1.RegisterCleanup(Multiplier, &res, &n2);  // res = 2;
56     c1.RegisterCleanup(Multiplier, &res, &n3);  // res = 2 * 3;
57     c1.Reset();
58     ASSERT_EQ(6, res);
59   }
60   // ~Cleanable
61   ASSERT_EQ(6, res);
62 
63   // Test Clenable is usable after Reset
64   res = 1;
65   {
66     Cleanable c1;
67     c1.RegisterCleanup(Multiplier, &res, &n2);  // res = 2;
68     c1.Reset();
69     ASSERT_EQ(2, res);
70     c1.RegisterCleanup(Multiplier, &res, &n3);  // res = 2 * 3;
71   }
72   // ~Cleanable
73   ASSERT_EQ(6, res);
74 }
75 
76 // the first Cleanup is on stack and the rest on heap,
77 // so test all the combinations of them
TEST_F(CleanableTest,Delegation)78 TEST_F(CleanableTest, Delegation) {
79   int n2 = 2, n3 = 3, n5 = 5, n7 = 7;
80   int res = 1;
81   {
82     Cleanable c2;
83     {
84       Cleanable c1;
85       c1.RegisterCleanup(Multiplier, &res, &n2);  // res = 2;
86       c1.DelegateCleanupsTo(&c2);
87     }
88     // ~Cleanable
89     ASSERT_EQ(1, res);
90   }
91   // ~Cleanable
92   ASSERT_EQ(2, res);
93 
94   res = 1;
95   {
96     Cleanable c2;
97     {
98       Cleanable c1;
99       c1.DelegateCleanupsTo(&c2);
100     }
101     // ~Cleanable
102     ASSERT_EQ(1, res);
103   }
104   // ~Cleanable
105   ASSERT_EQ(1, res);
106 
107   res = 1;
108   {
109     Cleanable c2;
110     {
111       Cleanable c1;
112       c1.RegisterCleanup(Multiplier, &res, &n2);  // res = 2;
113       c1.RegisterCleanup(Multiplier, &res, &n3);  // res = 2 * 3;
114       c1.DelegateCleanupsTo(&c2);
115     }
116     // ~Cleanable
117     ASSERT_EQ(1, res);
118   }
119   // ~Cleanable
120   ASSERT_EQ(6, res);
121 
122   res = 1;
123   {
124     Cleanable c2;
125     c2.RegisterCleanup(Multiplier, &res, &n5);  // res = 5;
126     {
127       Cleanable c1;
128       c1.RegisterCleanup(Multiplier, &res, &n2);  // res = 2;
129       c1.RegisterCleanup(Multiplier, &res, &n3);  // res = 2 * 3;
130       c1.DelegateCleanupsTo(&c2);                 // res = 2 * 3 * 5;
131     }
132     // ~Cleanable
133     ASSERT_EQ(1, res);
134   }
135   // ~Cleanable
136   ASSERT_EQ(30, res);
137 
138   res = 1;
139   {
140     Cleanable c2;
141     c2.RegisterCleanup(Multiplier, &res, &n5);  // res = 5;
142     c2.RegisterCleanup(Multiplier, &res, &n7);  // res = 5 * 7;
143     {
144       Cleanable c1;
145       c1.RegisterCleanup(Multiplier, &res, &n2);  // res = 2;
146       c1.RegisterCleanup(Multiplier, &res, &n3);  // res = 2 * 3;
147       c1.DelegateCleanupsTo(&c2);                 // res = 2 * 3 * 5 * 7;
148     }
149     // ~Cleanable
150     ASSERT_EQ(1, res);
151   }
152   // ~Cleanable
153   ASSERT_EQ(210, res);
154 
155   res = 1;
156   {
157     Cleanable c2;
158     c2.RegisterCleanup(Multiplier, &res, &n5);  // res = 5;
159     c2.RegisterCleanup(Multiplier, &res, &n7);  // res = 5 * 7;
160     {
161       Cleanable c1;
162       c1.RegisterCleanup(Multiplier, &res, &n2);  // res = 2;
163       c1.DelegateCleanupsTo(&c2);                 // res = 2 * 5 * 7;
164     }
165     // ~Cleanable
166     ASSERT_EQ(1, res);
167   }
168   // ~Cleanable
169   ASSERT_EQ(70, res);
170 
171   res = 1;
172   {
173     Cleanable c2;
174     c2.RegisterCleanup(Multiplier, &res, &n5);  // res = 5;
175     c2.RegisterCleanup(Multiplier, &res, &n7);  // res = 5 * 7;
176     {
177       Cleanable c1;
178       c1.DelegateCleanupsTo(&c2);  // res = 5 * 7;
179     }
180     // ~Cleanable
181     ASSERT_EQ(1, res);
182   }
183   // ~Cleanable
184   ASSERT_EQ(35, res);
185 
186   res = 1;
187   {
188     Cleanable c2;
189     c2.RegisterCleanup(Multiplier, &res, &n5);  // res = 5;
190     {
191       Cleanable c1;
192       c1.DelegateCleanupsTo(&c2);  // res = 5;
193     }
194     // ~Cleanable
195     ASSERT_EQ(1, res);
196   }
197   // ~Cleanable
198   ASSERT_EQ(5, res);
199 }
200 
ReleaseStringHeap(void * s,void *)201 static void ReleaseStringHeap(void* s, void*) {
202   delete reinterpret_cast<const std::string*>(s);
203 }
204 
205 class PinnableSlice4Test : public PinnableSlice {
206  public:
TestStringIsRegistered(std::string * s)207   void TestStringIsRegistered(std::string* s) {
208     ASSERT_TRUE(cleanup_.function == ReleaseStringHeap);
209     ASSERT_EQ(cleanup_.arg1, s);
210     ASSERT_EQ(cleanup_.arg2, nullptr);
211     ASSERT_EQ(cleanup_.next, nullptr);
212   }
213 };
214 
215 // Putting the PinnableSlice tests here due to similarity to Cleanable tests
TEST_F(CleanableTest,PinnableSlice)216 TEST_F(CleanableTest, PinnableSlice) {
217   int n2 = 2;
218   int res = 1;
219   const std::string const_str = "123";
220 
221   {
222     res = 1;
223     PinnableSlice4Test value;
224     Slice slice(const_str);
225     value.PinSlice(slice, Multiplier, &res, &n2);
226     std::string str;
227     str.assign(value.data(), value.size());
228     ASSERT_EQ(const_str, str);
229   }
230   // ~Cleanable
231   ASSERT_EQ(2, res);
232 
233   {
234     res = 1;
235     PinnableSlice4Test value;
236     Slice slice(const_str);
237     {
238       Cleanable c1;
239       c1.RegisterCleanup(Multiplier, &res, &n2);  // res = 2;
240       value.PinSlice(slice, &c1);
241     }
242     // ~Cleanable
243     ASSERT_EQ(1, res);  // cleanups must have be delegated to value
244     std::string str;
245     str.assign(value.data(), value.size());
246     ASSERT_EQ(const_str, str);
247   }
248   // ~Cleanable
249   ASSERT_EQ(2, res);
250 
251   {
252     PinnableSlice4Test value;
253     Slice slice(const_str);
254     value.PinSelf(slice);
255     std::string str;
256     str.assign(value.data(), value.size());
257     ASSERT_EQ(const_str, str);
258   }
259 
260   {
261     PinnableSlice4Test value;
262     std::string* self_str_ptr = value.GetSelf();
263     self_str_ptr->assign(const_str);
264     value.PinSelf();
265     std::string str;
266     str.assign(value.data(), value.size());
267     ASSERT_EQ(const_str, str);
268   }
269 }
270 
271 }  // namespace ROCKSDB_NAMESPACE
272 
main(int argc,char ** argv)273 int main(int argc, char** argv) {
274   ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
275   ::testing::InitGoogleTest(&argc, argv);
276   return RUN_ALL_TESTS();
277 }
278