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

Commit d49db42

Browse files
committed
radix_tree: extend concurrent_iterate test with erasing
1 parent 995a0a8 commit d49db42

1 file changed

Lines changed: 150 additions & 0 deletions

File tree

tests/radix_tree/radix_concurrent_iterate.cpp

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,84 @@ test_write_iterate(nvobj::pool<root> &pop,
7272
UT_ASSERTeq(num_allocs(pop), 0);
7373
}
7474

75+
/* Insert INITIAL_ELEMENTS elements to the radix. After that, concurrently
76+
* erase elements with even keys and iterate through the entire container to
77+
* count elements with odd keys. */
78+
void
79+
test_erase_iterate(nvobj::pool<root> &pop,
80+
nvobj::persistent_ptr<container_int_int> &ptr)
81+
{
82+
const size_t value_repeats = 1000;
83+
size_t threads = 4;
84+
if (On_drd)
85+
threads = 2;
86+
87+
/* check how many allocs will remain after removing elements with even
88+
* keys */
89+
init_container(pop, ptr, INITIAL_ELEMENTS, value_repeats);
90+
for (size_t i = 0; i < INITIAL_ELEMENTS; i += 2) {
91+
ptr->erase(key<container_int_int>(i));
92+
}
93+
auto expected_allocs = num_allocs(pop);
94+
nvobj::transaction::run(
95+
pop, [&] { nvobj::delete_persistent<container_int_int>(ptr); });
96+
97+
init_container(pop, ptr, INITIAL_ELEMENTS, value_repeats);
98+
ptr->runtime_initialize_mt();
99+
100+
/* force 3 gc cycles to ensure that all garbage vectors will be
101+
* allocated */
102+
for (size_t i = 0; i < 3; ++i) {
103+
ptr->erase(key<container_int_int>(i));
104+
ptr->garbage_collect();
105+
ptr->emplace(key<container_int_int>(i),
106+
value<container_int_int>(i));
107+
}
108+
109+
auto writer_f = [&] {
110+
for (size_t i = 0; i < INITIAL_ELEMENTS; i += 2) {
111+
ptr->erase(key<container_int_int>(i));
112+
ptr->garbage_collect();
113+
}
114+
};
115+
116+
auto readers_f = std::vector<std::function<void()>>{
117+
[&] {
118+
auto w = ptr->register_worker();
119+
120+
size_t cnt = 0;
121+
w.critical([&] {
122+
for (auto it = ptr->begin(); it != ptr->end();
123+
++it) {
124+
if (it->key() % 2) {
125+
++cnt;
126+
}
127+
}
128+
});
129+
UT_ASSERTeq(cnt, INITIAL_ELEMENTS / 2);
130+
},
131+
};
132+
133+
parallel_modify_read(writer_f, readers_f, threads);
134+
135+
UT_ASSERTeq(ptr->size(), INITIAL_ELEMENTS / 2);
136+
137+
ptr->garbage_collect_force();
138+
139+
/* num allocs == expected_allocs + 3 garbage vectors */
140+
UT_ASSERTeq(num_allocs(pop), expected_allocs + 3);
141+
142+
ptr->runtime_finalize_mt();
143+
144+
nvobj::transaction::run(
145+
pop, [&] { nvobj::delete_persistent<container_int_int>(ptr); });
146+
147+
UT_ASSERTeq(num_allocs(pop), 0);
148+
}
149+
150+
/* Insert INITIAL_ELEMENTS/2 elements to the radix. After that concurrently
151+
* write new elements from the writer thread and do lower_bound/upper_bound
152+
* from the other threads. */
75153
void
76154
test_write_upper_lower_bounds(nvobj::pool<root> &pop,
77155
nvobj::persistent_ptr<container_int_int> &ptr)
@@ -379,6 +457,77 @@ test_write_erase_upper_lower_bounds_split(
379457
UT_ASSERTeq(num_allocs(pop), 0);
380458
}
381459

460+
/* Insert INITIAL_ELEMENTS elements to the radix. After that concurrently
461+
* erase elements in one thread and do lower_bound/upper_bound
462+
* in the other threads. */
463+
void
464+
test_erase_upper_lower_bounds(nvobj::pool<root> &pop,
465+
nvobj::persistent_ptr<container_int_int> &ptr)
466+
{
467+
const size_t value_repeats = 10;
468+
size_t threads = 4;
469+
if (On_drd)
470+
threads = 2;
471+
const size_t batch_size = INITIAL_ELEMENTS / threads;
472+
473+
init_container(pop, ptr, INITIAL_ELEMENTS, value_repeats);
474+
ptr->runtime_initialize_mt();
475+
476+
auto writer = [&]() {
477+
for (size_t i = 0; i < INITIAL_ELEMENTS; i += 2) {
478+
ptr->erase(key<container_int_int>(i));
479+
}
480+
};
481+
482+
std::atomic<size_t> reader_id;
483+
reader_id.store(0);
484+
auto readers = std::vector<std::function<void()>>{
485+
[&]() {
486+
auto id = reader_id++;
487+
for (size_t i = id * batch_size;
488+
i < (id + 1) * batch_size; ++i) {
489+
std::vector<unsigned int> keys;
490+
auto it = ptr->lower_bound(i);
491+
while (it != ptr->end()) {
492+
keys.push_back(it->key());
493+
++it;
494+
}
495+
496+
for (auto &k : keys) {
497+
UT_ASSERT(k >=
498+
key<container_int_int>(i));
499+
}
500+
}
501+
},
502+
[&]() {
503+
auto id = reader_id++;
504+
for (size_t i = id * batch_size;
505+
i < (id + 1) * batch_size; ++i) {
506+
std::vector<unsigned int> keys;
507+
auto it = ptr->upper_bound(i);
508+
while (it != ptr->end()) {
509+
keys.push_back(it->key());
510+
++it;
511+
}
512+
513+
for (auto &k : keys) {
514+
UT_ASSERT(k >
515+
key<container_int_int>(i));
516+
}
517+
}
518+
},
519+
};
520+
521+
parallel_modify_read(writer, readers, threads);
522+
523+
ptr->runtime_finalize_mt();
524+
525+
nvobj::transaction::run(
526+
pop, [&] { nvobj::delete_persistent<container_int_int>(ptr); });
527+
528+
UT_ASSERTeq(num_allocs(pop), 0);
529+
}
530+
382531
static void
383532
test(int argc, char *argv[])
384533
{
@@ -407,6 +556,7 @@ test(int argc, char *argv[])
407556
generator = std::mt19937_64(seed);
408557

409558
test_write_iterate(pop, pop.root()->radix_int_int);
559+
test_erase_iterate(pop, pop.root()->radix_int_int);
410560
test_write_upper_lower_bounds(pop, pop.root()->radix_int_int);
411561
test_erase_upper_lower_bounds_neighbours(pop, pop.root()->radix_str);
412562
test_write_erase_upper_lower_bounds_split(pop, pop.root()->radix_str);

0 commit comments

Comments
 (0)