Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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/Mutex.h"
21 #include "common/Cond.h"
22
23 /**
24  * Provides a registry of shared_ptr<V> indexed by K while
25  * the references are alive.
26  */
27 template <class K, class V, class C = std::less<K> >
28 class SharedPtrRegistry {
29 public:
30   typedef ceph::shared_ptr<V> VPtr;
31   typedef ceph::weak_ptr<V> WeakVPtr;
32   int waiting;
33 private:
34   Mutex lock;
35   Cond cond;
36   map<K, pair<WeakVPtr, V*>, C> contents;
37
38   class OnRemoval {
39     SharedPtrRegistry<K,V,C> *parent;
40     K key;
41   public:
42     OnRemoval(SharedPtrRegistry<K,V,C> *parent, K key) :
43       parent(parent), key(key) {}
44     void operator()(V *to_remove) {
45       {
46         Mutex::Locker l(parent->lock);
47         typename map<K, pair<WeakVPtr, V*>, C>::iterator i =
48           parent->contents.find(key);
49         if (i != parent->contents.end() &&
50             i->second.second == to_remove) {
51           parent->contents.erase(i);
52           parent->cond.Signal();
53         }
54       }
55       delete to_remove;
56     }
57   };
58   friend class OnRemoval;
59
60 public:
61   SharedPtrRegistry() :
62     waiting(0),
63     lock("SharedPtrRegistry::lock")
64   {}
65
66   bool empty() {
67     Mutex::Locker l(lock);
68     return contents.empty();
69   }
70
71   bool get_next(const K &key, pair<K, VPtr> *next) {
72     pair<K, VPtr> r;
73     {
74       Mutex::Locker l(lock);
75       VPtr next_val;
76       typename map<K, pair<WeakVPtr, V*>, C>::iterator i =
77         contents.upper_bound(key);
78       while (i != contents.end() &&
79              !(next_val = i->second.first.lock()))
80         ++i;
81       if (i == contents.end())
82         return false;
83       if (next)
84         r = make_pair(i->first, next_val);
85     }
86     if (next)
87       *next = r;
88     return true;
89   }
90
91   
92   bool get_next(const K &key, pair<K, V> *next) {
93     VPtr next_val;
94     Mutex::Locker l(lock);
95     typename map<K, pair<WeakVPtr, V*>, C>::iterator i =
96       contents.upper_bound(key);
97     while (i != contents.end() &&
98            !(next_val = i->second.first.lock()))
99       ++i;
100     if (i == contents.end())
101       return false;
102     if (next)
103       *next = make_pair(i->first, *next_val);
104     return true;
105   }
106
107   VPtr lookup(const K &key) {
108     Mutex::Locker l(lock);
109     waiting++;
110     while (1) {
111       typename map<K, pair<WeakVPtr, V*>, C>::iterator i =
112         contents.find(key);
113       if (i != contents.end()) {
114         VPtr retval = i->second.first.lock();
115         if (retval) {
116           waiting--;
117           return retval;
118         }
119       } else {
120         break;
121       }
122       cond.Wait(lock);
123     }
124     waiting--;
125     return VPtr();
126   }
127
128   VPtr lookup_or_create(const K &key) {
129     Mutex::Locker l(lock);
130     waiting++;
131     while (1) {
132       typename map<K, pair<WeakVPtr, V*>, C>::iterator i =
133         contents.find(key);
134       if (i != contents.end()) {
135         VPtr retval = i->second.first.lock();
136         if (retval) {
137           waiting--;
138           return retval;
139         }
140       } else {
141         break;
142       }
143       cond.Wait(lock);
144     }
145     V *ptr = new V();
146     VPtr retval(ptr, OnRemoval(this, key));
147     contents.insert(make_pair(key, make_pair(retval, ptr)));
148     waiting--;
149     return retval;
150   }
151
152   unsigned size() {
153     Mutex::Locker l(lock);
154     return contents.size();
155   }
156
157   void remove(const K &key) {
158     Mutex::Locker l(lock);
159     contents.erase(key);
160     cond.Signal();
161   }
162
163   template<class A>
164   VPtr lookup_or_create(const K &key, const A &arg) {
165     Mutex::Locker l(lock);
166     waiting++;
167     while (1) {
168       typename map<K, pair<WeakVPtr, V*>, C>::iterator i =
169         contents.find(key);
170       if (i != contents.end()) {
171         VPtr retval = i->second.first.lock();
172         if (retval) {
173           waiting--;
174           return retval;
175         }
176       } else {
177         break;
178       }
179       cond.Wait(lock);
180     }
181     V *ptr = new V(arg);
182     VPtr retval(ptr, OnRemoval(this, key));
183     contents.insert(make_pair(key, make_pair(retval, ptr)));
184     waiting--;
185     return retval;
186   }
187
188   friend class SharedPtrRegistryTest;
189 };
190
191 #endif