diff options
author | Tor Egge <Tor.Egge@online.no> | 2023-08-24 12:48:25 +0200 |
---|---|---|
committer | Tor Egge <Tor.Egge@online.no> | 2023-08-24 12:48:25 +0200 |
commit | 56e0a3c779450d7301a3d5e648d20614eaa4af56 (patch) | |
tree | 5cd8ef8ade60ce7737cb37f02827e57716471ca7 /vespalib | |
parent | bbd2ea86eb91da28d7321f9551c3e8820e3f4d05 (diff) |
Add premmapped areas to file area freelist.
Diffstat (limited to 'vespalib')
3 files changed, 89 insertions, 12 deletions
diff --git a/vespalib/src/tests/util/file_area_freelist/file_area_freelist_test.cpp b/vespalib/src/tests/util/file_area_freelist/file_area_freelist_test.cpp index 9a51be3b817..e844a66f5e9 100644 --- a/vespalib/src/tests/util/file_area_freelist/file_area_freelist_test.cpp +++ b/vespalib/src/tests/util/file_area_freelist/file_area_freelist_test.cpp @@ -14,6 +14,7 @@ protected: public: FileAreaFreeListTest(); ~FileAreaFreeListTest(); + void test_merge_area_blocked(bool previous); }; FileAreaFreeListTest::FileAreaFreeListTest() @@ -23,6 +24,24 @@ FileAreaFreeListTest::FileAreaFreeListTest() FileAreaFreeListTest::~FileAreaFreeListTest() = default; +void +FileAreaFreeListTest::test_merge_area_blocked(bool previous) +{ + _freelist.add_premmapped_area(4, 1); + _freelist.add_premmapped_area(5, 1); + EXPECT_EQ(4, _freelist.alloc(1)); + EXPECT_EQ(5, _freelist.alloc(1)); + if (previous) { + _freelist.free(4, 1); + _freelist.free(5, 1); + } else { + _freelist.free(5, 1); + _freelist.free(4, 1); + } + EXPECT_EQ(bad_offset, _freelist.alloc(2)); + _freelist.remove_premmapped_area(4, 1); + _freelist.remove_premmapped_area(5, 1); +} TEST_F(FileAreaFreeListTest, empty_freelist_is_ok) { @@ -44,6 +63,11 @@ TEST_F(FileAreaFreeListTest, merge_area_with_next_area) EXPECT_EQ(bad_offset, _freelist.alloc(1)); } +TEST_F(FileAreaFreeListTest, merge_area_with_next_area_blocked_by_fence) +{ + test_merge_area_blocked(false); +} + TEST_F(FileAreaFreeListTest, merge_area_with_previous_area) { _freelist.free(3, 1); @@ -52,6 +76,11 @@ TEST_F(FileAreaFreeListTest, merge_area_with_previous_area) EXPECT_EQ(bad_offset, _freelist.alloc(1)); } +TEST_F(FileAreaFreeListTest, merge_area_with_previous_area_blocked_by_fence) +{ + test_merge_area_blocked(true); +} + TEST_F(FileAreaFreeListTest, merge_area_with_previous_and_next_area) { _freelist.free(5, 1); diff --git a/vespalib/src/vespa/vespalib/util/file_area_freelist.cpp b/vespalib/src/vespa/vespalib/util/file_area_freelist.cpp index 4894ddfa2fd..32b58b7e805 100644 --- a/vespalib/src/vespa/vespalib/util/file_area_freelist.cpp +++ b/vespalib/src/vespa/vespalib/util/file_area_freelist.cpp @@ -7,11 +7,15 @@ namespace vespalib::alloc { FileAreaFreeList::FileAreaFreeList() : _free_areas(), - _free_sizes() + _free_sizes(), + _fences() { } -FileAreaFreeList::~FileAreaFreeList() = default; +FileAreaFreeList::~FileAreaFreeList() +{ + assert(_fences.empty()); +} void FileAreaFreeList::remove_from_size_set(uint64_t offset, size_t size) @@ -73,23 +77,29 @@ FileAreaFreeList::free(uint64_t offset, size_t size) { auto itr = _free_areas.lower_bound(offset); if (itr != _free_areas.end() && itr->first <= offset + size) { - // Merge with next free area assert(itr->first == offset + size); - remove_from_size_set(itr->first, itr->second); - size += itr->second; - itr = _free_areas.erase(itr); + if (!_fences.contains(offset + size)) { + // Merge with next free area + remove_from_size_set(itr->first, itr->second); + size += itr->second; + itr = _free_areas.erase(itr); + } } bool adjusted_prev_area = false; if (itr != _free_areas.begin()) { --itr; if (itr->first + itr->second >= offset) { - // Merge with previous free area assert(itr->first + itr->second == offset); - remove_from_size_set(itr->first, itr->second); - offset = itr->first; - size += itr->second; - itr->second = size; - adjusted_prev_area = true; + if (!_fences.contains(offset)) { + // Merge with previous free area + remove_from_size_set(itr->first, itr->second); + offset = itr->first; + size += itr->second; + itr->second = size; + adjusted_prev_area = true; + } else { + ++itr; + } } else { ++itr; } @@ -101,4 +111,38 @@ FileAreaFreeList::free(uint64_t offset, size_t size) assert(ins_res.second); } +void +FileAreaFreeList::add_premmapped_area(uint64_t offset, size_t size) +{ + auto itr = _free_areas.lower_bound(offset); + if (itr != _free_areas.end()) { + assert(itr->first >= offset + size); + } + auto ins_res = _free_sizes[size].insert(offset); + assert(ins_res.second); + _free_areas.emplace_hint(itr, offset, size); + auto fences_ins_res = _fences.insert(offset); + assert(fences_ins_res.second); +} + +void +FileAreaFreeList::remove_premmapped_area(uint64_t offset, size_t size) +{ + auto itr = _free_areas.lower_bound(offset); + assert(itr != _free_areas.end()); + assert(itr->first == offset); + assert(itr->second == size); + auto sizes_itr = _free_sizes.lower_bound(size); + assert(sizes_itr != _free_sizes.end()); + assert(sizes_itr->first == size); + assert(sizes_itr->second.contains(offset)); + assert(_fences.contains(offset)); + _free_areas.erase(itr); + sizes_itr->second.erase(offset); + if (sizes_itr->second.empty()) { + _free_sizes.erase(sizes_itr); + } + _fences.erase(offset); +} + } diff --git a/vespalib/src/vespa/vespalib/util/file_area_freelist.h b/vespalib/src/vespa/vespalib/util/file_area_freelist.h index 00820c680ed..4982f294289 100644 --- a/vespalib/src/vespa/vespalib/util/file_area_freelist.h +++ b/vespalib/src/vespa/vespalib/util/file_area_freelist.h @@ -2,6 +2,7 @@ #pragma once +#include <vespa/vespalib/stllike/hash_set.h> #include <cstddef> #include <cstdint> #include <limits> @@ -16,6 +17,7 @@ namespace vespalib::alloc { class FileAreaFreeList { std::map<uint64_t, size_t> _free_areas; // map from offset to size std::map<size_t, std::set<uint64_t>> _free_sizes; // map from size to set of offsets + vespalib::hash_set<uint64_t> _fences; void remove_from_size_set(uint64_t offset, size_t size); std::pair<uint64_t, size_t> prepare_reuse_area(size_t size); public: @@ -23,6 +25,8 @@ public: ~FileAreaFreeList(); uint64_t alloc(size_t size); void free(uint64_t offset, size_t size); + void add_premmapped_area(uint64_t offset, size_t size); + void remove_premmapped_area(uint64_t offset, size_t size); static constexpr uint64_t bad_offset = std::numeric_limits<uint64_t>::max(); }; |