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