]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/sharedptr_registry.hpp
update ceph source to reef 18.2.0
[ceph.git] / ceph / src / common / sharedptr_registry.hpp
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #ifndef CEPH_SHAREDPTR_REGISTRY_H
16 #define CEPH_SHAREDPTR_REGISTRY_H
17
18 #include <map>
19 #include <memory>
20 #include "common/ceph_mutex.h"
21
22 /**
23 * Provides a registry of shared_ptr<V> indexed by K while
24 * the references are alive.
25 */
26 template <class K, class V, class C = std::less<K> >
27 class SharedPtrRegistry {
28 public:
29 typedef std::shared_ptr<V> VPtr;
30 typedef std::weak_ptr<V> WeakVPtr;
31 int waiting;
32 private:
33 ceph::mutex lock = ceph::make_mutex("SharedPtrRegistry::lock");
34 ceph::condition_variable cond;
35 std::map<K, std::pair<WeakVPtr, V*>, C> contents;
36
37 class OnRemoval {
38 SharedPtrRegistry<K,V,C> *parent;
39 K key;
40 public:
41 OnRemoval(SharedPtrRegistry<K,V,C> *parent, K key) :
42 parent(parent), key(key) {}
43 void operator()(V *to_remove) {
44 {
45 std::lock_guard l(parent->lock);
46 typename std::map<K, std::pair<WeakVPtr, V*>, C>::iterator i =
47 parent->contents.find(key);
48 if (i != parent->contents.end() &&
49 i->second.second == to_remove) {
50 parent->contents.erase(i);
51 parent->cond.notify_all();
52 }
53 }
54 delete to_remove;
55 }
56 };
57 friend class OnRemoval;
58
59 public:
60 SharedPtrRegistry() :
61 waiting(0)
62 {}
63
64 bool empty() {
65 std::lock_guard l(lock);
66 return contents.empty();
67 }
68
69 bool get_next(const K &key, std::pair<K, VPtr> *next) {
70 std::pair<K, VPtr> r;
71 {
72 std::lock_guard l(lock);
73 VPtr next_val;
74 typename std::map<K, std::pair<WeakVPtr, V*>, C>::iterator i =
75 contents.upper_bound(key);
76 while (i != contents.end() &&
77 !(next_val = i->second.first.lock()))
78 ++i;
79 if (i == contents.end())
80 return false;
81 if (next)
82 r = std::make_pair(i->first, next_val);
83 }
84 if (next)
85 *next = r;
86 return true;
87 }
88
89
90 bool get_next(const K &key, std::pair<K, V> *next) {
91 VPtr next_val;
92 std::lock_guard l(lock);
93 typename std::map<K, std::pair<WeakVPtr, V*>, C>::iterator i =
94 contents.upper_bound(key);
95 while (i != contents.end() &&
96 !(next_val = i->second.first.lock()))
97 ++i;
98 if (i == contents.end())
99 return false;
100 if (next)
101 *next = std::make_pair(i->first, *next_val);
102 return true;
103 }
104
105 VPtr lookup(const K &key) {
106 std::unique_lock l(lock);
107 waiting++;
108 while (1) {
109 typename std::map<K, std::pair<WeakVPtr, V*>, C>::iterator i =
110 contents.find(key);
111 if (i != contents.end()) {
112 VPtr retval = i->second.first.lock();
113 if (retval) {
114 waiting--;
115 return retval;
116 }
117 } else {
118 break;
119 }
120 cond.wait(l);
121 }
122 waiting--;
123 return VPtr();
124 }
125
126 VPtr lookup_or_create(const K &key) {
127 std::unique_lock l(lock);
128 waiting++;
129 while (1) {
130 typename std::map<K, std::pair<WeakVPtr, V*>, C>::iterator i =
131 contents.find(key);
132 if (i != contents.end()) {
133 VPtr retval = i->second.first.lock();
134 if (retval) {
135 waiting--;
136 return retval;
137 }
138 } else {
139 break;
140 }
141 cond.wait(l);
142 }
143 V *ptr = new V();
144 VPtr retval(ptr, OnRemoval(this, key));
145 contents.insert(std::make_pair(key, make_pair(retval, ptr)));
146 waiting--;
147 return retval;
148 }
149
150 unsigned size() {
151 std::lock_guard l(lock);
152 return contents.size();
153 }
154
155 void remove(const K &key) {
156 std::lock_guard l(lock);
157 contents.erase(key);
158 cond.notify_all();
159 }
160
161 template<class A>
162 VPtr lookup_or_create(const K &key, const A &arg) {
163 std::unique_lock l(lock);
164 waiting++;
165 while (1) {
166 typename std::map<K, std::pair<WeakVPtr, V*>, C>::iterator i =
167 contents.find(key);
168 if (i != contents.end()) {
169 VPtr retval = i->second.first.lock();
170 if (retval) {
171 waiting--;
172 return retval;
173 }
174 } else {
175 break;
176 }
177 cond.wait(l);
178 }
179 V *ptr = new V(arg);
180 VPtr retval(ptr, OnRemoval(this, key));
181 contents.insert(std::make_pair(key, make_pair(retval, ptr)));
182 waiting--;
183 return retval;
184 }
185
186 friend class SharedPtrRegistryTest;
187 };
188
189 #endif