Skip to content
This repository was archived by the owner on Mar 22, 2023. It is now read-only.

Commit e076ff7

Browse files
hashmap: move reserve() from base class to public method
1 parent cf343ab commit e076ff7

File tree

6 files changed

+194
-20
lines changed

6 files changed

+194
-20
lines changed

examples/concurrent_hash_map/concurrent_hash_map.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ main(int argc, char *argv[])
8181

8282
auto &map = *r;
8383

84+
/* We expect around 10 * THREADS_NUM items, so we reserve
85+
* hashmap's capacity to speed up insert operations. */
86+
map.reserve(10 * THREADS_NUM);
87+
8488
std::vector<std::thread> threads;
8589
threads.reserve(static_cast<size_t>(THREADS_NUM));
8690

include/libpmemobj++/container/concurrent_hash_map.hpp

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,25 +1298,6 @@ class hash_map_base {
12981298
return false;
12991299
}
13001300

1301-
/**
1302-
* Prepare enough segments for number of buckets
1303-
*/
1304-
void
1305-
reserve(size_type buckets)
1306-
{
1307-
if (buckets == 0)
1308-
return;
1309-
1310-
--buckets;
1311-
1312-
bool is_initial = this->size() == 0;
1313-
1314-
for (size_type m = mask(); buckets > m; m = mask())
1315-
enable_segment(
1316-
segment_traits_t::segment_index_of(m + 1),
1317-
is_initial);
1318-
}
1319-
13201301
/**
13211302
* Swap hash_map_base
13221303
* @throw std::transaction_error in case of PMDK transaction failed
@@ -1661,6 +1642,7 @@ class concurrent_hash_map
16611642
using hash_map_base::check_growth;
16621643
using hash_map_base::check_mask_race;
16631644
using hash_map_base::embedded_buckets;
1645+
using hash_map_base::enable_segment;
16641646
using hash_map_base::FEATURE_CONSISTENT_SIZE;
16651647
using hash_map_base::get_bucket;
16661648
using hash_map_base::get_pool_base;
@@ -1669,7 +1651,6 @@ class concurrent_hash_map
16691651
using hash_map_base::internal_swap;
16701652
using hash_map_base::layout_features;
16711653
using hash_map_base::mask;
1672-
using hash_map_base::reserve;
16731654
using tls_t = typename hash_map_base::tls_t;
16741655
using node = typename hash_map_base::node;
16751656
using node_mutex_t = typename node::mutex_t;
@@ -2874,6 +2855,27 @@ class concurrent_hash_map
28742855
return my_defrag.run();
28752856
}
28762857

2858+
/**
2859+
* Prepare enough segments for number of buckets.
2860+
*
2861+
* XXX: fixme
2862+
*/
2863+
void
2864+
reserve(size_type buckets)
2865+
{
2866+
if (buckets == 0)
2867+
return;
2868+
2869+
--buckets;
2870+
2871+
bool is_initial = this->size() == 0;
2872+
2873+
for (size_type m = mask(); buckets > m; m = mask())
2874+
enable_segment(
2875+
segment_traits_t::segment_index_of(m + 1),
2876+
is_initial);
2877+
}
2878+
28772879
/**
28782880
* Remove element with corresponding key
28792881
*

tests/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,15 @@ if(TEST_CONCURRENT_HASHMAP)
497497
build_test(concurrent_hash_map_defrag concurrent_hash_map_defrag/concurrent_hash_map_defrag.cpp)
498498
add_test_generic(NAME concurrent_hash_map_defrag TRACERS none)
499499

500+
build_test(concurrent_hash_map_reserve concurrent_hash_map_reserve/concurrent_hash_map_reserve.cpp)
501+
add_test_generic(NAME concurrent_hash_map_reserve TRACERS none) # memcheck pmemcheck
502+
503+
build_test(concurrent_hash_map_reserve_mock concurrent_hash_map_reserve/concurrent_hash_map_reserve_mock.cpp)
504+
if (NOT WIN32)
505+
target_link_libraries(concurrent_hash_map_reserve_mock "-Wl,--wrap=reserve")
506+
endif()
507+
add_test_generic(NAME concurrent_hash_map_reserve_mock TRACERS none)
508+
500509
# This test can NOT be run under helgrind as it will report wrong lock ordering. Helgrind is right about
501510
# possible deadlock situation but that could only happen in case of wrong API usage.
502511
build_test(concurrent_hash_map_deadlock concurrent_hash_map_deadlock/concurrent_hash_map_deadlock.cpp)
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
/* Copyright 2020, Intel Corporation */
3+
4+
#include "../concurrent_hash_map/concurrent_hash_map_string_test.hpp"
5+
#include "unittest.hpp"
6+
7+
#define LAYOUT "concurrent_hash_map"
8+
9+
namespace nvobj = pmem::obj;
10+
11+
/*
12+
* reserve -- basic reserve test of
13+
* pmem::obj::concurrent_hash_map<pmem::obj::string, pmem::obj::string>
14+
*/
15+
void
16+
reserve_test(nvobj::pool<root> &pop)
17+
{
18+
const size_t RESERVE_COUNT = 5000;
19+
auto map = pop.root()->cons;
20+
21+
UT_ASSERT(map != nullptr);
22+
23+
map->runtime_initialize();
24+
25+
UT_ASSERT(map->bucket_count() < RESERVE_COUNT);
26+
UT_ASSERTeq(map->size(), 0);
27+
map->reserve(RESERVE_COUNT);
28+
UT_ASSERTeq(map->size(), 0);
29+
UT_ASSERT(map->bucket_count() >= RESERVE_COUNT);
30+
31+
map->clear();
32+
}
33+
34+
static void
35+
test(int argc, char *argv[])
36+
{
37+
if (argc < 1) {
38+
UT_FATAL("usage: %s file-name", argv[0]);
39+
}
40+
41+
const char *path = argv[1];
42+
nvobj::pool<root> pop;
43+
44+
try {
45+
pop = nvobj::pool<root>::create(path, LAYOUT,
46+
200 * PMEMOBJ_MIN_POOL,
47+
S_IWUSR | S_IRUSR);
48+
pmem::obj::transaction::run(pop, [&] {
49+
pop.root()->cons =
50+
nvobj::make_persistent<persistent_map_type>();
51+
});
52+
} catch (pmem::pool_error &pe) {
53+
UT_FATAL("!pool::create: %s %s", pe.what(), path);
54+
}
55+
56+
reserve_test(pop);
57+
58+
pop.close();
59+
}
60+
61+
int
62+
main(int argc, char *argv[])
63+
{
64+
return run_test([&] { test(argc, argv); });
65+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
/* Copyright 2020, Intel Corporation */
3+
4+
#include "../concurrent_hash_map/concurrent_hash_map_string_test.hpp"
5+
#include "tests/wrap_reserve.h"
6+
#include "unittest.hpp"
7+
8+
#define LAYOUT "concurrent_hash_map"
9+
10+
namespace nvobj = pmem::obj;
11+
12+
/*
13+
* reserve_insert -- mock reserve and insert
14+
* pmem::obj::concurrent_hash_map<pmem::obj::string, pmem::obj::string>
15+
*/
16+
void
17+
reserve_insert(nvobj::pool<root> &pop)
18+
{
19+
const size_t RESERVE_COUNT = 5000;
20+
auto map = pop.root()->cons;
21+
22+
UT_ASSERT(map != nullptr);
23+
24+
map->runtime_initialize();
25+
26+
UT_ASSERT(map->bucket_count() < RESERVE_COUNT);
27+
UT_ASSERTeq(map->size(), 0);
28+
map->reserve(RESERVE_COUNT);
29+
// UT_ASSERT(0);
30+
UT_ASSERTeq(map->size(), 0);
31+
UT_ASSERT(map->bucket_count() >= RESERVE_COUNT);
32+
33+
/* insert and check allocations */
34+
35+
map->clear();
36+
}
37+
38+
static void
39+
test(int argc, char *argv[])
40+
{
41+
if (argc < 1) {
42+
UT_FATAL("usage: %s file-name", argv[0]);
43+
}
44+
45+
const char *path = argv[1];
46+
nvobj::pool<root> pop;
47+
48+
try {
49+
pop = nvobj::pool<root>::create(path, LAYOUT,
50+
200 * PMEMOBJ_MIN_POOL,
51+
S_IWUSR | S_IRUSR);
52+
pmem::obj::transaction::run(pop, [&] {
53+
pop.root()->cons =
54+
nvobj::make_persistent<persistent_map_type>();
55+
});
56+
} catch (pmem::pool_error &pe) {
57+
UT_FATAL("!pool::create: %s %s", pe.what(), path);
58+
}
59+
60+
reserve_insert(pop);
61+
62+
pop.close();
63+
}
64+
65+
int
66+
main(int argc, char *argv[])
67+
{
68+
return run_test([&] { test(argc, argv); });
69+
}

tests/wrap_reserve.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
/* Copyright 2020, Intel Corporation */
3+
4+
/*
5+
* wrap_reserve.h -- mock function for hashmap reserve()
6+
* used in the concurrent_hash_map tests which are checking...
7+
* XXX: fixme
8+
*/
9+
10+
#ifdef __cplusplus
11+
extern "C" {
12+
#endif
13+
14+
/*
15+
* __wrap_reserve -- mock function for hashmap reserve()
16+
*/
17+
void
18+
__wrap_reserve(size_t buckets)
19+
{
20+
std::cerr << "debug!n";
21+
}
22+
23+
#ifdef __cplusplus
24+
}
25+
#endif

0 commit comments

Comments
 (0)