]>
git.proxmox.com Git - ceph.git/blob - 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).
6 #include "rocksdb/cleanable.h"
8 #include <gtest/gtest.h>
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"
19 namespace ROCKSDB_NAMESPACE
{
21 class CleanableTest
: public testing::Test
{};
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
);
30 // the first Cleanup is on stack and the rest on heap, so test with both cases
31 TEST_F(CleanableTest
, Register
) {
41 c1
.RegisterCleanup(Multiplier
, &res
, &n2
); // res = 2;
49 c1
.RegisterCleanup(Multiplier
, &res
, &n2
); // res = 2;
50 c1
.RegisterCleanup(Multiplier
, &res
, &n3
); // res = 2 * 3;
55 // Test the Reset does cleanup
59 c1
.RegisterCleanup(Multiplier
, &res
, &n2
); // res = 2;
60 c1
.RegisterCleanup(Multiplier
, &res
, &n3
); // res = 2 * 3;
67 // Test Clenable is usable after Reset
71 c1
.RegisterCleanup(Multiplier
, &res
, &n2
); // res = 2;
74 c1
.RegisterCleanup(Multiplier
, &res
, &n3
); // res = 2 * 3;
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;
89 c1
.RegisterCleanup(Multiplier
, &res
, &n2
); // res = 2;
90 c1
.DelegateCleanupsTo(&c2
);
103 c1
.DelegateCleanupsTo(&c2
);
116 c1
.RegisterCleanup(Multiplier
, &res
, &n2
); // res = 2;
117 c1
.RegisterCleanup(Multiplier
, &res
, &n3
); // res = 2 * 3;
118 c1
.DelegateCleanupsTo(&c2
);
129 c2
.RegisterCleanup(Multiplier
, &res
, &n5
); // res = 5;
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;
145 c2
.RegisterCleanup(Multiplier
, &res
, &n5
); // res = 5;
146 c2
.RegisterCleanup(Multiplier
, &res
, &n7
); // res = 5 * 7;
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;
162 c2
.RegisterCleanup(Multiplier
, &res
, &n5
); // res = 5;
163 c2
.RegisterCleanup(Multiplier
, &res
, &n7
); // res = 5 * 7;
166 c1
.RegisterCleanup(Multiplier
, &res
, &n2
); // res = 2;
167 c1
.DelegateCleanupsTo(&c2
); // res = 2 * 5 * 7;
178 c2
.RegisterCleanup(Multiplier
, &res
, &n5
); // res = 5;
179 c2
.RegisterCleanup(Multiplier
, &res
, &n7
); // res = 5 * 7;
182 c1
.DelegateCleanupsTo(&c2
); // res = 5 * 7;
193 c2
.RegisterCleanup(Multiplier
, &res
, &n5
); // res = 5;
196 c1
.DelegateCleanupsTo(&c2
); // res = 5;
205 static void ReleaseStringHeap(void* s
, void*) {
206 delete reinterpret_cast<const std::string
*>(s
);
209 class PinnableSlice4Test
: public PinnableSlice
{
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);
219 // Putting the PinnableSlice tests here due to similarity to Cleanable tests
220 TEST_F(CleanableTest
, PinnableSlice
) {
223 const std::string const_str
= "123";
227 PinnableSlice4Test value
;
228 Slice
slice(const_str
);
229 value
.PinSlice(slice
, Multiplier
, &res
, &n2
);
231 str
.assign(value
.data(), value
.size());
232 ASSERT_EQ(const_str
, str
);
239 PinnableSlice4Test value
;
240 Slice
slice(const_str
);
243 c1
.RegisterCleanup(Multiplier
, &res
, &n2
); // res = 2;
244 value
.PinSlice(slice
, &c1
);
247 ASSERT_EQ(1, res
); // cleanups must have be delegated to value
249 str
.assign(value
.data(), value
.size());
250 ASSERT_EQ(const_str
, str
);
256 PinnableSlice4Test value
;
257 Slice
slice(const_str
);
258 value
.PinSelf(slice
);
260 str
.assign(value
.data(), value
.size());
261 ASSERT_EQ(const_str
, str
);
265 PinnableSlice4Test value
;
266 std::string
* self_str_ptr
= value
.GetSelf();
267 self_str_ptr
->assign(const_str
);
270 str
.assign(value
.data(), value
.size());
271 ASSERT_EQ(const_str
, str
);
275 static void Decrement(void* intptr
, void*) { --*static_cast<int*>(intptr
); }
277 // Allow unit testing moved-from data
279 void MarkInitializedForClangAnalyze(T
& t
) {
280 // No net effect, but confuse analyzer. (Published advice doesn't work.)
281 char* p
= reinterpret_cast<char*>(&t
);
285 TEST_F(CleanableTest
, SharedWrapCleanables
) {
288 c1
.RegisterCleanup(&Decrement
, &val
, nullptr);
289 c1
.RegisterCleanup(&Decrement
, &val
, nullptr);
290 ASSERT_TRUE(c1
.HasCleanups());
291 ASSERT_FALSE(c2
.HasCleanups());
293 SharedCleanablePtr scp1
;
294 ASSERT_EQ(scp1
.get(), nullptr);
297 scp1
.RegisterCopyWith(&c2
);
298 scp1
.MoveAsCleanupTo(&c2
);
300 ASSERT_FALSE(c2
.HasCleanups());
301 c2
.RegisterCleanup(&Decrement
, &val
, nullptr);
302 c2
.RegisterCleanup(&Decrement
, &val
, nullptr);
303 c2
.RegisterCleanup(&Decrement
, &val
, nullptr);
306 ASSERT_NE(scp1
.get(), nullptr);
307 ASSERT_FALSE(scp1
->HasCleanups());
309 // Copy ctor (alias scp2 = scp1)
310 SharedCleanablePtr scp2
{scp1
};
311 ASSERT_EQ(scp1
.get(), scp2
.get());
313 c1
.DelegateCleanupsTo(&*scp1
);
314 ASSERT_TRUE(scp1
->HasCleanups());
315 ASSERT_TRUE(scp2
->HasCleanups());
316 ASSERT_FALSE(c1
.HasCleanups());
318 SharedCleanablePtr scp3
;
319 ASSERT_EQ(scp3
.get(), nullptr);
321 // Copy operator (alias scp3 = scp2 = scp1)
324 // Make scp2 point elsewhere
326 c2
.DelegateCleanupsTo(&*scp2
);
329 // Move operator, invoke old c2 cleanups
330 scp2
= std::move(scp1
);
332 MarkInitializedForClangAnalyze(scp1
);
333 ASSERT_EQ(scp1
.get(), nullptr);
337 SharedCleanablePtr scp4
{std::move(scp3
)};
338 MarkInitializedForClangAnalyze(scp3
);
339 ASSERT_EQ(scp3
.get(), nullptr);
340 ASSERT_EQ(scp4
.get(), scp2
.get());
344 // invoke old c1 cleanups
349 TEST_F(CleanableTest
, CleanableWrapShared
) {
351 SharedCleanablePtr scp1
, scp2
;
353 scp1
->RegisterCleanup(&Decrement
, &val
, nullptr);
354 scp1
->RegisterCleanup(&Decrement
, &val
, nullptr);
357 scp2
->RegisterCleanup(&Decrement
, &val
, nullptr);
358 scp2
->RegisterCleanup(&Decrement
, &val
, nullptr);
359 scp2
->RegisterCleanup(&Decrement
, &val
, nullptr);
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);
374 ASSERT_FALSE(c2
.HasCleanups());
376 // invoke cleanups from scp2
379 // invoke cleanups from scp1
384 } // namespace ROCKSDB_NAMESPACE
386 int main(int argc
, char** argv
) {
387 ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
388 ::testing::InitGoogleTest(&argc
, argv
);
389 return RUN_ALL_TESTS();