Inherits concurrent_hash_map_internal::hash_map_base< Key, T, MutexType, ScopedLockType >.
 | 
| 
  | 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 () | 
|   | Destroys the concurrent_hash_map.  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 are assigned to buckets based on a hash code 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>
 
 
using hashmap_type = concurrent_hash_map<p<int>, p<int>>;
 
const int THREADS_NUM = 30;
 
struct root {
    persistent_ptr<hashmap_type> pptr;
};
 
int
main(int argc, char *argv[])
{
    pool<root> pop;
    bool remove_hashmap = false;
 
    if (argc < 2)
        std::cerr << "usage: " << argv[0]
              << " file-name [remove_hashmap]" << std::endl;
 
    auto path = argv[1];
 
    if (argc == 3)
        remove_hashmap = std::string(argv[2]) == "1";
 
    try {
        std::cerr << e.what() << std::endl;
        return -1;
    }
 
    try {
        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::cout << map.size() << std::endl;
 
        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;
        }
 
        if (remove_hashmap) {
            
            try {
                map.clear();
                std::cerr << "Clear exception: " << e.what()
                      << std::endl;
                throw;
                std::cerr << "Clear exception: " << e.what()
                      << std::endl;
                throw;
            }
 
            
            map.free_data();
 
            
 
                delete_persistent<hashmap_type>(r);
                r = nullptr;
            });
        }
        std::cerr << "Exception occurred: " << e.what() << std::endl;
    } catch (std::exception &e) {
        std::cerr << "Exception occurred: " << e.what() << std::endl;
    }
 
    try {
        pop.close();
    } catch (const std::logic_error &e) {
        std::cerr << "Exception: " << e.what() << std::endl;
        return -1;
    }
 
    return 0;
}
Custom defrag error class.
Definition: pexceptions.hpp:225
 
Custom lock error class.
Definition: pexceptions.hpp:100
 
static void run(obj::pool_base &pool, std::function< void()> tx, Locks &... locks)
Execute a closure-like transaction and lock locks.
Definition: transaction.hpp:694
 
static pool< T > open(const std::string &path, const std::string &layout)
Opens an existing object store memory pool.
Definition: pool.hpp:672
 
Custom pool error class.
Definition: pexceptions.hpp:45
 
Custom transaction error class.
Definition: pexceptions.hpp:158
 
Custom out of memory error class.
Definition: pexceptions.hpp:138
 
A persistent version of concurrent hash map implementation Ref: https://arxiv.org/abs/1509....
 
Main libpmemobj namespace.
Definition: allocation_flag.hpp:18
 
Resides on pmem property template.
 
Persistent smart pointer.
 
 The example of storing strings without necessity of using transactions would be: 
#include <iostream>
#include <string>
#include <vector>
 
 
using hashmap_type =
 
const int THREADS_NUM = 30;
 
struct root {
};
 
int
main(int argc, char *argv[])
{
    bool remove_hashmap = false;
    int retval = 0;
 
    try {
        if (argc < 2) {
            std::cerr
                << "usage: " << argv[0]
                << " file-name [remove_hashmap]" << std::endl
                << "Before running this example, run:"
                << std::endl
                << "pmempool create obj --layout=\"cmap_string\" --size 1G path_to_a_pool"
                << std::endl;
            return -1;
        }
 
        auto path = argv[1];
 
        if (argc == 3)
            remove_hashmap = std::string(argv[2]) == "1";
 
        try {
            std::cerr << e.what() << std::endl;
            return -1;
        }
 
        auto &r = pop.
root()->pptr;
 
 
        if (r == nullptr) {
            
                r = pmem::obj::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::cout << " Number of elements at application startup: "
              << map.size() << std::endl;
 
        std::vector<std::thread> threads;
        threads.reserve(static_cast<size_t>(THREADS_NUM));
 
        
        for (int j = 0; j < THREADS_NUM / 3; ++j) {
            threads.emplace_back([&]() {
                for (int i = 0; i < 10 * THREADS_NUM; ++i) {
                    
                    map.insert_or_assign(i,
                                 std::to_string(i));
                }
            });
        }
 
        
        for (int j = 0; j < THREADS_NUM / 3; ++j) {
            threads.emplace_back([&]() {
                for (int i = 0; i < 10 * THREADS_NUM; ++i) {
                    
                    hashmap_type::const_accessor acc;
                    bool res = map.find(acc, i);
 
                    if (res) {
                        assert(acc->first == i);
                        
                            *element = &acc->second;
                        std::cout << element->
c_str()
 
                              << std::endl;
                    }
                }
            });
        }
 
        
        for (int j = 0; j < THREADS_NUM / 3; ++j) {
            threads.emplace_back([&]() {
                for (int i = 0; i < 10 * THREADS_NUM; ++i) {
                    map.erase(i);
                }
            });
        }
 
        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;
        }
 
        if (remove_hashmap) {
            
            try {
                map.clear();
                std::cerr << "Clear exception: " << e.what()
                      << std::endl;
                throw;
                std::cerr << "Clear exception: " << e.what()
                      << std::endl;
                throw;
            }
 
            
            map.free_data();
 
            
 
                pmem::obj::delete_persistent<hashmap_type>(r);
                r = nullptr;
            });
        }
        std::cerr << "Exception occurred: " << e.what() << std::endl;
        retval = -127;
    } catch (const std::exception &e) {
        std::cerr << "Exception occurred: " << e.what() << std::endl;
        retval = -1;
    }
    try {
    } catch (const std::logic_error &e) {
        std::cerr << "Exception occurred: " << e.what() << std::endl;
        retval = -2;
    }
    return retval;
}
pmem::obj::string - persistent container with std::basic_string compatible interface.
Definition: basic_string.hpp:46
 
const CharT * c_str() const noexcept
Definition: basic_string.hpp:3685
 
Persistent memory aware implementation of Intel TBB concurrent_hash_map.
Definition: concurrent_hash_map.hpp:1628
 
Persistent pointer class.
Definition: persistent_ptr.hpp:152
 
void close()
Closes the pool.
Definition: pool.hpp:255
 
PMEMobj pool class.
Definition: pool.hpp:482
 
persistent_ptr< T > root()
Retrieves pool's root object.
Definition: pool.hpp:644
 
String typedefs for common character types.