PMDK C++ bindings  1.12.1-rc1
This is the C++ bindings documentation for PMDK's libpmemobj.
Classes | Public Member Functions | Protected Member Functions | List of all members
pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType > Class Template Reference

Persistent memory aware implementation of Intel TBB concurrent_hash_map. More...

#include <libpmemobj++/container/concurrent_hash_map.hpp>

Classes

class  accessor
 Allows write access to elements and combines data access, locking, and garbage collection. More...
 
class  bucket_accessor
 Bucket accessor is to find, rehash, acquire a lock, and access a bucket. More...
 
class  const_accessor
 Combines data access, locking, and garbage collection. More...
 
class  mutex_vector
 Vector of locks to be unlocked at the destruction time. More...
 
class  serial_bucket_accessor
 Serial bucket accessor used to access bucket in a serial operations. More...
 

Public Member Functions

 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_mapoperator= (const concurrent_hash_map &table)
 Assignment Not thread safe. More...
 
concurrent_hash_mapoperator= (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...
 

Protected Member Functions

void internal_copy (const concurrent_hash_map &source)
 Copy "source" to *this, where *this must start out empty.
 
void defrag_save_nodes (bucket *b, pmem::obj::defrag &defrag)
 Internal method used by defragment(). More...
 

Detailed Description

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 namespace pmem::obj;
/* In this example we use concurrent_hash_map with p<int> type as
* both key and value. */
using hashmap_type = concurrent_hash_map<p<int>, p<int>>;
const int THREADS_NUM = 30;
/* This is basic example and we only need to use concurrent_hash_map. Hence we
* correlate memory pool root object with a single instance of persistent
* pointer to hashmap_type. */
struct root {
};
/* Before running this example, run:
* pmempool create obj --layout="concurrent_hash_map" --size 1G path_to_a_pool
*/
int
main(int argc, char *argv[])
{
bool remove_hashmap = false;
try {
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 {
pop = pool<root>::open(path, "concurrent_hash_map");
} catch (pmem::pool_error &e) {
std::cerr << e.what() << std::endl;
return -1;
}
auto &r = pop.root()->pptr;
if (r == nullptr) {
/* Logic when file was first opened. First, we have to
* allocate object of hashmap_type and attach it to the
* root object. */
r = make_persistent<hashmap_type>();
});
r->runtime_initialize();
} else {
/* Logic when hash_map already exists. After opening of
* the pool we have to call runtime_initialize()
* function in order to recalculate mask and check for
* consistency. */
r->runtime_initialize();
/* Defragment the whole pool at the beginning. */
try {
r->defragment();
} catch (const pmem::defrag_error &e) {
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));
/* Start THREADS_NUM/3 threads to insert key-value pairs
* to the hashmap. This operation is thread-safe. */
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));
}
});
}
/* Start THREADS_NUM/3 threads to erase key-value pairs
* from the hashmap. This operation is thread-safe. */
for (int i = 0; i < THREADS_NUM / 3; ++i) {
threads.emplace_back([&]() {
for (int i = 0; i < 10 * THREADS_NUM; ++i) {
map.erase(i);
}
});
}
/* Start THREADS_NUM/3 threads to check if given key is
* in the hashmap. For the time of an accessor life,
* the read-write lock is taken on the item. */
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 {
/* Defragment the whole pool at the end. */
map.defragment();
} catch (const pmem::defrag_error &e) {
std::cerr << "Defragmentation exception: " << e.what()
<< std::endl;
throw;
} catch (const pmem::lock_error &e) {
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) {
/* Firstly, erase remaining items in the map. This
* function is not thread-safe, hence the function is
* being called only after thread execution has
* completed. */
try {
map.clear();
} catch (const pmem::transaction_out_of_memory &e) {
std::cerr << "Clear exception: " << e.what()
<< std::endl;
throw;
} catch (const pmem::transaction_free_error &e) {
std::cerr << "Clear exception: " << e.what()
<< std::endl;
throw;
}
/* If hash map is to be removed, free_data() method
* should be called first. Otherwise, if deallocating
* internal hash map metadata in a destructor fails
* program might terminate. */
map.free_data();
/* map.clear() // WRONG
* After free_data() hash map cannot be used anymore! */
transaction::run(pop, [&] {
delete_persistent<hashmap_type>(r);
r = nullptr;
});
}
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;
}

The example of storing strings without necessity of using transactions would be:

#include <iostream>
#include <string>
#include <vector>
/* In this example we use concurrent_hash_map with p<int> type as
* keys and pmem::obj::string type for values. It shows, there is no need to
* explicitly use transacions if strings are stored in concurrent_hash_map. */
using hashmap_type =
const int THREADS_NUM = 30;
/* In this example we need to place concurrent_hash_map in the pool. Hence
* correlate memory pool root object with a single instance of persistent
* pointer to hashmap_type */
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 {
pop = pmem::obj::pool<root>::open(path, "cmap_string");
} catch (pmem::pool_error &e) {
std::cerr << e.what() << std::endl;
return -1;
}
auto &r = pop.root()->pptr;
if (r == nullptr) {
/* Logic when file was first opened. First, we have to
* allocate object of hashmap_type and attach it to the
* root object. */
r = pmem::obj::make_persistent<hashmap_type>();
});
r->runtime_initialize();
} else {
/* Logic when hash_map already exists. After opening of
* the pool we have to call runtime_initialize()
* function in order to recalculate mask and check for
* consistency. */
r->runtime_initialize();
/* Defragment the whole pool at the beginning */
try {
r->defragment();
} catch (const pmem::defrag_error &e) {
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));
/* Start THREADS_NUM/3 threads to insert key-value pairs
* to the hashmap. This operation is thread-safe. */
for (int j = 0; j < THREADS_NUM / 3; ++j) {
threads.emplace_back([&]() {
for (int i = 0; i < 10 * THREADS_NUM; ++i) {
/* Implicit conversion from std::string
* to pmem::obj::string. */
map.insert_or_assign(i,
std::to_string(i));
}
});
}
/* Start THREADS_NUM/3 threads to check if given key is
* in the hashmap. For the time of an accessor life,
* the read-write lock is taken on the item. */
for (int j = 0; j < THREADS_NUM / 3; ++j) {
threads.emplace_back([&]() {
for (int i = 0; i < 10 * THREADS_NUM; ++i) {
/* Usage of const_accessor, indicates
* read-only access */
hashmap_type::const_accessor acc;
bool res = map.find(acc, i);
if (res) {
assert(acc->first == i);
/* Pointer to the value may be
* used as long as the accessor
* object exists. */
*element = &acc->second;
std::cout << element->c_str()
<< std::endl;
}
}
});
}
/* Start THREADS_NUM/3 threads to erase key-value pairs
* from the hashmap. This operation is thread-safe. */
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 {
/* Defragment the whole pool at the end */
map.defragment();
} catch (const pmem::defrag_error &e) {
std::cerr << "Defragmentation exception: " << e.what()
<< std::endl;
throw;
} catch (const pmem::lock_error &e) {
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) {
/* Firstly, erase remaining items in the map. This
* function is not thread-safe, hence the function is
* being called only after thread execution has
* completed. */
try {
map.clear();
} catch (const pmem::transaction_out_of_memory &e) {
std::cerr << "Clear exception: " << e.what()
<< std::endl;
throw;
} catch (const pmem::transaction_free_error &e) {
std::cerr << "Clear exception: " << e.what()
<< std::endl;
throw;
}
/* If hash map is to be removed, free_data() method
* should be called first. Otherwise, if deallocating
* internal hash map metadata in a destructor fails
* program might terminate. */
map.free_data();
/* map.clear() // WRONG
* After free_data() concurrent hash map cannot be used
* anymore! */
pmem::obj::delete_persistent<hashmap_type>(r);
r = nullptr;
});
}
} catch (std::exception &e) {
std::cerr << "Exception occured: " << e.what() << std::endl;
retval = -1;
}
try {
pop.close();
} catch (const std::logic_error &e) {
std::cerr << "Exception: " << e.what() << std::endl;
retval = -2;
}
return retval;
}

Constructor & Destructor Documentation

◆ concurrent_hash_map()

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::concurrent_hash_map ( size_type  n)
inline

Construct empty table with n preallocated buckets.

This number serves also as initial concurrency level.

◆ ~concurrent_hash_map()

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::~concurrent_hash_map ( )
inline

free_data should be called before concurrent_hash_map destructor is called.

Otherwise, program can terminate if an exception occurs while freeing memory inside dtor.

Hash map can NOT be used after free_data() was called (unless it was called in a transaction and that transaction aborted).

Member Function Documentation

◆ begin() [1/2]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
iterator pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::begin ( )
inline
Returns
an iterator to the beginning Not thread safe.
Exceptions
pmem::transaction_scope_errorif called inside transaction

◆ begin() [2/2]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
const_iterator pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::begin ( ) const
inline
Returns
an iterator to the beginning Not thread safe.

◆ bucket_count()

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
size_type pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::bucket_count ( ) const
inline
Returns
the current number of buckets

◆ clear()

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
void pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::clear

Clear hash map content Not thread safe.

Exceptions
pmem::transaction_errorin case of PMDK transaction failure

◆ count() [1/2]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
template<typename K , typename = typename std::enable_if< concurrent_hash_map_internal:: has_transparent_key_equal<hasher>::value, K>::type>
size_type pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::count ( const K &  key) const
inline

This overload only participates in overload resolution if the qualified-id Hash::transparent_key_equal is valid and denotes a type.

This assumes that such Hash is callable with both K and Key type, and that its key_equal is transparent, which, together, allows calling this function without constructing an instance of Key

Returns
count of items (0 or 1)
Exceptions
pmem::transaction_scope_errorif called inside transaction

◆ count() [2/2]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
size_type pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::count ( const Key &  key) const
inline
Returns
count of items (0 or 1)
Exceptions
pmem::transaction_scope_errorif called inside transaction

◆ defrag_save_nodes()

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
void pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::defrag_save_nodes ( bucket *  b,
pmem::obj::defrag defrag 
)
inlineprotected

Internal method used by defragment().

Adds nodes to the defragmentation list.

◆ defragment()

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
pobj_defrag_result pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::defragment ( double  start_percent = 0,
double  amount_percent = 100 
)
inline

Defragment the given (by 'start_percent' and 'amount_percent') part of buckets of the hash map.

The algorithm is 'opportunistic' - if it is not able to lock a bucket it will just skip it.

Returns
result struct containing a number of relocated and total processed objects.
Exceptions
std::range_errorif the range: [start_percent, start_percent + amount_percent] is incorrect.
rethrowspmem::defrag_error when a failure during defragmentation occurs. Even if this error is thrown, some of objects could have been relocated, see in such case defrag_error.result for summary stats.

◆ empty()

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
bool pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::empty ( ) const
inline
Returns
true if size()==0.

◆ end() [1/2]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
iterator pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::end ( )
inline
Returns
an iterator to the end Not thread safe.

◆ end() [2/2]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
const_iterator pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::end ( ) const
inline
Returns
an iterator to the end Not thread safe.

◆ erase() [1/2]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
template<typename K , typename = typename std::enable_if< concurrent_hash_map_internal:: has_transparent_key_equal<hasher>::value, K>::type>
bool pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::erase ( const K &  key)
inline

Remove element with corresponding key.

This overload only participates in overload resolution if the qualified-id Hash::transparent_key_equal is valid and denotes a type. This assumes that such Hash is callable with both K and Key type, and that its key_equal is transparent, which, together, allows calling this function without constructing an instance of Key

Returns
true if element was deleted by this call
Exceptions
pmem::transaction_free_errorin case of PMDK unable to free the memory
pmem::transaction_scope_errorif called inside transaction

◆ erase() [2/2]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
bool pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::erase ( const Key &  key)
inline

Remove element with corresponding key.

Returns
true if element was deleted by this call
Exceptions
pmem::transaction_free_errorin case of PMDK unable to free the memory
pmem::transaction_scope_errorif called inside transaction

◆ find() [1/4]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
template<typename K , typename = typename std::enable_if< concurrent_hash_map_internal:: has_transparent_key_equal<hasher>::value, K>::type>
bool pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::find ( accessor result,
const K &  key 
)
inline

Find item and acquire a write lock on the item.

This overload only participates in overload resolution if the qualified-id Hash::transparent_key_equal is valid and denotes a type. This assumes that such Hash is callable with both K and Key type, and that its key_equal is transparent, which, together, allows calling this function without constructing an instance of Key

Returns
true if item is found, false otherwise.
Exceptions
pmem::transaction_scope_errorif called inside transaction

◆ find() [2/4]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
bool pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::find ( accessor result,
const Key &  key 
)
inline

Find item and acquire a write lock on the item.

Returns
true if item is found, false otherwise.
Exceptions
pmem::transaction_scope_errorif called inside transaction

◆ find() [3/4]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
template<typename K , typename = typename std::enable_if< concurrent_hash_map_internal:: has_transparent_key_equal<hasher>::value, K>::type>
bool pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::find ( const_accessor result,
const K &  key 
) const
inline

Find item and acquire a read lock on the item.

This overload only participates in overload resolution if the qualified-id Hash::transparent_key_equal is valid and denotes a type. This assumes that such Hash is callable with both K and Key type, and that its key_equal is transparent, which, together, allows calling this function without constructing an instance of Key

Returns
true if item is found, false otherwise.
Exceptions
pmem::transaction_scope_errorif called inside transaction

◆ find() [4/4]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
bool pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::find ( const_accessor result,
const Key &  key 
) const
inline

Find item and acquire a read lock on the item.

Returns
true if item is found, false otherwise.
Exceptions
pmem::transaction_scope_errorif called inside transaction

◆ free_data()

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
void pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::free_data ( )
inline

Destroys the concurrent_hash_map.

Unlike destructor it will throw an exception in case of any failure (e.g. not enough space for a transactional data). If that happens, it might be necessary to free some other data in the pool.

Should be called before concurrent_hash_map destructor is called. Otherwise, program can terminate if an exception occurs while freeing memory inside dtor.

Hash map can NOT be used after free_data() was called (unless this was done in a transaction and transaction aborted).

Exceptions
std::transaction_errorin case of PMDK transaction failure
pmem::transaction_free_errorwhen freeing underlying memory failed.

◆ insert() [1/10]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
bool pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::insert ( accessor result,
const Key &  key 
)
inline

Insert item (if not already present) and acquire a write lock on the item.

Returns
true if item is new.
Exceptions
pmem::transaction_alloc_erroron allocation failure.
pmem::transaction_scope_errorif called inside transaction

◆ insert() [2/10]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
bool pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::insert ( accessor result,
const value_type &  value 
)
inline

Insert item by copying if there is no such key present already and acquire a write lock on the item.

Returns
true if item is new.
Exceptions
pmem::transaction_scope_errorif called inside transaction

◆ insert() [3/10]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
bool pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::insert ( accessor result,
value_type &&  value 
)
inline

Insert item by copying if there is no such key present already and acquire a write lock on the item.

Returns
true if item is new.
Exceptions
pmem::transaction_alloc_erroron allocation failure.
pmem::transaction_scope_errorif called inside transaction

◆ insert() [4/10]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
bool pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::insert ( const value_type &  value)
inline

Insert item by copying if there is no such key present already.

Returns
true if item is inserted.
Exceptions
pmem::transaction_scope_errorif called inside transaction

◆ insert() [5/10]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
bool pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::insert ( const_accessor result,
const Key &  key 
)
inline

Insert item (if not already present) and acquire a read lock on the item.

Returns
true if item is new.
Exceptions
pmem::transaction_alloc_erroron allocation failure.
pmem::transaction_scope_errorif called inside transaction

◆ insert() [6/10]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
bool pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::insert ( const_accessor result,
const value_type &  value 
)
inline

Insert item by copying if there is no such key present already and acquire a read lock on the item.

Returns
true if item is new.
Exceptions
pmem::transaction_alloc_erroron allocation failure.
pmem::transaction_scope_errorif called inside transaction

◆ insert() [7/10]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
bool pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::insert ( const_accessor result,
value_type &&  value 
)
inline

Insert item by copying if there is no such key present already and acquire a read lock on the item.

Returns
true if item is new.
Exceptions
pmem::transaction_alloc_erroron allocation failure.
pmem::transaction_scope_errorif called inside transaction

◆ insert() [8/10]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
template<typename I >
void pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::insert ( first,
last 
)
inline

Insert range [first, last)

Exceptions
pmem::transaction_alloc_erroron allocation failure.
pmem::transaction_scope_errorif called inside transaction

◆ insert() [9/10]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
void pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::insert ( std::initializer_list< value_type >  il)
inline

Insert initializer list.

Exceptions
pmem::transaction_alloc_erroron allocation failure.
pmem::transaction_scope_errorif called inside transaction

◆ insert() [10/10]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
bool pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::insert ( value_type &&  value)
inline

Insert item by copying if there is no such key present already.

Returns
true if item is inserted.
Exceptions
pmem::transaction_alloc_erroron allocation failure.
pmem::transaction_scope_errorif called inside transaction

◆ insert_or_assign() [1/3]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
template<typename M >
bool pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::insert_or_assign ( const key_type &  key,
M &&  obj 
)
inline

Inserts item if there is no such key present already, assigns provided value otherwise.

Returns
return true if the insertion took place and false if the assignment took place.
Exceptions
pmem::transaction_alloc_erroron allocation failure.
pmem::transaction_scope_errorif called inside transaction

◆ insert_or_assign() [2/3]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
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 pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::insert_or_assign ( K &&  key,
M &&  obj 
)
inline

Inserts item if there is no such key-comparable type present already, assigns provided value otherwise.

Returns
return true if the insertion took place and false if the assignment took place.
Exceptions
pmem::transaction_alloc_erroron allocation failure.
pmem::transaction_scope_errorif called inside transaction

◆ insert_or_assign() [3/3]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
template<typename M >
bool pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::insert_or_assign ( key_type &&  key,
M &&  obj 
)
inline

Inserts item if there is no such key present already, assigns provided value otherwise.

Returns
return true if the insertion took place and false if the assignment took place.
Exceptions
pmem::transaction_alloc_erroron allocation failure.
pmem::transaction_scope_errorif called inside transaction

◆ operator=() [1/2]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
concurrent_hash_map& pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::operator= ( const concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType > &  table)
inline

Assignment Not thread safe.

Exceptions
std::transaction_errorin case of PMDK transaction failure
pmem::transaction_alloc_errorwhen allocating new memory failed.
pmem::transaction_free_errorwhen freeing old underlying array failed.
rethrowsconstructor's exception.

◆ operator=() [2/2]

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
concurrent_hash_map& pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::operator= ( std::initializer_list< value_type >  il)
inline

Assignment Not thread safe.

Exceptions
std::transaction_errorin case of PMDK transaction failure
pmem::transaction_alloc_errorwhen allocating new memory failed.
pmem::transaction_free_errorwhen freeing old underlying array failed.
rethrowsconstructor's exception.

◆ rehash()

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
void pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::rehash ( size_type  n = 0)

Rehashes and optionally resizes the whole table.

Useful to optimize performance before or after concurrent operations. Not thread safe.

Exceptions
pmem::transaction_scope_errorif called inside transaction

◆ runtime_initialize()

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
void pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::runtime_initialize ( )
inline

Initialize persistent concurrent hash map after process restart.

MUST be called every time after process restart. Not thread safe.

Exceptions
pmem::layout_errorif hashmap was created using incompatible version of libpmemobj-cpp

◆ size()

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
size_type pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::size ( ) const
inline
Returns
number of items in table.

◆ swap()

template<typename Key , typename T , typename Hash , typename KeyEqual , typename MutexType , typename ScopedLockType >
void pmem::obj::concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType >::swap ( concurrent_hash_map< Key, T, Hash, KeyEqual, MutexType, ScopedLockType > &  table)

Swap two instances.

Iterators are invalidated. Not thread safe.


The documentation for this class was generated from the following file:
pmem::transaction_free_error
Custom transaction error class.
Definition: pexceptions.hpp:145
pmem::pool_error
Custom pool error class.
Definition: pexceptions.hpp:47
pmem::obj::basic_string::c_str
const CharT * c_str() const noexcept
Definition: basic_string.hpp:3685
pmem::transaction_out_of_memory
Custom out of memory error class.
Definition: pexceptions.hpp:125
pmem::obj::basic_transaction::run
static void run(obj::pool_base &pool, std::function< void()> tx, Locks &... locks)
Execute a closure-like transaction and lock locks.
Definition: transaction.hpp:688
pmem::obj::p
Resides on pmem class.
Definition: p.hpp:35
pmem::obj::pool::root
persistent_ptr< T > root()
Retrieves pool's root object.
Definition: pool.hpp:627
pool.hpp
C++ pmemobj pool.
string.hpp
String typedefs for common character types.
pmem::obj
Main libpmemobj namespace.
Definition: allocation_flag.hpp:18
pmem::lock_error
Custom lock error class.
Definition: pexceptions.hpp:84
pmem::defrag_error
Custom defrag error class.
Definition: pexceptions.hpp:212
pmem::obj::persistent_ptr
Persistent pointer class.
Definition: persistent_ptr.hpp:152
pmem::obj::pool
PMEMobj pool class.
Definition: pool.hpp:465
p.hpp
Resides on pmem property template.
pmem::obj::pool::open
static pool< T > open(const std::string &path, const std::string &layout)
Opens an existing object store memory pool.
Definition: pool.hpp:655
pmem::obj::basic_string
pmem::obj::string - persistent container with std::basic_string compatible interface.
Definition: basic_string.hpp:46
persistent_ptr.hpp
Persistent smart pointer.
concurrent_hash_map.hpp
A persistent version of concurrent hash map implementation Ref: https://arxiv.org/abs/1509....
pmem::obj::concurrent_hash_map
Persistent memory aware implementation of Intel TBB concurrent_hash_map.
Definition: concurrent_hash_map.hpp:1628