summaryrefslogtreecommitdiffstats
path: root/vespalib
diff options
context:
space:
mode:
authorTor Egge <Tor.Egge@online.no>2021-04-13 14:25:03 +0200
committerTor Egge <Tor.Egge@online.no>2021-04-13 14:25:03 +0200
commit16892237c5b241bfada8870435d92aa67ce4d897 (patch)
treed0633fd725ad39d916600545d5c69ec8137fc021 /vespalib
parentf9cc338cc28a79045da882db7ddcc8e02cb301df (diff)
Compact enum store dictionary when needed.
Diffstat (limited to 'vespalib')
-rw-r--r--vespalib/src/tests/datastore/unique_store_dictionary/unique_store_dictionary_test.cpp71
-rw-r--r--vespalib/src/vespa/vespalib/datastore/i_unique_store_dictionary.h2
-rw-r--r--vespalib/src/vespa/vespalib/datastore/sharded_hash_map.cpp26
-rw-r--r--vespalib/src/vespa/vespalib/datastore/sharded_hash_map.h2
-rw-r--r--vespalib/src/vespa/vespalib/datastore/unique_store_dictionary.h2
-rw-r--r--vespalib/src/vespa/vespalib/datastore/unique_store_dictionary.hpp37
6 files changed, 129 insertions, 11 deletions
diff --git a/vespalib/src/tests/datastore/unique_store_dictionary/unique_store_dictionary_test.cpp b/vespalib/src/tests/datastore/unique_store_dictionary/unique_store_dictionary_test.cpp
index ce1ebe395ce..7b46196780f 100644
--- a/vespalib/src/tests/datastore/unique_store_dictionary/unique_store_dictionary_test.cpp
+++ b/vespalib/src/tests/datastore/unique_store_dictionary/unique_store_dictionary_test.cpp
@@ -34,25 +34,37 @@ public:
return resolve(lhs).ref() == resolve(rhs).ref();
}
size_t hash(const EntryRef rhs) const override {
- return rhs.ref();
+ return rhs.valid() ? rhs.ref() : _to_find.ref();
}
};
template <typename UniqueStoreDictionaryType>
-struct DictionaryReadTest : public ::testing::Test {
+struct UniqueStoreDictionaryTest : public ::testing::Test {
UniqueStoreDictionaryType dict;
std::unique_ptr<IUniqueStoreDictionaryReadSnapshot> snapshot;
+ vespalib::GenerationHandler gen_handler;
- DictionaryReadTest()
+ UniqueStoreDictionaryTest()
: dict(std::make_unique<Comparator>(0)),
- snapshot()
+ snapshot(),
+ gen_handler()
{
}
- DictionaryReadTest& add(uint32_t value) {
+ UniqueStoreDictionaryTest& add(uint32_t value) {
auto result = dict.add(Comparator(value), [=]() noexcept { return EntryRef(value); });
assert(result.inserted());
return *this;
}
+ UniqueStoreDictionaryTest& remove(uint32_t value) {
+ dict.remove(Comparator(value), EntryRef(value));
+ return *this;
+ }
+ void inc_generation() {
+ dict.freeze();
+ dict.transfer_hold_lists(gen_handler.getCurrentGeneration());
+ gen_handler.incGeneration();
+ dict.trim_hold_lists(gen_handler.getFirstUsedGeneration());
+ }
void take_snapshot() {
dict.freeze();
snapshot = dict.get_read_snapshot();
@@ -61,8 +73,8 @@ struct DictionaryReadTest : public ::testing::Test {
}
};
-using DictionaryReadTestTypes = ::testing::Types<DefaultUniqueStoreDictionary, UniqueStoreDictionary<DefaultDictionary, IUniqueStoreDictionary, ShardedHashMap>, UniqueStoreDictionary<NoBTreeDictionary, IUniqueStoreDictionary, ShardedHashMap>>;
-VESPA_GTEST_TYPED_TEST_SUITE(DictionaryReadTest, DictionaryReadTestTypes);
+using UniqueStoreDictionaryTestTypes = ::testing::Types<DefaultUniqueStoreDictionary, UniqueStoreDictionary<DefaultDictionary, IUniqueStoreDictionary, ShardedHashMap>, UniqueStoreDictionary<NoBTreeDictionary, IUniqueStoreDictionary, ShardedHashMap>>;
+VESPA_GTEST_TYPED_TEST_SUITE(UniqueStoreDictionaryTest, UniqueStoreDictionaryTestTypes);
// Disable warnings emitted by gtest generated files when using typed tests
#pragma GCC diagnostic push
@@ -70,7 +82,7 @@ VESPA_GTEST_TYPED_TEST_SUITE(DictionaryReadTest, DictionaryReadTestTypes);
#pragma GCC diagnostic ignored "-Wsuggest-override"
#endif
-TYPED_TEST(DictionaryReadTest, can_count_occurrences_of_a_key)
+TYPED_TEST(UniqueStoreDictionaryTest, can_count_occurrences_of_a_key)
{
this->add(3).add(5).take_snapshot();
EXPECT_EQ(0, this->snapshot->count(Comparator(2)));
@@ -79,7 +91,7 @@ TYPED_TEST(DictionaryReadTest, can_count_occurrences_of_a_key)
EXPECT_EQ(1, this->snapshot->count(Comparator(5)));
}
-TYPED_TEST(DictionaryReadTest, can_count_occurrences_of_keys_in_a_range)
+TYPED_TEST(UniqueStoreDictionaryTest, can_count_occurrences_of_keys_in_a_range)
{
if (!this->dict.get_has_btree_dictionary()) {
return;
@@ -95,7 +107,7 @@ TYPED_TEST(DictionaryReadTest, can_count_occurrences_of_keys_in_a_range)
EXPECT_EQ(0, this->snapshot->count_in_range(Comparator(5), Comparator(3)));
}
-TYPED_TEST(DictionaryReadTest, can_iterate_all_keys)
+TYPED_TEST(UniqueStoreDictionaryTest, can_iterate_all_keys)
{
using EntryRefVector = std::vector<EntryRef>;
this->add(3).add(5).add(7).take_snapshot();
@@ -104,7 +116,7 @@ TYPED_TEST(DictionaryReadTest, can_iterate_all_keys)
EXPECT_EQ(EntryRefVector({EntryRef(3), EntryRef(5), EntryRef(7)}), refs);
}
-TYPED_TEST(DictionaryReadTest, memory_usage_is_reported)
+TYPED_TEST(UniqueStoreDictionaryTest, memory_usage_is_reported)
{
auto initial_usage = this->dict.get_memory_usage();
this->add(10);
@@ -114,6 +126,43 @@ TYPED_TEST(DictionaryReadTest, memory_usage_is_reported)
EXPECT_EQ(0, usage.allocatedBytesOnHold());
}
+TYPED_TEST(UniqueStoreDictionaryTest, compaction_works)
+{
+ for (uint32_t i = 1; i < 100; ++i) {
+ this->add(i);
+ }
+ for (uint32_t i = 10; i < 100; ++i) {
+ this->remove(i);
+ }
+ this->inc_generation();
+ auto btree_memory_usage_before = this->dict.get_btree_memory_usage();
+ auto hash_memory_usage_before = this->dict.get_hash_memory_usage();
+ for (uint32_t i = 0; i < 15; ++i) {
+ this->dict.compact_worst(true, true);
+ }
+ this->inc_generation();
+ auto btree_memory_usage_after = this->dict.get_btree_memory_usage();
+ auto hash_memory_usage_after = this->dict.get_hash_memory_usage();
+ if (this->dict.get_has_btree_dictionary()) {
+ EXPECT_LT(btree_memory_usage_after.deadBytes(), btree_memory_usage_before.deadBytes());
+ } else {
+ EXPECT_EQ(btree_memory_usage_after.deadBytes(), btree_memory_usage_before.deadBytes());
+ }
+ if (this->dict.get_has_hash_dictionary()) {
+ EXPECT_LT(hash_memory_usage_after.deadBytes(), hash_memory_usage_before.deadBytes());
+ } else {
+ EXPECT_EQ(hash_memory_usage_after.deadBytes(), hash_memory_usage_before.deadBytes());
+ }
+ std::vector<EntryRef> exp_refs;
+ for (uint32_t i = 1; i < 10; ++i) {
+ exp_refs.emplace_back(EntryRef(i));
+ }
+ this->take_snapshot();
+ std::vector<EntryRef> refs;
+ this->snapshot->foreach_key([&](EntryRef ref){ refs.emplace_back(ref); });
+ EXPECT_EQ(exp_refs, refs);
+}
+
#pragma GCC diagnostic pop
GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/vespalib/src/vespa/vespalib/datastore/i_unique_store_dictionary.h b/vespalib/src/vespa/vespalib/datastore/i_unique_store_dictionary.h
index 4f53a872822..13c389c9a31 100644
--- a/vespalib/src/vespa/vespalib/datastore/i_unique_store_dictionary.h
+++ b/vespalib/src/vespa/vespalib/datastore/i_unique_store_dictionary.h
@@ -39,6 +39,8 @@ public:
virtual bool get_has_hash_dictionary() const = 0;
virtual vespalib::MemoryUsage get_btree_memory_usage() const = 0;
virtual vespalib::MemoryUsage get_hash_memory_usage() const = 0;
+ virtual bool has_held_buffers() const = 0;
+ virtual void compact_worst(bool compact_btree_dictionary, bool compact_hash_dictionary) = 0;
};
}
diff --git a/vespalib/src/vespa/vespalib/datastore/sharded_hash_map.cpp b/vespalib/src/vespa/vespalib/datastore/sharded_hash_map.cpp
index 36d68873176..a04163f120c 100644
--- a/vespalib/src/vespa/vespalib/datastore/sharded_hash_map.cpp
+++ b/vespalib/src/vespa/vespalib/datastore/sharded_hash_map.cpp
@@ -194,4 +194,30 @@ ShardedHashMap::normalize_values(std::function<EntryRef(EntryRef)> normalize)
return changed;
}
+bool
+ShardedHashMap::has_held_buffers() const
+{
+ return _gen_holder.getHeldBytes() != 0;
+}
+
+void
+ShardedHashMap::compact_worst()
+{
+ size_t worst_index = 0u;
+ size_t worst_dead_bytes = 0u;
+ for (size_t i = 0; i < num_shards; ++i) {
+ auto map = _maps[i].load(std::memory_order_relaxed);
+ if (map != nullptr) {
+ auto memory_usage = map->get_memory_usage();
+ if (memory_usage.deadBytes() > worst_dead_bytes) {
+ worst_index = i;
+ worst_dead_bytes = memory_usage.deadBytes();
+ }
+ }
+ }
+ if (worst_dead_bytes > 0u) {
+ alloc_shard(worst_index);
+ }
+}
+
}
diff --git a/vespalib/src/vespa/vespalib/datastore/sharded_hash_map.h b/vespalib/src/vespa/vespalib/datastore/sharded_hash_map.h
index aa787421634..54d6481f34c 100644
--- a/vespalib/src/vespa/vespalib/datastore/sharded_hash_map.h
+++ b/vespalib/src/vespa/vespalib/datastore/sharded_hash_map.h
@@ -58,6 +58,8 @@ public:
void foreach_key(std::function<void(EntryRef)> callback) const;
void move_keys(std::function<EntryRef(EntryRef)> callback);
bool normalize_values(std::function<EntryRef(EntryRef)> normalize);
+ bool has_held_buffers() const;
+ void compact_worst();
};
}
diff --git a/vespalib/src/vespa/vespalib/datastore/unique_store_dictionary.h b/vespalib/src/vespa/vespalib/datastore/unique_store_dictionary.h
index faaa2294ff3..1775fda7ae3 100644
--- a/vespalib/src/vespa/vespalib/datastore/unique_store_dictionary.h
+++ b/vespalib/src/vespa/vespalib/datastore/unique_store_dictionary.h
@@ -90,6 +90,8 @@ public:
bool get_has_hash_dictionary() const override;
vespalib::MemoryUsage get_btree_memory_usage() const override;
vespalib::MemoryUsage get_hash_memory_usage() const override;
+ bool has_held_buffers() const override;
+ void compact_worst(bool compact_btree_dictionary, bool compact_hash_dictionary) override;
};
}
diff --git a/vespalib/src/vespa/vespalib/datastore/unique_store_dictionary.hpp b/vespalib/src/vespa/vespalib/datastore/unique_store_dictionary.hpp
index 4a9cf3d96b2..99037b7aaf8 100644
--- a/vespalib/src/vespa/vespalib/datastore/unique_store_dictionary.hpp
+++ b/vespalib/src/vespa/vespalib/datastore/unique_store_dictionary.hpp
@@ -318,4 +318,41 @@ UniqueStoreDictionary<BTreeDictionaryT, ParentT, HashDictionaryT>::get_hash_memo
return {};
}
+template <typename BTreeDictionaryT, typename ParentT, typename HashDictionaryT>
+bool
+UniqueStoreDictionary<BTreeDictionaryT, ParentT, HashDictionaryT>::has_held_buffers() const
+{
+ if constexpr (has_btree_dictionary) {
+ if (this->_btree_dict.getAllocator().getNodeStore().has_held_buffers()) {
+ return true;
+ }
+ }
+ if constexpr (has_hash_dictionary) {
+ if (this->_hash_dict.has_held_buffers()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+template <typename BTreeDictionaryT, typename ParentT, typename HashDictionaryT>
+void
+UniqueStoreDictionary<BTreeDictionaryT, ParentT, HashDictionaryT>::compact_worst(bool compact_btree_dictionary, bool compact_hash_dictionary)
+{
+ if constexpr (has_btree_dictionary) {
+ if (compact_btree_dictionary) {
+ this->_btree_dict.compact_worst();
+ }
+ } else {
+ (void) compact_btree_dictionary;
+ }
+ if constexpr (has_hash_dictionary) {
+ if (compact_hash_dictionary) {
+ this->_hash_dict.compact_worst();
+ }
+ } else {
+ (void) compact_hash_dictionary;
+ }
+}
+
}