| 
| 
  | concurrent_hash_map () | 
|   | Construct empty table. 
  | 
|   | 
|   | concurrent_hash_map (size_type n) | 
|   | Construct empty table with n preallocated buckets.  More...
  | 
|   | 
| 
  | concurrent_hash_map (const concurrent_hash_map &table) | 
|   | Copy constructor. 
  | 
|   | 
| 
  | concurrent_hash_map (concurrent_hash_map &&table) | 
|   | Move constructor. 
  | 
|   | 
| 
template<typename I >  | 
|   | concurrent_hash_map (I first, I last) | 
|   | Construction table with copying iteration range. 
  | 
|   | 
| 
  | concurrent_hash_map (std::initializer_list< value_type > il) | 
|   | Construct table with initializer list. 
  | 
|   | 
| void  | runtime_initialize () | 
|   | Initialize persistent concurrent hash map after process restart.  More...
  | 
|   | 
| concurrent_hash_map &  | operator= (const concurrent_hash_map &table) | 
|   | Assignment Not thread safe.  More...
  | 
|   | 
| concurrent_hash_map &  | operator= (std::initializer_list< value_type > il) | 
|   | Assignment Not thread safe.  More...
  | 
|   | 
| void  | rehash (size_type n=0) | 
|   | Rehashes and optionally resizes the whole table.  More...
  | 
|   | 
| void  | clear () | 
|   | Clear hash map content Not thread safe.  More...
  | 
|   | 
| void  | free_data () | 
|   | Should be called before concurrent_hash_map destructor is called.  More...
  | 
|   | 
|   | ~concurrent_hash_map () | 
|   | free_data should be called before concurrent_hash_map destructor is called.  More...
  | 
|   | 
| iterator  | begin () | 
|   | 
| iterator  | end () | 
|   | 
| const_iterator  | begin () const | 
|   | 
| const_iterator  | end () const | 
|   | 
| size_type  | size () const | 
|   | 
| bool  | empty () const | 
|   | 
| 
size_type  | max_size () const | 
|   | Upper bound on size. 
  | 
|   | 
| size_type  | bucket_count () const | 
|   | 
| void  | swap (concurrent_hash_map &table) | 
|   | Swap two instances.  More...
  | 
|   | 
| size_type  | count (const Key &key) const | 
|   | 
| template<typename K , typename  = typename std::enable_if<			  concurrent_hash_map_internal::				  has_transparent_key_equal<hasher>::value,			  K>::type>  | 
| size_type  | count (const K &key) const | 
|   | This overload only participates in overload resolution if the qualified-id Hash::transparent_key_equal is valid and denotes a type.  More...
  | 
|   | 
| bool  | find (const_accessor &result, const Key &key) const | 
|   | Find item and acquire a read lock on the item.  More...
  | 
|   | 
| template<typename K , typename  = typename std::enable_if<			  concurrent_hash_map_internal::				  has_transparent_key_equal<hasher>::value,			  K>::type>  | 
| bool  | find (const_accessor &result, const K &key) const | 
|   | Find item and acquire a read lock on the item.  More...
  | 
|   | 
| bool  | find (accessor &result, const Key &key) | 
|   | Find item and acquire a write lock on the item.  More...
  | 
|   | 
| template<typename K , typename  = typename std::enable_if<			  concurrent_hash_map_internal::				  has_transparent_key_equal<hasher>::value,			  K>::type>  | 
| bool  | find (accessor &result, const K &key) | 
|   | Find item and acquire a write lock on the item.  More...
  | 
|   | 
| bool  | insert (const_accessor &result, const Key &key) | 
|   | Insert item (if not already present) and acquire a read lock on the item.  More...
  | 
|   | 
| bool  | insert (accessor &result, const Key &key) | 
|   | Insert item (if not already present) and acquire a write lock on the item.  More...
  | 
|   | 
| bool  | insert (const_accessor &result, const value_type &value) | 
|   | Insert item by copying if there is no such key present already and acquire a read lock on the item.  More...
  | 
|   | 
| bool  | insert (accessor &result, const value_type &value) | 
|   | Insert item by copying if there is no such key present already and acquire a write lock on the item.  More...
  | 
|   | 
| bool  | insert (const value_type &value) | 
|   | Insert item by copying if there is no such key present already.  More...
  | 
|   | 
| bool  | insert (const_accessor &result, value_type &&value) | 
|   | Insert item by copying if there is no such key present already and acquire a read lock on the item.  More...
  | 
|   | 
| bool  | insert (accessor &result, value_type &&value) | 
|   | Insert item by copying if there is no such key present already and acquire a write lock on the item.  More...
  | 
|   | 
| bool  | insert (value_type &&value) | 
|   | Insert item by copying if there is no such key present already.  More...
  | 
|   | 
| template<typename I >  | 
| void  | insert (I first, I last) | 
|   | Insert range [first, last)  More...
  | 
|   | 
| void  | insert (std::initializer_list< value_type > il) | 
|   | Insert initializer list.  More...
  | 
|   | 
| template<typename M >  | 
| bool  | insert_or_assign (const key_type &key, M &&obj) | 
|   | Inserts item if there is no such key present already, assigns provided value otherwise.  More...
  | 
|   | 
| template<typename M >  | 
| bool  | insert_or_assign (key_type &&key, M &&obj) | 
|   | Inserts item if there is no such key present already, assigns provided value otherwise.  More...
  | 
|   | 
| template<typename K , typename M , typename  = typename std::enable_if<			concurrent_hash_map_internal::has_transparent_key_equal<				hasher>::value &&				std::is_constructible<key_type, K>::value,			K>::type>  | 
| bool  | insert_or_assign (K &&key, M &&obj) | 
|   | Inserts item if there is no such key-comparable type present already, assigns provided value otherwise.  More...
  | 
|   | 
| bool  | erase (const Key &key) | 
|   | Remove element with corresponding key.  More...
  | 
|   | 
| pobj_defrag_result  | defragment (double start_percent=0, double amount_percent=100) | 
|   | Defragment the given (by 'start_percent' and 'amount_percent') part of buckets of the hash map.  More...
  | 
|   | 
| template<typename K , typename  = typename std::enable_if<			  concurrent_hash_map_internal::				  has_transparent_key_equal<hasher>::value,			  K>::type>  | 
| bool  | erase (const K &key) | 
|   | Remove element with corresponding key.  More...
  | 
|   | 
template<typename Key, typename T, typename Hash, typename KeyEqual, typename MutexType, typename ScopedLockType>
class pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >
Persistent memory aware implementation of Intel TBB concurrent_hash_map. 
The implementation is based on a concurrent hash table algorithm (https://arxiv.org/ftp/arxiv/papers/1509/1509.02235.pdf) where elements assigned to buckets based on a hash code are calculated from a key. In addition to concurrent find, insert, and erase operations, the algorithm employs resizing and on-demand per-bucket rehashing. The hash table consists of an array of buckets, and each bucket consists of a list of nodes and a read-write lock to control concurrent access by multiple threads.
Each time, the pool with concurrent_hash_map is being opened, the concurrent_hash_map requires runtime_initialize() to be called (in order to recalculate mask and restore the size).
find(), insert(), erase() (and all overloads) are guaranteed to be thread-safe.
When a thread holds accessor to an element with a certain key, it is not allowed to call find, insert nor erase with that key.
MutexType defines type of read write lock used in concurrent_hash_map. ScopedLockType defines a mutex wrapper that provides RAII-style mechanism for owning a mutex. It should implement following methods and constructors: ScopedLockType() ScopedLockType(rw_mutex_type &m, bool write = true) void acquire(rw_mutex_type &m, bool write) void release() bool try_acquire(rw_mutex_type &m, bool write)
and optionally: bool upgrade_to_writer() bool downgrade_to_reader() bool is_writer (variable)
Implementing all optional methods and supplying is_writer variable can improve performance if MutexType supports efficient upgrading and downgrading operations.
Testing note: In some case, helgrind and drd might report lock ordering errors for concurrent_hash_map. This might happen when calling find, insert or erase while already holding an accessor to some element.
The typical usage example would be: 
#include <iostream>
#include <vector>
 
 
 
const int THREADS_NUM = 30;
const bool remove_hashmap = false;
 
struct root {
};
 
int
main(int argc, char *argv[])
{
    try {
        if (argc != 2)
            std::cerr << "usage: " << argv[0] << " file-name"
                  << std::endl;
 
        auto path = argv[1];
 
        try {
            std::cerr << e.what() << std::endl;
            return -1;
        }
 
        auto r = pop.
root()->pptr;
 
 
        if (r == nullptr) {
            
            
            
                r = make_persistent<hashmap_type>();
            });
 
            r->runtime_initialize();
        } else {
            
            
            
            
 
            r->runtime_initialize();
 
            
            try {
                r->defragment();
                std::cerr << "Defragmentation exception: "
                      << e.what() << std::endl;
                throw;
            }
        }
 
        auto &map = *r;
 
        std::vector<std::thread> threads;
        threads.reserve(static_cast<size_t>(THREADS_NUM));
 
        
        
        for (int i = 0; i < THREADS_NUM / 3; ++i) {
            threads.emplace_back([&]() {
                for (int i = 0; i < 10 * THREADS_NUM; ++i) {
                    map.insert(
                        hashmap_type::value_type(i, i));
                }
            });
        }
 
        
        
        for (int i = 0; i < THREADS_NUM / 3; ++i) {
            threads.emplace_back([&]() {
                for (int i = 0; i < 10 * THREADS_NUM; ++i) {
                    map.erase(i);
                }
            });
        }
 
        
        
        for (int i = 0; i < THREADS_NUM / 3; ++i) {
            threads.emplace_back([&]() {
                for (int i = 0; i < 10 * THREADS_NUM; ++i) {
                    hashmap_type::accessor acc;
                    bool res = map.find(acc, i);
 
                    if (res) {
                        assert(acc->first == i);
                        assert(acc->second >= i);
                        acc->second.get_rw() += 1;
                        pop.persist(acc->second);
                    }
                }
            });
        }
 
        for (auto &t : threads) {
            t.join();
        }
        try {
            
            map.defragment();
            std::cerr << "Defragmentation exception: " << e.what()
                  << std::endl;
            throw;
            std::cerr << "Defragmentation exception: " << e.what()
                  << std::endl;
            throw;
        } catch (const std::range_error &e) {
            std::cerr << "Defragmentation exception: " << e.what()
                  << std::endl;
            throw;
        } catch (const std::runtime_error &e) {
            std::cerr << "Defragmentation exception: " << e.what()
                  << std::endl;
            throw;
        }
        
        
        
        try {
            map.clear();
            std::cerr << "Clear exception: " << e.what()
                  << std::endl;
            throw;
            std::cerr << "Clear exception: " << e.what()
                  << std::endl;
            throw;
        }
 
        
        
        
        if (remove_hashmap) {
            map.free_data();
 
            
            
            
 
                delete_persistent<hashmap_type>(r);
            });
        }
        pop.close();
    } catch (std::exception &e) {
        std::cerr << "Exception occured: " << e.what() << std::endl;
        try {
            pop.close();
        } catch (const std::logic_error &e) {
            std::cerr << "Exception: " << e.what() << std::endl;
        }
        return -1;
    }
    return 0;
}