ATLAS Offline Software
ConcurrentHashmapImpl.h
Go to the documentation of this file.
1 // This file's extension implies that it's C, but it's really -*- C++ -*-.
2 /*
3  * Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration.
4  */
14 #ifndef CXXUTILS_CONCURRENTHASHMAPIMPL_H
15 #define CXXUTILS_CONCURRENTHASHMAPIMPL_H
16 
17 
18 #include "CxxUtils/bitscan.h"
20 #include "CxxUtils/concepts.h"
21 #include <functional>
22 #include <cstdint>
23 #include <cstdlib>
24 #include <atomic>
25 #include <mutex>
26 #include <memory>
27 #include <new>
28 
29 
30 class ConcurrentHashmapImplTest;
31 
32 
33 namespace CxxUtils {
34 namespace detail {
35 
36 
41 using ConcurrentHashmapVal_t = uintptr_t;
42 
43 
44 #if HAVE_CONCEPTS
45 
46 
52 template <class T>
53 concept IsConcurrentHashmapPayload = std::is_standard_layout_v<T> &&
54  std::is_trivial_v<T> &&
55  sizeof (T) <= sizeof (ConcurrentHashmapVal_t);
56 
57 
58 #endif
59 
60 
61 
66  : public std::unique_lock<std::mutex>
67 {
68 public:
69  using std::unique_lock<std::mutex>::unique_lock;
70 };
71 
72 
91 template <unsigned ENTRIES_PER_CACHELINE>
93 {
95  static constexpr size_t ENTRIES_PER_CACHELINE_MASK = ENTRIES_PER_CACHELINE-1;
96 
104  CHMTableIterator (size_t hash, size_t mask, size_t maskBits, size_t probeLimit);
105 
106 
110  size_t offset() const;
111 
112 
116  size_t nprobes() const;
117 
118 
124  bool next();
125 
126 
127 private:
130  const size_t m_mask;
132  const size_t m_boffs;
134  const size_t m_stride;
136  const size_t m_probeLimit;
138  size_t m_bucket;
140  size_t m_nprobes;
141 };
142 
143 
202 template <template <class> class UPDATER_,
203  typename HASHER_ = std::hash<uintptr_t>,
204  typename MATCHER_ = std::equal_to<uintptr_t>,
205  uintptr_t NULLVAL_ = 0,
206  uintptr_t TOMBSTONE_ = NULLVAL_>
208 {
209 public:
213  using Hasher_t = HASHER_;
215  using Matcher_t = MATCHER_;
217  static constexpr uintptr_t nullval = NULLVAL_;
219  static constexpr uintptr_t tombstone = TOMBSTONE_;
221  static constexpr size_t INVALID = static_cast<size_t>(-1);
222 
225 
226 
227 private:
229  struct entry_t {
230  std::atomic<val_t> m_key;
231  std::atomic<val_t> m_val;
232  };
233 
235  static constexpr size_t CACHELINE = 64;
236 
237  // Ensure that entries will evenly pack a cache line.
238  // If CACHELINE is a power of two, this implies that sizeof(entry_t)
239  // is as well.
240  static_assert (CACHELINE >= sizeof (entry_t) &&
241  CACHELINE % sizeof(entry_t) == 0);
242 
244  static constexpr size_t ENTRIES_PER_CACHELINE = CACHELINE / sizeof(entry_t);
246  static constexpr size_t ENTRIES_PER_CACHELINE_MASK = (ENTRIES_PER_CACHELINE-1);
247 
249  friend class ::ConcurrentHashmapImplTest;
250 
251 
261  class alignas(CACHELINE) Table
262  {
263  public:
265 
266 
273  Table (size_t capacity,
274  const Hasher_t& hasher = Hasher_t(),
275  const Matcher_t& matcher = Matcher_t());
276 
277 
285  static void* operator new (size_t, size_t capacity);
286 
287 
291  void operator delete (void* p);
292 
293 
301  size_t probeRead (val_t key, size_t hash) const;
302 
303 
315  size_t probeWrite (val_t key, size_t hash, bool& insert);
316 
317 
321  size_t capacity() const;
322 
323 
328  const entry_t& entry (size_t offset) const;
329 
330 
335  entry_t& entry (size_t offset);
336 
337 
338  private:
340  const size_t m_capacity;
342  const size_t m_maxProbe;
344  const size_t m_mask;
346  const size_t m_maskBits;
352  std::atomic<size_t> m_longestProbe;
354  alignas(CACHELINE) entry_t m_entries[1];
355  };
356 
357 
358 public:
360  using Updater_t = UPDATER_<Table>;
362  using Context_t = typename Updater_t::Context_t;
363 
364 
365 
376  size_t capacity_in,
377  const Hasher_t& hasher,
378  const Matcher_t& matcher,
379  const typename Updater_t::Context_t& ctx);
380 
381 
382  // Don't implement copying.
383  // This should be done by derived classes, if desired.
386 
387 
392  size_t size() const;
393 
394 
398  size_t capacity() const;
399 
400 
404  size_t erased() const;
405 
406 
410  const Hasher_t& hasher() const;
411 
412 
416  const Matcher_t& matcher() const;
417 
418 
426  {
427  public:
434  const_iterator (const Table& table, bool end);
435 
436 
443  const_iterator (const Table& table, size_t offset);
444 
445 
449  void next();
450 
451 
455  void prev();
456 
457 
463  val_t key() const;
464 
465 
469  val_t value() const;
470 
471 
475  bool operator!= (const const_iterator& other) const;
476 
477 
481  bool valid() const;
482 
483 
484  private:
486  const Table& m_table;
489  size_t m_offset;
490  };
491 
492 
502 
503 
517  std::pair<const_iterator, bool>
518  put (val_t key, size_t hash, val_t val,
519  bool overwrite,
520  const typename Updater_t::Context_t& ctx);
521 
522 
537  std::pair<const_iterator, bool>
538  put (const Lock_t& lock,
539  val_t key, size_t hash, val_t val,
540  bool overwrite,
541  const typename Updater_t::Context_t& ctx);
542 
543 
551  const_iterator get (val_t key, size_t hash) const;
552 
553 
569  bool erase (val_t key, size_t hash);
570 
571 
588  bool erase (const Lock_t& lock, val_t key, size_t hash);
589 
590 
592  using const_iterator_range = std::pair<const_iterator, const_iterator>;
593 
594 
599 
600 
604  const_iterator begin() const;
605 
606 
610  const_iterator end() const;
611 
612 
620  const_iterator clear (size_t capacity,
621  const typename Updater_t::Context_t& ctx);
622 
623 
630  const_iterator clear (const typename Updater_t::Context_t& ctx);
631 
632 
640  void forceClear();
641 
642 
651  void reserve (size_t capacity,
652  const typename Updater_t::Context_t& ctx);
653 
654 
660  void quiescent (const typename Updater_t::Context_t& ctx);
661 
662 
675 
676 
681 
682 
683 private:
690  bool grow (const Lock_t& lock, const typename Updater_t::Context_t& ctx);
691 
692 
700  bool grow (const Lock_t& lock, size_t new_capacity, const typename Updater_t::Context_t& ctx);
701 
702 
704 
705 
713  Table* m_table;
715  std::atomic<size_t> m_size;
717  std::atomic<size_t> m_erased;
720 };
721 
722 
723 } // namespace detail
724 
725 
726 } // namespace CxxUtils
727 
728 
730 
731 
732 #endif // not CXXUTILS_CONCURRENTHASHMAPIMPL_H
CxxUtils::detail::ConcurrentHashmapImpl::matcher
const Matcher_t & matcher() const
Return the matcher object.
CxxUtils::detail::ConcurrentHashmapImpl::m_table
Table * m_table
The current table instance. Must be holding the mutex to access this.
Definition: ConcurrentHashmapImpl.h:713
CxxUtils::detail::ConcurrentHashmapImpl::clear
const_iterator clear(size_t capacity, const typename Updater_t::Context_t &ctx)
Erase the table and change the capacity.
CxxUtils::SimpleUpdater< Table >
CxxUtils::detail::ConcurrentHashmapImpl::operator=
ConcurrentHashmapImpl & operator=(const ConcurrentHashmapImpl &)=delete
CxxUtils::detail::ConcurrentHashmapImpl::tombstone
static constexpr uintptr_t tombstone
Tombstone key value. Must be different from nullval to allow erasures.
Definition: ConcurrentHashmapImpl.h:219
CxxUtils::detail::CHMTableIterator::m_stride
const size_t m_stride
Base increment between probes.
Definition: ConcurrentHashmapImpl.h:134
CxxUtils::detail::CHMTableIterator
Helper to generate hash probes.
Definition: ConcurrentHashmapImpl.h:93
CxxUtils::detail::ConcurrentHashmapImpl::entry_t::m_key
std::atomic< val_t > m_key
Definition: ConcurrentHashmapImpl.h:230
CxxUtils::detail::ConcurrentHashmapImpl::entry_t
One entry in the hash table.
Definition: ConcurrentHashmapImpl.h:229
CxxUtils::detail::ConcurrentHashmapVal_t
uintptr_t ConcurrentHashmapVal_t
Type used for keys and values — an unsigned big enough to hold a pointer.
Definition: ConcurrentHashmapImpl.h:41
CxxUtils::detail::ConcurrentHashmapImpl::swap
void swap(ConcurrentHashmapImpl &other)
Swap this container with another.
CxxUtils::detail::ConcurrentHashmapImpl::Table::capacity
size_t capacity() const
The number of entries in the table.
CxxUtils::detail::ConcurrentHashmapImpl::Table::probeWrite
size_t probeWrite(val_t key, size_t hash, bool &insert)
Find a table entry for writing.
CxxUtils::detail::CHMTableIterator::m_nprobes
size_t m_nprobes
Number of probes tried so far.
Definition: ConcurrentHashmapImpl.h:140
CxxUtils::detail::ConcurrentHashmapImpl::erase
bool erase(const Lock_t &lock, val_t key, size_t hash)
Erase an entry from the table, with external locking.
BeamSpot::mutex
std::mutex mutex
Definition: InDetBeamSpotVertex.cxx:18
CxxUtils::detail::ConcurrentHashmapImpl::Table::entry
const entry_t & entry(size_t offset) const
Return the entry for an offset.
CxxUtils::detail::CHMTableIterator::m_bucket
size_t m_bucket
Index of the start of the cacheline currently being probed.
Definition: ConcurrentHashmapImpl.h:138
CxxUtils::detail::ConcurrentHashmapImpl::Table::Table
Table(size_t capacity, const Hasher_t &hasher=Hasher_t(), const Matcher_t &matcher=Matcher_t())
Constructor.
CxxUtils::detail::ConcurrentHashmapImpl::put
std::pair< const_iterator, bool > put(val_t key, size_t hash, val_t val, bool overwrite, const typename Updater_t::Context_t &ctx)
Add an entry to the table.
CxxUtils::detail::ConcurrentHashmapImpl::erased
size_t erased() const
The number of erased elements in the current table.
detail
Definition: extract_histogram_tag.cxx:14
CxxUtils::detail::ConcurrentHashmapImpl::const_iterator::prev
void prev()
Move the iterator back to the previous occupied entry.
CxxUtils::detail::ConcurrentHashmapImpl::Table::probeRead
size_t probeRead(val_t key, size_t hash) const
Find a table entry for reading.
CxxUtils::detail::ConcurrentHashmapImpl::round_up
static uint64_t round_up(uint64_t)
CxxUtils::detail::CHMTableIterator::CHMTableIterator
CHMTableIterator(size_t hash, size_t mask, size_t maskBits, size_t probeLimit)
Constructor.
CxxUtils::detail::ConcurrentHashmapImpl::m_updater
Updater_t m_updater
Updater object managing memory. See above.
Definition: ConcurrentHashmapImpl.h:707
CxxUtils::detail::ConcurrentHashmapImpl::const_iterator::next
void next()
Advance the iterator to the next occupied entry.
CxxUtils::detail::ConcurrentHashmapImpl::quiescent
void quiescent(const typename Updater_t::Context_t &ctx)
Called when this thread is no longer referencing anything from this container.
CxxUtils::detail::ConcurrentHashmapImpl
Hash table allowing concurrent, lockless reads.
Definition: ConcurrentHashmapImpl.h:208
atomic_fetch_minmax.h
Atomic min/max functions.
CxxUtils::detail::ConcurrentHashmapImpl::Table::m_matcher
const Matcher_t & m_matcher
The key match object.
Definition: ConcurrentHashmapImpl.h:350
python.utils.AtlRunQueryLookup.mask
string mask
Definition: AtlRunQueryLookup.py:460
CxxUtils::detail::ConcurrentHashmapImpl::CACHELINE
static constexpr size_t CACHELINE
Assumed length in bytes of one cache line.
Definition: ConcurrentHashmapImpl.h:235
CxxUtils::detail::ConcurrentHashmapImpl::forceClear
void forceClear()
Erase the table by filling it with nulls.
CxxUtils::detail::ConcurrentHashmapImpl< CxxUtils::SimpleUpdater, Hasher, Matcher >::val_t
ConcurrentHashmapVal_t val_t
Type used for keys and values — an unsigned big enough to hold a pointer.
Definition: ConcurrentHashmapImpl.h:211
CxxUtils::detail::ConcurrentHashmapImpl::capacity
size_t capacity() const
Return the current table size.
CxxUtils::detail::ConcurrentHashmapImpl::Table
Table of hash entries.
Definition: ConcurrentHashmapImpl.h:262
CxxUtils::detail::ConcurrentHashmapImpl::nullval
static constexpr uintptr_t nullval
Null key value.
Definition: ConcurrentHashmapImpl.h:217
CxxUtils::detail::ConcurrentHashmapImpl< CxxUtils::SimpleUpdater, Hasher, Matcher >::Context_t
typename Updater_t::Context_t Context_t
Context type for the updater.
Definition: ConcurrentHashmapImpl.h:362
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:210
CxxUtils::detail::ConcurrentHashmapImpl::const_iterator::key
val_t key() const
Return the key for this iterator.
CxxUtils::detail::ConcurrentHashmapImpl::const_iterator::m_offset
size_t m_offset
The current position in the table.
Definition: ConcurrentHashmapImpl.h:489
operator!=
bool operator!=(const DataVector< T > &a, const DataVector< T > &b)
Based on operator==.
CxxUtils::detail::ConcurrentHashmapImpl::grow
bool grow(const Lock_t &lock, const typename Updater_t::Context_t &ctx)
Make the table larger.
CxxUtils::detail::ConcurrentHashmapImpl::range
const_iterator_range range() const
Return a range that can be used to iterate over the container.
CxxUtils::detail::ConcurrentHashmapImpl::ENTRIES_PER_CACHELINE
static constexpr size_t ENTRIES_PER_CACHELINE
Number of entries in one cache line.
Definition: ConcurrentHashmapImpl.h:244
CxxUtils::detail::ConcurrentHashmapImpl::size
size_t size() const
Return the number of items currently stored.
CxxUtils
Definition: aligned_vector.h:29
CxxUtils::detail::ConcurrentHashmapImpl::entry_t::m_val
std::atomic< val_t > m_val
Definition: ConcurrentHashmapImpl.h:231
CxxUtils::detail::ConcurrentHashmapImpl::ConcurrentHashmapImpl
ConcurrentHashmapImpl(const ConcurrentHashmapImpl &)=delete
CxxUtils::detail::ConcurrentHashmapImpl::const_iterator::const_iterator
const_iterator(const Table &table, bool end)
Constructor.
CxxUtils::detail::ConcurrentHashmapImpl::ConcurrentHashmapImpl
ConcurrentHashmapImpl(Updater_t &&updater, size_t capacity_in, const Hasher_t &hasher, const Matcher_t &matcher, const typename Updater_t::Context_t &ctx)
Constructor.
CxxUtils::detail::ConcurrentHashmapImpl::Table::m_mask
const size_t m_mask
Mask for table indices (capacity-1).
Definition: ConcurrentHashmapImpl.h:344
xAOD::uint64_t
uint64_t
Definition: EventInfo_v1.cxx:123
CxxUtils::detail::ConcurrentHashmapImpl::lock
Lock_t lock()
Take a lock on the container.
CxxUtils::detail::ConcurrentHashmapImpl::get
const_iterator get(val_t key, size_t hash) const
Look up an entry in the table.
CxxUtils::detail::CHMTableIterator::m_boffs
const size_t m_boffs
Offset of the first entry we probe within its cacheline.
Definition: ConcurrentHashmapImpl.h:132
CxxUtils::detail::ConcurrentHashmapImpl::erase
bool erase(val_t key, size_t hash)
Erase an entry from the table.
ConcurrentHashmapImpl.icc
CxxUtils::detail::ConcurrentHashmapImpl::const_iterator
Bidirectional iterator over occupied table entries.
Definition: ConcurrentHashmapImpl.h:426
CxxUtils::detail::ConcurrentHashmapImpl::m_size
std::atomic< size_t > m_size
Number of entries in the map.
Definition: ConcurrentHashmapImpl.h:715
CxxUtils::detail::ConcurrentHashmapImpl::Table::m_maskBits
const size_t m_maskBits
Number of bits in the mask.
Definition: ConcurrentHashmapImpl.h:346
CxxUtils::detail::ConcurrentHashmapImpl::Table::entry
entry_t & entry(size_t offset)
Return the entry for an offset (non-const).
python.ext.table_printer.table
list table
Definition: table_printer.py:81
CxxUtils::detail::ConcurrentHashmapImpl::m_hasher
const Hasher_t m_hasher
The hash object.
Definition: ConcurrentHashmapImpl.h:709
CxxUtils::detail::ConcurrentHashmapImpl::m_matcher
const Matcher_t m_matcher
The key match object.
Definition: ConcurrentHashmapImpl.h:711
CxxUtils::detail::CHMTableIterator::next
bool next()
Move to the next probe.
CxxUtils::detail::ConcurrentHashmapImpl::m_erased
std::atomic< size_t > m_erased
Number of entries that have been erased.
Definition: ConcurrentHashmapImpl.h:717
CxxUtils::detail::ConcurrentHashmapImpl::const_iterator::m_table
const Table & m_table
The table over which we're iterating.
Definition: ConcurrentHashmapImpl.h:486
CxxUtils::detail::ConcurrentHashmapImpl::Table::m_capacity
const size_t m_capacity
Number of entries in the table. Must be a power of 2.
Definition: ConcurrentHashmapImpl.h:340
CxxUtils::detail::CHMTableIterator::ENTRIES_PER_CACHELINE_MASK
static constexpr size_t ENTRIES_PER_CACHELINE_MASK
Mask for the within-cacheline part of indices.
Definition: ConcurrentHashmapImpl.h:95
CxxUtils::detail::ConcurrentHashmapImpl::grow
bool grow(const Lock_t &lock, size_t new_capacity, const typename Updater_t::Context_t &ctx)
Make the table larger.
CxxUtils::detail::ConcurrentHashmapImpl::const_iterator::valid
bool valid() const
Check that the iterator is valid (not pointing at the end).
CxxUtils::detail::CHMTableIterator::offset
size_t offset() const
Offset of the element currently being probed.
concepts.h
Compatibility helpers for using some pieces of C++20 concepts with older compilers.
CxxUtils::detail::ConcurrentHashmapImpl::const_iterator::const_iterator
const_iterator(const Table &table, size_t offset)
Constructor.
InDetDD::other
@ other
Definition: InDetDD_Defs.h:16
CxxUtils::detail::ConcurrentHashmapImpl::ENTRIES_PER_CACHELINE_MASK
static constexpr size_t ENTRIES_PER_CACHELINE_MASK
Mask for the cache line part of an index.
Definition: ConcurrentHashmapImpl.h:246
CxxUtils::detail::ConcurrentHashmapImpl::begin
const_iterator begin() const
A begin iterator for the container.
CaloCondBlobAlgs_fillNoiseFromASCII.hash
dictionary hash
Definition: CaloCondBlobAlgs_fillNoiseFromASCII.py:109
CxxUtils::detail::CHMTableIterator::m_mask
const size_t m_mask
Mask for the table; i.e., capacity-1, but with the low bits corresponding to ENTRIES_PER_CACHELINE al...
Definition: ConcurrentHashmapImpl.h:130
CxxUtils::detail::HashmapLock
Helper to allow for external locking with put().
Definition: ConcurrentHashmapImpl.h:67
CxxUtils::detail::ConcurrentHashmapImpl::INVALID
static constexpr size_t INVALID
Used to represent an invalid table index.
Definition: ConcurrentHashmapImpl.h:221
CxxUtils::detail::ConcurrentHashmapImpl< CxxUtils::SimpleUpdater, Hasher, Matcher >::const_iterator_range
std::pair< const_iterator, const_iterator > const_iterator_range
Two iterators defining a range.
Definition: ConcurrentHashmapImpl.h:592
CxxUtils::detail::ConcurrentHashmapImpl::end
const_iterator end() const
An end iterator for the container.
Pythia8_RapidityOrderMPI.val
val
Definition: Pythia8_RapidityOrderMPI.py:14
CxxUtils::detail::ConcurrentHashmapImpl::put
std::pair< const_iterator, bool > put(const Lock_t &lock, val_t key, size_t hash, val_t val, bool overwrite, const typename Updater_t::Context_t &ctx)
Add an entry to the table, with external locking.
CxxUtils::detail::ConcurrentHashmapImpl::Table::m_longestProbe
std::atomic< size_t > m_longestProbe
Longest probe needed so far.
Definition: ConcurrentHashmapImpl.h:352
convertTimingResiduals.offset
offset
Definition: convertTimingResiduals.py:71
CxxUtils::detail::ConcurrentHashmapImpl::const_iterator::value
val_t value() const
Return the value for this iterator.
CxxUtils::detail::ConcurrentHashmapImpl< CxxUtils::SimpleUpdater, Hasher, Matcher >::Hasher_t
Hasher Hasher_t
Hash object.
Definition: ConcurrentHashmapImpl.h:213
CxxUtils::detail::ConcurrentHashmapImpl< CxxUtils::SimpleUpdater, Hasher, Matcher >::Matcher_t
Matcher Matcher_t
Key match object.
Definition: ConcurrentHashmapImpl.h:215
CxxUtils::detail::ConcurrentHashmapImpl::Table::m_maxProbe
const size_t m_maxProbe
Maximum number of probes allowed before resizing the table.
Definition: ConcurrentHashmapImpl.h:342
CxxUtils::detail::ConcurrentHashmapImpl::Table::m_hasher
const Hasher_t & m_hasher
The hash object.
Definition: ConcurrentHashmapImpl.h:348
CxxUtils::detail::ConcurrentHashmapImpl::updater
Updater_t & updater()
Access the Updater instance.
CxxUtils::detail::ConcurrentHashmapImpl::clear
const_iterator clear(const typename Updater_t::Context_t &ctx)
Erase the table (don't change the capacity).
CxxUtils::detail::ConcurrentHashmapImpl::m_mutex
std::mutex m_mutex
Mutex to serialize changes to the map.
Definition: ConcurrentHashmapImpl.h:719
CxxUtils::detail::CHMTableIterator::nprobes
size_t nprobes() const
Return the number of probes performed so far.
CxxUtils::detail::CHMTableIterator::m_probeLimit
const size_t m_probeLimit
Maximum number of probes to try.
Definition: ConcurrentHashmapImpl.h:136
bitscan.h
Bit scanning functions.
CxxUtils::detail::ConcurrentHashmapImpl::reserve
void reserve(size_t capacity, const typename Updater_t::Context_t &ctx)
Increase the table capacity.
mapkey::key
key
Definition: TElectronEfficiencyCorrectionTool.cxx:37
CxxUtils::detail::ConcurrentHashmapImpl::hasher
const Hasher_t & hasher() const
Return the hasher object.