]>
git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/util/cleanable.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 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7 // Use of this source code is governed by a BSD-style license that can be
8 // found in the LICENSE file. See the AUTHORS file for names of contributors.
10 #include "rocksdb/cleanable.h"
16 namespace ROCKSDB_NAMESPACE
{
18 Cleanable::Cleanable() {
19 cleanup_
.function
= nullptr;
20 cleanup_
.next
= nullptr;
23 Cleanable::~Cleanable() { DoCleanup(); }
25 Cleanable::Cleanable(Cleanable
&& other
) noexcept
{ *this = std::move(other
); }
27 Cleanable
& Cleanable::operator=(Cleanable
&& other
) noexcept
{
28 assert(this != &other
); // https://stackoverflow.com/a/9322542/454544
29 cleanup_
= other
.cleanup_
;
30 other
.cleanup_
.function
= nullptr;
31 other
.cleanup_
.next
= nullptr;
35 // If the entire linked list was on heap we could have simply add attach one
36 // link list to another. However the head is an embeded object to avoid the cost
37 // of creating objects for most of the use cases when the Cleanable has only one
38 // Cleanup to do. We could put evernything on heap if benchmarks show no
39 // negative impact on performance.
40 // Also we need to iterate on the linked list since there is no pointer to the
41 // tail. We can add the tail pointer but maintainin it might negatively impact
42 // the perforamnce for the common case of one cleanup where tail pointer is not
43 // needed. Again benchmarks could clarify that.
44 // Even without a tail pointer we could iterate on the list, find the tail, and
45 // have only that node updated without the need to insert the Cleanups one by
46 // one. This however would be redundant when the source Cleanable has one or a
47 // few Cleanups which is the case most of the time.
48 // TODO(myabandeh): if the list is too long we should maintain a tail pointer
49 // and have the entire list (minus the head that has to be inserted separately)
50 // merged with the target linked list at once.
51 void Cleanable::DelegateCleanupsTo(Cleanable
* other
) {
52 assert(other
!= nullptr);
53 if (cleanup_
.function
== nullptr) {
56 Cleanup
* c
= &cleanup_
;
57 other
->RegisterCleanup(c
->function
, c
->arg1
, c
->arg2
);
59 while (c
!= nullptr) {
60 Cleanup
* next
= c
->next
;
61 other
->RegisterCleanup(c
);
64 cleanup_
.function
= nullptr;
65 cleanup_
.next
= nullptr;
68 void Cleanable::RegisterCleanup(Cleanable::Cleanup
* c
) {
70 if (cleanup_
.function
== nullptr) {
71 cleanup_
.function
= c
->function
;
72 cleanup_
.arg1
= c
->arg1
;
73 cleanup_
.arg2
= c
->arg2
;
76 c
->next
= cleanup_
.next
;
81 void Cleanable::RegisterCleanup(CleanupFunction func
, void* arg1
, void* arg2
) {
82 assert(func
!= nullptr);
84 if (cleanup_
.function
== nullptr) {
88 c
->next
= cleanup_
.next
;
96 struct SharedCleanablePtr::Impl
: public Cleanable
{
97 std::atomic
<unsigned> ref_count
{1}; // Start with 1 ref
98 void Ref() { ref_count
.fetch_add(1, std::memory_order_relaxed
); }
100 if (ref_count
.fetch_sub(1, std::memory_order_relaxed
) == 1) {
105 static void UnrefWrapper(void* arg1
, void* /*arg2*/) {
106 static_cast<SharedCleanablePtr::Impl
*>(arg1
)->Unref();
110 void SharedCleanablePtr::Reset() {
117 void SharedCleanablePtr::Allocate() {
122 SharedCleanablePtr::SharedCleanablePtr(const SharedCleanablePtr
& from
) {
126 SharedCleanablePtr::SharedCleanablePtr(SharedCleanablePtr
&& from
) noexcept
{
127 *this = std::move(from
);
130 SharedCleanablePtr
& SharedCleanablePtr::operator=(
131 const SharedCleanablePtr
& from
) {
142 SharedCleanablePtr
& SharedCleanablePtr::operator=(
143 SharedCleanablePtr
&& from
) noexcept
{
144 assert(this != &from
); // https://stackoverflow.com/a/9322542/454544
151 SharedCleanablePtr::~SharedCleanablePtr() { Reset(); }
153 Cleanable
& SharedCleanablePtr::operator*() {
154 return *ptr_
; // implicit upcast
157 Cleanable
* SharedCleanablePtr::operator->() {
158 return ptr_
; // implicit upcast
161 Cleanable
* SharedCleanablePtr::get() {
162 return ptr_
; // implicit upcast
165 void SharedCleanablePtr::RegisterCopyWith(Cleanable
* target
) {
167 // "Virtual" copy of the pointer
169 target
->RegisterCleanup(&Impl::UnrefWrapper
, ptr_
, nullptr);
173 void SharedCleanablePtr::MoveAsCleanupTo(Cleanable
* target
) {
175 // "Virtual" move of the pointer
176 target
->RegisterCleanup(&Impl::UnrefWrapper
, ptr_
, nullptr);
181 } // namespace ROCKSDB_NAMESPACE