XRootD
Loading...
Searching...
No Matches
XrdSsiRRTable.hh
Go to the documentation of this file.
1#ifndef __XRDSSIRRTABLE_HH__
2#define __XRDSSIRRTABLE_HH__
3/******************************************************************************/
4/* */
5/* X r d S s i R R T a b l e . h h */
6/* */
7/* (c) 2017 by the Board of Trustees of the Leland Stanford, Jr., University */
8/* Produced by Andrew Hanushevsky for Stanford University under contract */
9/* DE-AC02-76-SFO0515 with the Department of Energy */
10/* */
11/* This file is part of the XRootD software suite. */
12/* */
13/* XRootD is free software: you can redistribute it and/or modify it under */
14/* the terms of the GNU Lesser General Public License as published by the */
15/* Free Software Foundation, either version 3 of the License, or (at your */
16/* option) any later version. */
17/* */
18/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
19/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
20/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
21/* License for more details. */
22/* */
23/* You should have received a copy of the GNU Lesser General Public License */
24/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
25/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
26/* */
27/* The copyright holder's institutional names and contributor's names may not */
28/* be used to endorse or promote products derived from this software without */
29/* specific prior written permission of the institution or contributor. */
30/******************************************************************************/
31
32#include <map>
33#include <cstdint>
34#include <vector>
35
37
38template<class T>
39class XrdSsiRRTable;
40
41template<class T>
43{
44public:
45 XrdSsiRRTableItem() : item(0) { }
46
47 XrdSsiRRTableItem(T* _item, XrdSsiRRTable<T> *_tab, uint64_t itemID) :
48 item(_item), tab(_tab), reqid(itemID) { }
49
50 XrdSsiRRTableItem(XrdSsiRRTableItem &&other) : item(other.item), tab(other.tab),
51 reqid(other.reqid) { other.item = 0; }
52
53 XrdSsiRRTableItem(const XrdSsiRRTableItem &other) =delete;
54
56
58 {item = other.item;
59 tab = other.tab;
60 reqid = other.reqid;
61 other.item = 0;
62 return *this;
63 }
64
66
67 explicit operator bool() const { return item != nullptr; }
68
69 T& operator*() { return *item; }
70 T* operator->() { return item; }
71
72 void reset() { if (item) {tab->Release(item, reqid); item=0;} }
73
74 T* release() { T* itm=item; item=0; return itm; }
75
76 uint64_t reqID() const { return reqid; }
77
78private:
79 T* item;
81 uint64_t reqid;
82};
83
84template<class T>
86{
87public:
88
89// Init with refcounter to 2. One reference is for the entry in the
90// baseITem or theMap and other reference for item returned.
91XrdSsiRRTableItem<T> Add(T *item, uint64_t itemID)
92 {XrdSsiMutexMon lck(rrtMutex);
93 if ((baseItem.item && baseKey == itemID)
94 || theMap.count(itemID))
95 {return XrdSsiRRTableItem<T>();}
96 if (baseItem.item == 0)
97 {baseItem.Init(item, 2);
98 baseKey = itemID;
99 return XrdSsiRRTableItem(item, this, itemID);
100 }
101 theMap[itemID].Init(item, 2);
102 return XrdSsiRRTableItem(item, this, itemID);
103 }
104
105void Clear() {rrtMutex.Lock(); theMap.clear(); baseItem.item = 0; rrtMutex.UnLock();}
106
107// Called by the SsiFileReq when the request is complete. Return false indicates
108// we no longer have the request in the table, so XrdSsiFileReq::Finalize() can be
109// called immedatly. We return true to prevent Finalize() being called, but we
110// arrange to call it as the request leaves our table.
111//
112bool DeferFinalize(T *item, uint64_t itemID)
113 {XrdSsiMutexMon lck(rrtMutex);
114 if (baseItem.item && baseKey == itemID)
115 {if (baseItem.item != item) return false;
116 baseItem.deferedFinalize = true;
117 return true;
118 }
119 typename std::map<uint64_t,ItemInfo>::iterator it = theMap.find(itemID);
120 if (it == theMap.end()) return false;
121 ItemInfo &info = it->second;
122 if (info.item != item) return false;
123 info.deferedFinalize = true;
124 return true;
125 }
126
127// Called once XrdSsiFileReq::Finalize() has been called for an request in our table.
128//
129void DeferredFinalizeDone(T *item, uint64_t itemID)
130 {XrdSsiMutexMon lck(rrtMutex);
131 wCond.Lock();
132 nDef--;
133 wCond.Broadcast();
134 wCond.UnLock();
135 if (baseItem.item && baseKey == itemID)
136 {
137 if (baseItem.item != item) return;
138 baseItem.item = 0;
139 return;
140 }
141 typename std::map<uint64_t,ItemInfo>::iterator it = theMap.find(itemID);
142 if (it == theMap.end()) return;
143 ItemInfo &info = it->second;
144 if (info.item != item) return;
145 theMap.erase(it);
146 }
147
148// Mark request as deleted from the table (LookUp will not longer return it).
149// Request will stay in the table until reference count becomes zero.
150//
151void Del(uint64_t itemID) {Decr(itemID, true);}
152
153// Mark request as deleted and also to be finalized once refernce count reaches zero.
154// Blocks until the refernce count reaches zero.
156 {if (!r) return;
157 uint64_t itemID = r.reqID();
158 T* item = r.release();
159 Decr(itemID, true, item, true, 1);
160 XrdSsiMutexMon lck(rrtMutex);
161 while((baseItem.item && baseKey == itemID) ||
162 theMap.count(itemID))
163 {wCond.Lock();
164 lck.UnLock();
165 do { wCond.Wait(); } while(nDef>0);
166 wCond.UnLock();
167 lck.Lock(&rrtMutex);
168 }
169 }
170
171void Release(T* item, uint64_t itemID) {Decr(itemID, false, item, false, 1);}
172
173// Return a request object pointer from the table. Request pointer is wrapped in
174// an XrdSsiRRTableItem to take care of decreasing the reference count when
175// 'item' container is destroyed.
176//
178 {XrdSsiMutexMon lck(rrtMutex);
179 if (baseItem.item && baseKey == itemID)
180 {if (baseItem.deleted) return XrdSsiRRTableItem<T>();
181 baseItem.refcount++;
182 return XrdSsiRRTableItem(baseItem.item, this, itemID);
183 }
184 typename std::map<uint64_t,ItemInfo>::iterator it = theMap.find(itemID);
185 if (it == theMap.end()) return XrdSsiRRTableItem<T>();
186 ItemInfo &info = it->second;
187 if (info.deleted) return XrdSsiRRTableItem<T>();
188 info.refcount++;
189 return XrdSsiRRTableItem(info.item, this, itemID);
190 }
191
192int Num() {return theMap.size() + (baseItem.item ? 1 : 0);}
193
194// Finalize all remaining requests and block until the reference counts
195// have falled to zero.
196//
197void Reset()
198 {XrdSsiMutexMon lck(rrtMutex);
199 std::vector<std::pair<T*,uint64_t>> tofin;
200 if (baseItem.item && baseItem.refcount > 0)
201 {if (!baseItem.deleted)
202 {baseItem.deleted = true;
203 baseItem.refcount--;
204 baseItem.deferedFinalize = true;
205 }
206 if (baseItem.refcount <= 0)
207 {tofin.push_back(std::make_pair(baseItem.item,baseKey));}
208 }
209 for(auto it=theMap.begin(); it!=theMap.end(); ++it)
210 {ItemInfo &info = it->second;
211 if (info.refcount <= 0) continue;
212 if (!info.deleted)
213 {info.deleted = true;
214 info.refcount--;
215 info.deferedFinalize=true;
216 }
217 if (info.refcount <= 0) tofin.push_back(std::make_pair(info.item,it->first));
218 }
219 lck.UnLock();
220 for(auto &fpair : tofin)
221 {T* f=fpair.first;
222 uint64_t itemID=fpair.second;
223 wCond.Lock();
224 nDef++;
225 wCond.UnLock();
226 f->Finalize();
227 DeferredFinalizeDone(f, itemID);
228 }
229
230 lck.Lock(&rrtMutex);
231 while(baseItem.item || theMap.size() != 0)
232 {wCond.Lock();
233 lck.UnLock();
234 do { wCond.Wait(); } while(nDef>0);
235 wCond.UnLock();
236 lck.Lock(&rrtMutex);
237 }
238 }
239
240 XrdSsiRRTable() : baseKey(0), wCond(0), nDef(0) {}
241
243
244private:
245void Decr(uint64_t itemID, bool del=false, T* item=0, bool fin=false, int ecnt=0)
246 {XrdSsiMutexMon lck(rrtMutex);
247 if (baseItem.item && baseKey == itemID)
248 {if (item && baseItem.item != item) return;
249 if (baseItem.refcount <=0) return;
250 if (!baseItem.deleted)
251 {if (fin) baseItem.deferedFinalize=true;
252 if (del)
253 {baseItem.refcount--;
254 baseItem.deleted = true;
255 }
256 }
257 baseItem.refcount -= ecnt;
258 T *f=0;
259 if (baseItem.refcount <= 0)
260 {if (baseItem.deferedFinalize)
261 { f = baseItem.item; baseItem.deleted = true; }
262 else { wCond.Lock(); wCond.Broadcast(); wCond.UnLock(); baseItem.item = 0; }
263 }
264 lck.UnLock();
265 if (f)
266 {wCond.Lock();
267 nDef++;
268 wCond.UnLock();
269 if (fin)
270 {f->Finalize();
271 DeferredFinalizeDone(f, itemID);
272 }
273 else f->DeferredFinalize();
274 }
275 return;
276 }
277 typename std::map<uint64_t,ItemInfo>::iterator it = theMap.find(itemID);
278 if (it == theMap.end()) return;
279 ItemInfo &info = it->second;
280 if (item && info.item != item) return;
281 if (info.refcount <= 0) return;
282 if (!info.deleted)
283 {if (fin) info.deferedFinalize=true;
284 if (del)
285 {info.refcount--;
286 info.deleted = true;
287 }
288 }
289 info.refcount -= ecnt;
290 T* f=0;
291 if (info.refcount <= 0)
292 {if (info.deferedFinalize)
293 { f=info.item; info.deleted = true; }
294 else { wCond.Lock(); wCond.Broadcast(); wCond.UnLock(); theMap.erase(it); }
295 }
296 lck.UnLock();
297 if (f)
298 {wCond.Lock();
299 nDef++;
300 wCond.UnLock();
301 if (fin)
302 {f->Finalize();
303 DeferredFinalizeDone(f, itemID);
304 }
305 else f->DeferredFinalize();
306 }
307 }
308
309struct ItemInfo
310 {int refcount;
311 bool deferedFinalize;
312 bool deleted;
313 T *item;
314 ItemInfo() {Init(0,0);}
315 void Init(T* _item, int cnt)
316 {refcount = cnt;
317 deferedFinalize = false;
318 deleted = false;
319 item = _item;
320 }
321 };
322XrdSsiMutex rrtMutex;
323ItemInfo baseItem;
324uint64_t baseKey;
325std::map<uint64_t, ItemInfo> theMap;
326XrdSysCondVar wCond;
327int nDef;
328};
329#endif
void Lock(XrdSsiMutex *mutex)
XrdSsiRRTableItem(const XrdSsiRRTableItem &other)=delete
XrdSsiRRTableItem(T *_item, XrdSsiRRTable< T > *_tab, uint64_t itemID)
XrdSsiRRTableItem & operator=(XrdSsiRRTableItem &&other)
uint64_t reqID() const
XrdSsiRRTableItem & operator=(const XrdSsiRRTableItem &)=delete
XrdSsiRRTableItem(XrdSsiRRTableItem &&other)
XrdSsiRRTableItem< T > Add(T *item, uint64_t itemID)
bool DeferFinalize(T *item, uint64_t itemID)
void Del(uint64_t itemID)
void Release(T *item, uint64_t itemID)
XrdSsiRRTableItem< T > LookUp(uint64_t itemID)
void DeferredFinalizeDone(T *item, uint64_t itemID)
void DelFinalize(XrdSsiRRTableItem< T > &&r)