XRootD
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 
36 #include "XrdSsi/XrdSsiAtomics.hh"
37 
38 template<class T>
39 class XrdSsiRRTable;
40 
41 template<class T>
43 {
44 public:
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 
78 private:
79  T* item;
80  XrdSsiRRTable<T> *tab;
81  uint64_t reqid;
82 };
83 
84 template<class T>
86 {
87 public:
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.
91 XrdSsiRRTableItem<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 
105 void 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 //
112 bool 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 //
129 void 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 //
151 void 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 
171 void 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 //
177 XrdSsiRRTableItem<T> LookUp(uint64_t itemID)
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 
192 int 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 //
197 void 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 
244 private:
245 void 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 
309 struct 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  };
322 XrdSsiMutex rrtMutex;
323 ItemInfo baseItem;
324 uint64_t baseKey;
325 std::map<uint64_t, ItemInfo> theMap;
326 XrdSysCondVar wCond;
327 int nDef;
328 };
329 #endif
void Lock(XrdSsiMutex *mutex)
XrdSsiRRTableItem(const XrdSsiRRTableItem &other)=delete
XrdSsiRRTableItem & operator=(XrdSsiRRTableItem &&other)
XrdSsiRRTableItem(T *_item, XrdSsiRRTable< T > *_tab, uint64_t itemID)
XrdSsiRRTableItem & operator=(const XrdSsiRRTableItem &)=delete
uint64_t reqID() const
XrdSsiRRTableItem(XrdSsiRRTableItem &&other)
bool DeferFinalize(T *item, uint64_t itemID)
XrdSsiRRTableItem< T > Add(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)