ATLAS Offline Software
IdentifiableCacheBase.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 // $Id: IdentifiableCacheBase.cxx 791541 2017-01-09 10:43:53Z smh $
13 // null --- default state.
14 // ABORTED -- conversion failed or returned null
15 // ptr > null && ptr < ABORTED --- Have payload
16 // INVALID --- Conversion in progress or intention to add soon.
17 
20 #include <bit>
21 
22 namespace EventContainers {
23 
24 const void* const INVALID = std::bit_cast<const void*>(IdentifiableCacheBase::INVALIDflag);
25 const void* const ABORTED = std::bit_cast<const void*>(IdentifiableCacheBase::ABORTEDflag);
26 
27 
28 
30  const IMaker* maker)
31  : m_vec(maxHash),
32  m_maker (maker),
33  m_currentHashes(0)
34 {
35 }
36 
37 
39 
41  const void *ptr1 =nullptr;
42 
43  if(m_vec[hash].compare_exchange_strong(ptr1, INVALID, std::memory_order_relaxed, std::memory_order_relaxed)){//atomic swap (replaces ptr1 with value)
44  //First call
45  //Setup the IDC_WriteHandle to "lock" on this hash's pointer
46  lock.LockOn(&m_vec[hash]);
47  return 0;
48  }
49 
50  if(ptr1 == INVALID){
51  //Second call while not finished
52  wait.emplace_back(hash);
53  return 1;
54  }
55  if(ptr1 == ABORTED) return 3;
56  return 2; //Already completed
57 }
58 
59 
61 {
62  size_t s = m_vec.size();
63  if(0 != m_currentHashes.load(std::memory_order_relaxed)){
64  for (size_t i=0; i<s ;i++) {
65  const void* ptr = m_vec[i].load(std::memory_order_relaxed);
66  m_vec[i].store(nullptr, std::memory_order_relaxed);
67  if (ptr && ptr < ABORTED){
68  deleter (ptr);
69  }
70  }
71  m_currentHashes.store(0, std::memory_order_relaxed);
72  }else{
73  for (size_t i=0; i<s ;i++) m_vec[i].store(nullptr, std::memory_order_relaxed);//Need to clear incase of aborts
74  }
75 }
76 
77 
78 //Does not lock or clear atomics to allow faster destruction
80 {
81  std::atomic_thread_fence(std::memory_order_acquire);
82  if(0 != m_currentHashes.load(std::memory_order_relaxed)){ //Reduce overhead if cache was unused
83  size_t s = m_vec.size();
84  for (size_t i=0; i<s ;i++) {
85  const void* p = m_vec[i].load(std::memory_order_relaxed);
86  if(p && p < ABORTED) deleter (p);
87  }
88  }
89 }
90 
92  const void* p = m_vec[hash].load(std::memory_order_relaxed); //Relaxed because it is not returning a pointer to anything
93  return (p == ABORTED);
94 }
95 
96 
98  const void* p = m_vec[hash].load(std::memory_order_relaxed); //Relaxed because it is not returning a pointer to anything
99  return (p == INVALID);
100 }
101 
102 
104 {
105  if (ATH_UNLIKELY(hash >= m_vec.size())) return nullptr;
106  const void* p = m_vec[hash].load(std::memory_order_acquire);
107  if (p >= ABORTED)
108  return nullptr;
109  return p;
110 }
111 
113 {
114  std::atomic<const void*> &myatomic = m_vec[hash];
115  const void* item = myatomic.load(std::memory_order_acquire);
116  //Wait until pointer is set then retrieve and verify
117  while(item == INVALID){//Loop to check for spurious wakeups
118  myatomic.wait(item, std::memory_order_relaxed);
119  item = myatomic.load(std::memory_order_acquire);
120  }
121  return item;
122 }
123 
125 {
126  if (ATH_UNLIKELY(hash >= m_vec.size())) return nullptr;
127  const void* p = waitFor(hash);
128  if(p>=ABORTED) return nullptr;
129  return p;
130 }
131 
133 {
134  m_vec[hash].notify_all();
135 }
136 
138 {
139  // If it's there already, return directly without locking.
140  const void* ptr = nullptr;
141  if (ATH_UNLIKELY(hash >= m_vec.size())) return ptr;
142 
143  if(m_vec[hash].compare_exchange_strong(ptr, INVALID) ) {//Exchanges ptr with current value!!
144  // Make the payload.
145  if(m_maker == nullptr){
146  m_vec[hash].store( ABORTED );
147  return nullptr;
148  }
149  uniqueLock lock(m_mutex, std::defer_lock);
150  if(!m_maker->m_IsReEntrant) lock.lock();//Allow reentrant or non reentrant makers
151 
152  try {
153  ptr = m_maker->typelessMake (hash).release();
154  }
155  catch (...) {
156  // FIXME: Can this be done with RAII?
157  notifyHash(hash);
158  throw;
159  }
160  assert(m_vec[hash] == INVALID);
161  if(ptr){
162  m_vec[hash].store( ptr );
163  m_currentHashes++;
164  }else{
165  m_vec[hash].store( ABORTED );
166  }
167  notifyHash(hash);
168  }
169  else if(ptr == INVALID){
170  ptr= waitFor(hash);
171  }
172  if(ptr == ABORTED) return nullptr;
173  assert(ptr < ABORTED);
174  return ptr;
175 }
176 
177 void IdentifiableCacheBase::createSet (const std::vector<IdentifierHash>& hashes, std::vector<bool> &mask){
178  assert(mask.size() == fullSize());
179  for(IdentifierHash hash : hashes){
180  const void* ptr = get(hash);
181  if(ptr !=nullptr) mask[hash] = true;
182  }
183 }
184 
185 
187 {
188  return m_currentHashes.load(std::memory_order_relaxed); //Not to be used for syncing
189 }
190 
191 std::vector<IdentifierHash> IdentifiableCacheBase::ids()
192 {
193  std::vector<IdentifierHash> ret;
194  ret.reserve (m_currentHashes.load(std::memory_order_relaxed));
195  size_t s = m_vec.size();
196  for (size_t i =0; i<s; i++) {
197  const void* p = m_vec[i].load(std::memory_order_relaxed);
198  if (p && p < ABORTED)
199  ret.push_back (i);
200  }
201  return ret;
202 }
203 
204 
205 std::pair<bool, const void*> IdentifiableCacheBase::add (IdentifierHash hash, const void* p) noexcept
206 {
207  if (ATH_UNLIKELY(hash >= m_vec.size())) return std::make_pair(false, nullptr);
208  if(p==nullptr) return std::make_pair(false, nullptr);
209  const void* nul=nullptr;
210  if(m_vec[hash].compare_exchange_strong(nul, p, std::memory_order_release, std::memory_order_relaxed)){
211  m_currentHashes.fetch_add(1, std::memory_order_relaxed);
212  return std::make_pair(true, p);
213  }
214  const void* invalid = INVALID;
215  if(m_vec[hash].compare_exchange_strong(invalid, p, std::memory_order_release, std::memory_order_acquire)){
216  m_currentHashes.fetch_add(1, std::memory_order_relaxed);
217  notifyHash(hash);
218  return std::make_pair(true, p);
219  }
220  return std::make_pair(false, invalid);
221 }
222 
223 
224 std::pair<bool, const void*> IdentifiableCacheBase::addLock (IdentifierHash hash, const void* p) noexcept
225 { //Same as method above except we check for invalid state first,
226  // more optimal for calling using writehandle lock method
227  assert(hash < m_vec.size());
228  if(p==nullptr) return std::make_pair(false, nullptr);
229  const void* invalid = INVALID;
230  if(m_vec[hash].compare_exchange_strong(invalid, p, std::memory_order_release, std::memory_order_relaxed)){
231  m_currentHashes.fetch_add(1, std::memory_order_relaxed);
232  notifyHash(hash);
233  return std::make_pair(true, p);
234  }
235  const void* nul=nullptr;
236  if(m_vec[hash].compare_exchange_strong(nul, p, std::memory_order_release, std::memory_order_acquire)){
237  m_currentHashes.fetch_add(1, std::memory_order_relaxed);
238  return std::make_pair(true, p);
239  }
240  return std::make_pair(false, nul);
241 }
242 
243 std::pair<bool, const void*> IdentifiableCacheBase::addLock (IdentifierHash hash,
244  void_unique_ptr p) noexcept
245 {
246  std::pair<bool, const void*> b = addLock(hash, p.get());
247  if(b.first) p.release();
248  return b;
249 }
250 
251 
252 std::pair<bool, const void*> IdentifiableCacheBase::add (IdentifierHash hash,
253  void_unique_ptr p) noexcept
254 {
255  std::pair<bool, const void*> b = add(hash, p.get());
256  if(b.first) p.release();
257  return b;
258 }
259 
260 
261 
262 } // namespace EventContainers
263 
264 
EventContainers::ABORTED
const void *const ABORTED
Definition: IdentifiableCacheBase.cxx:25
python.root_lsr_rank.hashes
hashes
Definition: root_lsr_rank.py:34
IdentifiableCacheBase.h
SGTest::store
TestStore store
Definition: TestStore.cxx:23
EventContainers::IdentifiableCacheBase::findWait
const void * findWait(IdentifierHash hash)
Retrieve ptr, will wait if there is something in progress.
Definition: IdentifiableCacheBase.cxx:124
EventContainers::IdentifiableCacheBase::get
const void * get(IdentifierHash hash)
Try to make payload if not there.
Definition: IdentifiableCacheBase.cxx:137
EventContainers::IdentifiableCacheBase::ABORTEDflag
static constexpr uintptr_t ABORTEDflag
Definition: IdentifiableCacheBase.h:28
EventContainers::INVALID
const void *const INVALID
Definition: IdentifiableCacheBase.cxx:24
EventContainers::IdentifiableCacheBase::IMaker::m_IsReEntrant
bool m_IsReEntrant
Definition: IdentifiableCacheBase.h:37
EventContainers::IdentifiableCacheBase::numberOfHashes
size_t numberOfHashes()
In a concurrent situation this number isn't necessarily perfectly synchronised with ids()....
Definition: IdentifiableCacheBase.cxx:186
EventContainers::IdentifiableCacheBase::m_mutex
mutex_t m_mutex
Definition: IdentifiableCacheBase.h:99
EventContainers::IdentifiableCacheBase::m_maker
const IMaker * m_maker
Definition: IdentifiableCacheBase.h:94
ATH_UNLIKELY
#define ATH_UNLIKELY(x)
Definition: AthUnlikelyMacros.h:17
python.RatesEmulationExample.lock
lock
Definition: RatesEmulationExample.py:148
EventContainers
Definition: T_AthenaPoolCreateFuncs.h:33
dbg::ptr
void * ptr(T *p)
Definition: SGImplSvc.cxx:74
python.utils.AtlRunQueryLookup.mask
string mask
Definition: AtlRunQueryLookup.py:459
AthUnlikelyMacros.h
PyPoolBrowser.item
item
Definition: PyPoolBrowser.py:129
EventContainers::IdentifiableCacheBase::~IdentifiableCacheBase
~IdentifiableCacheBase()
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:209
lumiFormat.i
int i
Definition: lumiFormat.py:85
deleter_f
void deleter_f(const void *p)
Definition: deleter.h:13
add
bool add(const std::string &hname, TKey *tobj)
Definition: fastadd.cxx:55
EventContainers::IdentifiableCacheBase::IdentifiableCacheBase
IdentifiableCacheBase(IdentifierHash maxHash, const IMaker *maker)
Definition: IdentifiableCacheBase.cxx:29
EventContainers::IdentifiableCacheBase::tryLock
int tryLock(IdentifierHash, IDC_WriteHandleBase &, std::vector< IdentifierHash > &)
Checks if the item is completed if it is not started it extablishes lock (returns 0),...
Definition: IdentifiableCacheBase.cxx:40
EventContainers::IdentifiableCacheBase::fullSize
size_t fullSize() const
Definition: IdentifiableCacheBase.h:81
EventContainers::IdentifiableCacheBase::uniqueLock
std::unique_lock< mutex_t > uniqueLock
Definition: IdentifiableCacheBase.h:98
EventContainers::IdentifiableCacheBase::clear
void clear(deleter_f *deleter)
Definition: IdentifiableCacheBase.cxx:60
EventContainers::IdentifiableCacheBase::itemAborted
int itemAborted(IdentifierHash)
Returns 1 is the item has been aborted otherwise 0.
Definition: IdentifiableCacheBase.cxx:91
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:76
EventContainers::IdentifiableCacheBase::notifyHash
void notifyHash(IdentifierHash hash)
Definition: IdentifiableCacheBase.cxx:132
EventContainers::IdentifiableCacheBase::m_currentHashes
std::atomic< size_t > m_currentHashes
Holds the number of valid hashes in container, in concurrent use it is not guaranteed to be up to dat...
Definition: IdentifiableCacheBase.h:101
EventContainers::IdentifiableCacheBase::m_vec
std::vector< std::atomic< const void * > > m_vec
Definition: IdentifiableCacheBase.h:92
EventContainers::IdentifiableCacheBase::createSet
void createSet(const std::vector< IdentifierHash > &hashes, std::vector< bool > &mask)
Create a set of hashes, updates an IDC mask as appropriate.
Definition: IdentifiableCacheBase.cxx:177
void_unique_ptr
Definition: deleter.h:17
EventContainers::IdentifiableCacheBase::IMaker::typelessMake
virtual void_unique_ptr typelessMake(IdentifierHash hash) const =0
EventContainers::IdentifiableCacheBase::itemInProgress
int itemInProgress(IdentifierHash)
Returns 1 is the item is inprogress otherwise 0.
Definition: IdentifiableCacheBase.cxx:97
CaloCondBlobAlgs_fillNoiseFromASCII.hash
dictionary hash
Definition: CaloCondBlobAlgs_fillNoiseFromASCII.py:108
EventContainers::IdentifiableCacheBase::find
const void * find(IdentifierHash hash) noexcept
Return payload if there, null if not there.
Definition: IdentifiableCacheBase.cxx:103
EventContainers::IdentifiableCacheBase::waitFor
const void * waitFor(IdentifierHash)
Halts the thread until the require hash is completed or aborted.
Definition: IdentifiableCacheBase.cxx:112
EventContainers::IdentifiableCacheBase::add
std::pair< bool, const void * > add(IdentifierHash hash, const void *p) noexcept
Definition: IdentifiableCacheBase.cxx:205
EventContainers::IdentifiableCacheBase::ids
std::vector< IdentifierHash > ids()
In a threaded situation this collection will be valid but will not container hashes later added.
Definition: IdentifiableCacheBase.cxx:191
EventContainers::IDC_WriteHandleBase
Definition: IDC_WriteHandleBase.h:13
python.SystemOfUnits.s
float s
Definition: SystemOfUnits.py:147
EventContainers::IdentifiableCacheBase::IMaker
Definition: IdentifiableCacheBase.h:36
IdentifierHash
This is a "hash" representation of an Identifier. This encodes a 32 bit index which can be used to lo...
Definition: IdentifierHash.h:25
EventContainers::IdentifiableCacheBase::INVALIDflag
static constexpr uintptr_t INVALIDflag
Definition: IdentifiableCacheBase.h:27
EventContainers::IdentifiableCacheBase::addLock
std::pair< bool, const void * > addLock(IdentifierHash hash, const void *p) noexcept
Definition: IdentifiableCacheBase.cxx:224
EventContainers::IdentifiableCacheBase::cleanUp
void cleanUp(deleter_f *deleter)
Definition: IdentifiableCacheBase.cxx:79