]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/table/cleanable_test.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rocksdb / table / cleanable_test.cc
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 "rocksdb/cleanable.h"
7
8 #include <gtest/gtest.h>
9
10 #include <functional>
11
12 #include "port/port.h"
13 #include "port/stack_trace.h"
14 #include "rocksdb/iostats_context.h"
15 #include "rocksdb/perf_context.h"
16 #include "test_util/testharness.h"
17 #include "test_util/testutil.h"
18
19 namespace ROCKSDB_NAMESPACE {
20
21 class CleanableTest : public testing::Test {};
22
23 // Use this to keep track of the cleanups that were actually performed
24 void Multiplier(void* arg1, void* arg2) {
25 int* res = reinterpret_cast<int*>(arg1);
26 int* num = reinterpret_cast<int*>(arg2);
27 *res *= *num;
28 }
29
30 // the first Cleanup is on stack and the rest on heap, so test with both cases
31 TEST_F(CleanableTest, Register) {
32 int n2 = 2, n3 = 3;
33 int res = 1;
34 { Cleanable c1; }
35 // ~Cleanable
36 ASSERT_EQ(1, res);
37
38 res = 1;
39 {
40 Cleanable c1;
41 c1.RegisterCleanup(Multiplier, &res, &n2); // res = 2;
42 }
43 // ~Cleanable
44 ASSERT_EQ(2, res);
45
46 res = 1;
47 {
48 Cleanable c1;
49 c1.RegisterCleanup(Multiplier, &res, &n2); // res = 2;
50 c1.RegisterCleanup(Multiplier, &res, &n3); // res = 2 * 3;
51 }
52 // ~Cleanable
53 ASSERT_EQ(6, res);
54
55 // Test the Reset does cleanup
56 res = 1;
57 {
58 Cleanable c1;
59 c1.RegisterCleanup(Multiplier, &res, &n2); // res = 2;
60 c1.RegisterCleanup(Multiplier, &res, &n3); // res = 2 * 3;
61 c1.Reset();
62 ASSERT_EQ(6, res);
63 }
64 // ~Cleanable
65 ASSERT_EQ(6, res);
66
67 // Test Clenable is usable after Reset
68 res = 1;
69 {
70 Cleanable c1;
71 c1.RegisterCleanup(Multiplier, &res, &n2); // res = 2;
72 c1.Reset();
73 ASSERT_EQ(2, res);
74 c1.RegisterCleanup(Multiplier, &res, &n3); // res = 2 * 3;
75 }
76 // ~Cleanable
77 ASSERT_EQ(6, res);
78 }
79
80 // the first Cleanup is on stack and the rest on heap,
81 // so test all the combinations of them
82 TEST_F(CleanableTest, Delegation) {
83 int n2 = 2, n3 = 3, n5 = 5, n7 = 7;
84 int res = 1;
85 {
86 Cleanable c2;
87 {
88 Cleanable c1;
89 c1.RegisterCleanup(Multiplier, &res, &n2); // res = 2;
90 c1.DelegateCleanupsTo(&c2);
91 }
92 // ~Cleanable
93 ASSERT_EQ(1, res);
94 }
95 // ~Cleanable
96 ASSERT_EQ(2, res);
97
98 res = 1;
99 {
100 Cleanable c2;
101 {
102 Cleanable c1;
103 c1.DelegateCleanupsTo(&c2);
104 }
105 // ~Cleanable
106 ASSERT_EQ(1, res);
107 }
108 // ~Cleanable
109 ASSERT_EQ(1, res);
110
111 res = 1;
112 {
113 Cleanable c2;
114 {
115 Cleanable c1;
116 c1.RegisterCleanup(Multiplier, &res, &n2); // res = 2;
117 c1.RegisterCleanup(Multiplier, &res, &n3); // res = 2 * 3;
118 c1.DelegateCleanupsTo(&c2);
119 }
120 // ~Cleanable
121 ASSERT_EQ(1, res);
122 }
123 // ~Cleanable
124 ASSERT_EQ(6, res);
125
126 res = 1;
127 {
128 Cleanable c2;
129 c2.RegisterCleanup(Multiplier, &res, &n5); // res = 5;
130 {
131 Cleanable c1;
132 c1.RegisterCleanup(Multiplier, &res, &n2); // res = 2;
133 c1.RegisterCleanup(Multiplier, &res, &n3); // res = 2 * 3;
134 c1.DelegateCleanupsTo(&c2); // res = 2 * 3 * 5;
135 }
136 // ~Cleanable
137 ASSERT_EQ(1, res);
138 }
139 // ~Cleanable
140 ASSERT_EQ(30, res);
141
142 res = 1;
143 {
144 Cleanable c2;
145 c2.RegisterCleanup(Multiplier, &res, &n5); // res = 5;
146 c2.RegisterCleanup(Multiplier, &res, &n7); // res = 5 * 7;
147 {
148 Cleanable c1;
149 c1.RegisterCleanup(Multiplier, &res, &n2); // res = 2;
150 c1.RegisterCleanup(Multiplier, &res, &n3); // res = 2 * 3;
151 c1.DelegateCleanupsTo(&c2); // res = 2 * 3 * 5 * 7;
152 }
153 // ~Cleanable
154 ASSERT_EQ(1, res);
155 }
156 // ~Cleanable
157 ASSERT_EQ(210, res);
158
159 res = 1;
160 {
161 Cleanable c2;
162 c2.RegisterCleanup(Multiplier, &res, &n5); // res = 5;
163 c2.RegisterCleanup(Multiplier, &res, &n7); // res = 5 * 7;
164 {
165 Cleanable c1;
166 c1.RegisterCleanup(Multiplier, &res, &n2); // res = 2;
167 c1.DelegateCleanupsTo(&c2); // res = 2 * 5 * 7;
168 }
169 // ~Cleanable
170 ASSERT_EQ(1, res);
171 }
172 // ~Cleanable
173 ASSERT_EQ(70, res);
174
175 res = 1;
176 {
177 Cleanable c2;
178 c2.RegisterCleanup(Multiplier, &res, &n5); // res = 5;
179 c2.RegisterCleanup(Multiplier, &res, &n7); // res = 5 * 7;
180 {
181 Cleanable c1;
182 c1.DelegateCleanupsTo(&c2); // res = 5 * 7;
183 }
184 // ~Cleanable
185 ASSERT_EQ(1, res);
186 }
187 // ~Cleanable
188 ASSERT_EQ(35, res);
189
190 res = 1;
191 {
192 Cleanable c2;
193 c2.RegisterCleanup(Multiplier, &res, &n5); // res = 5;
194 {
195 Cleanable c1;
196 c1.DelegateCleanupsTo(&c2); // res = 5;
197 }
198 // ~Cleanable
199 ASSERT_EQ(1, res);
200 }
201 // ~Cleanable
202 ASSERT_EQ(5, res);
203 }
204
205 static void ReleaseStringHeap(void* s, void*) {
206 delete reinterpret_cast<const std::string*>(s);
207 }
208
209 class PinnableSlice4Test : public PinnableSlice {
210 public:
211 void TestStringIsRegistered(std::string* s) {
212 ASSERT_TRUE(cleanup_.function == ReleaseStringHeap);
213 ASSERT_EQ(cleanup_.arg1, s);
214 ASSERT_EQ(cleanup_.arg2, nullptr);
215 ASSERT_EQ(cleanup_.next, nullptr);
216 }
217 };
218
219 // Putting the PinnableSlice tests here due to similarity to Cleanable tests
220 TEST_F(CleanableTest, PinnableSlice) {
221 int n2 = 2;
222 int res = 1;
223 const std::string const_str = "123";
224
225 {
226 res = 1;
227 PinnableSlice4Test value;
228 Slice slice(const_str);
229 value.PinSlice(slice, Multiplier, &res, &n2);
230 std::string str;
231 str.assign(value.data(), value.size());
232 ASSERT_EQ(const_str, str);
233 }
234 // ~Cleanable
235 ASSERT_EQ(2, res);
236
237 {
238 res = 1;
239 PinnableSlice4Test value;
240 Slice slice(const_str);
241 {
242 Cleanable c1;
243 c1.RegisterCleanup(Multiplier, &res, &n2); // res = 2;
244 value.PinSlice(slice, &c1);
245 }
246 // ~Cleanable
247 ASSERT_EQ(1, res); // cleanups must have be delegated to value
248 std::string str;
249 str.assign(value.data(), value.size());
250 ASSERT_EQ(const_str, str);
251 }
252 // ~Cleanable
253 ASSERT_EQ(2, res);
254
255 {
256 PinnableSlice4Test value;
257 Slice slice(const_str);
258 value.PinSelf(slice);
259 std::string str;
260 str.assign(value.data(), value.size());
261 ASSERT_EQ(const_str, str);
262 }
263
264 {
265 PinnableSlice4Test value;
266 std::string* self_str_ptr = value.GetSelf();
267 self_str_ptr->assign(const_str);
268 value.PinSelf();
269 std::string str;
270 str.assign(value.data(), value.size());
271 ASSERT_EQ(const_str, str);
272 }
273 }
274
275 static void Decrement(void* intptr, void*) { --*static_cast<int*>(intptr); }
276
277 // Allow unit testing moved-from data
278 template <class T>
279 void MarkInitializedForClangAnalyze(T& t) {
280 // No net effect, but confuse analyzer. (Published advice doesn't work.)
281 char* p = reinterpret_cast<char*>(&t);
282 std::swap(*p, *p);
283 }
284
285 TEST_F(CleanableTest, SharedWrapCleanables) {
286 int val = 5;
287 Cleanable c1, c2;
288 c1.RegisterCleanup(&Decrement, &val, nullptr);
289 c1.RegisterCleanup(&Decrement, &val, nullptr);
290 ASSERT_TRUE(c1.HasCleanups());
291 ASSERT_FALSE(c2.HasCleanups());
292
293 SharedCleanablePtr scp1;
294 ASSERT_EQ(scp1.get(), nullptr);
295
296 // No-ops
297 scp1.RegisterCopyWith(&c2);
298 scp1.MoveAsCleanupTo(&c2);
299
300 ASSERT_FALSE(c2.HasCleanups());
301 c2.RegisterCleanup(&Decrement, &val, nullptr);
302 c2.RegisterCleanup(&Decrement, &val, nullptr);
303 c2.RegisterCleanup(&Decrement, &val, nullptr);
304
305 scp1.Allocate();
306 ASSERT_NE(scp1.get(), nullptr);
307 ASSERT_FALSE(scp1->HasCleanups());
308
309 // Copy ctor (alias scp2 = scp1)
310 SharedCleanablePtr scp2{scp1};
311 ASSERT_EQ(scp1.get(), scp2.get());
312
313 c1.DelegateCleanupsTo(&*scp1);
314 ASSERT_TRUE(scp1->HasCleanups());
315 ASSERT_TRUE(scp2->HasCleanups());
316 ASSERT_FALSE(c1.HasCleanups());
317
318 SharedCleanablePtr scp3;
319 ASSERT_EQ(scp3.get(), nullptr);
320
321 // Copy operator (alias scp3 = scp2 = scp1)
322 scp3 = scp2;
323
324 // Make scp2 point elsewhere
325 scp2.Allocate();
326 c2.DelegateCleanupsTo(&*scp2);
327
328 ASSERT_EQ(val, 5);
329 // Move operator, invoke old c2 cleanups
330 scp2 = std::move(scp1);
331 ASSERT_EQ(val, 2);
332 MarkInitializedForClangAnalyze(scp1);
333 ASSERT_EQ(scp1.get(), nullptr);
334
335 // Move ctor
336 {
337 SharedCleanablePtr scp4{std::move(scp3)};
338 MarkInitializedForClangAnalyze(scp3);
339 ASSERT_EQ(scp3.get(), nullptr);
340 ASSERT_EQ(scp4.get(), scp2.get());
341
342 scp2.Reset();
343 ASSERT_EQ(val, 2);
344 // invoke old c1 cleanups
345 }
346 ASSERT_EQ(val, 0);
347 }
348
349 TEST_F(CleanableTest, CleanableWrapShared) {
350 int val = 5;
351 SharedCleanablePtr scp1, scp2;
352 scp1.Allocate();
353 scp1->RegisterCleanup(&Decrement, &val, nullptr);
354 scp1->RegisterCleanup(&Decrement, &val, nullptr);
355
356 scp2.Allocate();
357 scp2->RegisterCleanup(&Decrement, &val, nullptr);
358 scp2->RegisterCleanup(&Decrement, &val, nullptr);
359 scp2->RegisterCleanup(&Decrement, &val, nullptr);
360
361 {
362 Cleanable c1;
363 {
364 Cleanable c2, c3;
365 scp1.RegisterCopyWith(&c1);
366 scp1.MoveAsCleanupTo(&c2);
367 ASSERT_TRUE(c1.HasCleanups());
368 ASSERT_TRUE(c2.HasCleanups());
369 ASSERT_EQ(scp1.get(), nullptr);
370 scp2.MoveAsCleanupTo(&c3);
371 ASSERT_TRUE(c3.HasCleanups());
372 ASSERT_EQ(scp2.get(), nullptr);
373 c2.Reset();
374 ASSERT_FALSE(c2.HasCleanups());
375 ASSERT_EQ(val, 5);
376 // invoke cleanups from scp2
377 }
378 ASSERT_EQ(val, 2);
379 // invoke cleanups from scp1
380 }
381 ASSERT_EQ(val, 0);
382 }
383
384 } // namespace ROCKSDB_NAMESPACE
385
386 int main(int argc, char** argv) {
387 ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
388 ::testing::InitGoogleTest(&argc, argv);
389 return RUN_ALL_TESTS();
390 }