summaryrefslogtreecommitdiffstats
path: root/vespalib
diff options
context:
space:
mode:
authorTor Egge <Tor.Egge@online.no>2023-08-24 12:48:25 +0200
committerTor Egge <Tor.Egge@online.no>2023-08-24 12:48:25 +0200
commit56e0a3c779450d7301a3d5e648d20614eaa4af56 (patch)
tree5cd8ef8ade60ce7737cb37f02827e57716471ca7 /vespalib
parentbbd2ea86eb91da28d7321f9551c3e8820e3f4d05 (diff)
Add premmapped areas to file area freelist.
Diffstat (limited to 'vespalib')
-rw-r--r--vespalib/src/tests/util/file_area_freelist/file_area_freelist_test.cpp29
-rw-r--r--vespalib/src/vespa/vespalib/util/file_area_freelist.cpp68
-rw-r--r--vespalib/src/vespa/vespalib/util/file_area_freelist.h4
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();
};