summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Egge <Tor.Egge@online.no>2023-06-22 18:32:17 +0200
committerTor Egge <Tor.Egge@online.no>2023-06-22 18:32:17 +0200
commit3bef09482a1fcc1a55ff09c778921ea921028e24 (patch)
tree6e4dd47797c192350b0178fb88fd8255bbe3bcb1
parentfec5b4b5837826129e9e06bd68c1488dd93766df (diff)
Allocate space for allowed buffer underflow.
-rw-r--r--vespalib/src/tests/datastore/array_store/array_store_test.cpp8
-rw-r--r--vespalib/src/tests/datastore/dynamic_array_buffer_type/dynamic_array_buffer_type_test.cpp52
-rw-r--r--vespalib/src/vespa/vespalib/datastore/buffer_type.cpp5
-rw-r--r--vespalib/src/vespa/vespalib/datastore/buffer_type.h15
-rw-r--r--vespalib/src/vespa/vespalib/datastore/buffer_type.hpp4
-rw-r--r--vespalib/src/vespa/vespalib/datastore/bufferstate.cpp42
-rw-r--r--vespalib/src/vespa/vespalib/datastore/bufferstate.h2
-rw-r--r--vespalib/src/vespa/vespalib/datastore/datastorebase.cpp3
-rw-r--r--vespalib/src/vespa/vespalib/datastore/dynamic_array_buffer_type.h7
-rw-r--r--vespalib/src/vespa/vespalib/datastore/dynamic_array_buffer_type.hpp7
10 files changed, 88 insertions, 57 deletions
diff --git a/vespalib/src/tests/datastore/array_store/array_store_test.cpp b/vespalib/src/tests/datastore/array_store/array_store_test.cpp
index a259fcaa4dc..2674acf1ce9 100644
--- a/vespalib/src/tests/datastore/array_store/array_store_test.cpp
+++ b/vespalib/src/tests/datastore/array_store/array_store_test.cpp
@@ -280,7 +280,7 @@ TYPED_TEST(NumberStoreTest, control_static_sizes) {
EXPECT_EQ(202140u, usage.allocatedBytes());
EXPECT_EQ(197680u, usage.usedBytes());
} else {
- EXPECT_EQ(202388u, usage.allocatedBytes());
+ EXPECT_EQ(202328u, usage.allocatedBytes());
EXPECT_EQ(197568u, usage.usedBytes());
}
}
@@ -564,10 +564,10 @@ TYPED_TEST(NumberStoreTest, address_space_usage_is_ratio_between_used_arrays_and
* allocated elements = 256 / sizeof(int) = 64.
* limit = 64 / 3 = 21.
*
- * For dynamic buffer 3, we have 16 * 5 * sizeof(int) => 320 -> 512
- * limit = 512 / (5 * 4) = 25
+ * For dynamic buffer 3, we have 16 * 5 * sizeof(int) => 320 -> 512 - 64
+ * limit = (512 -64) / (5 * 4) = 22
*/
- size_t type_id_3_entries = this->simple_buffers() ? 21 : 25;
+ size_t type_id_3_entries = this->simple_buffers() ? 21 : 22;
size_t expLimit = fourgig - 4 * TestFixture::EntryRefType::offsetSize() + 3 * 16 + type_id_3_entries;
EXPECT_EQ(static_cast<double>(2)/ expLimit, this->store.addressSpaceUsage().usage());
EXPECT_EQ(expLimit, this->store.addressSpaceUsage().limit());
diff --git a/vespalib/src/tests/datastore/dynamic_array_buffer_type/dynamic_array_buffer_type_test.cpp b/vespalib/src/tests/datastore/dynamic_array_buffer_type/dynamic_array_buffer_type_test.cpp
index a703d9b18eb..9c0432a7780 100644
--- a/vespalib/src/tests/datastore/dynamic_array_buffer_type/dynamic_array_buffer_type_test.cpp
+++ b/vespalib/src/tests/datastore/dynamic_array_buffer_type/dynamic_array_buffer_type_test.cpp
@@ -120,20 +120,23 @@ protected:
BufferType _buffer_type;
size_t _entry_size;
+ size_t _buffer_underflow_size;
size_t _buf_size;
- std::unique_ptr<char[]> _buf;
+ std::unique_ptr<char[]> _buf_alloc;
+ char* _buf;
};
DynamicArrayBufferTypeTest::DynamicArrayBufferTypeTest()
: testing::Test(),
_buffer_type(3, ArrayStoreConfig::AllocSpec(0, 10, 0, 0.2), {}),
_entry_size(_buffer_type.entry_size()),
+ _buffer_underflow_size(BufferType::buffer_underflow_size),
_buf_size(2 * _entry_size),
- _buf(std::make_unique<char[]>(_buf_size))
+ _buf_alloc(std::make_unique<char[]>(_buf_size + _buffer_underflow_size)),
+ _buf(_buf_alloc.get() + _buffer_underflow_size)
{
// Call initialize_reserved_entries to force construction of empty element
- _buffer_type.initialize_reserved_entries(_buf.get(), 1);
- memset(_buf.get(), 55, _buf_size);
+ _buffer_type.initialize_reserved_entries(_buf, 1);
// Reset counts after empty element has been constructed
counts = Counts();
}
@@ -178,7 +181,7 @@ DynamicArrayBufferTypeTest::get_max_vector(const void* buffer, uint32_t offset)
void
DynamicArrayBufferTypeTest::write_entry1()
{
- auto e1 = BufferType::get_entry(_buf.get(), 1, _entry_size);
+ auto e1 = BufferType::get_entry(_buf, 1, _entry_size);
BufferType::set_dynamic_array_size(e1, 2);
new (static_cast<void *>(e1)) WrapInt32(42);
new (static_cast<void *>(e1 + 1)) WrapInt32(47);
@@ -204,46 +207,47 @@ TEST_F(DynamicArrayBufferTypeTest, entry_size_is_calculated)
TEST_F(DynamicArrayBufferTypeTest, initialize_reserved_entries)
{
- _buffer_type.initialize_reserved_entries(_buf.get(), 2);
- EXPECT_EQ((std::vector<int>{}), get_vector(_buf.get(), 0));
- EXPECT_EQ((std::vector<int>{}), get_vector(_buf.get(), 1));
- EXPECT_EQ((std::vector<int>{0, 0, 0}), get_max_vector(_buf.get(), 0));
- EXPECT_EQ((std::vector<int>{0, 0, 0}), get_max_vector(_buf.get(), 1));
+ _buffer_type.initialize_reserved_entries(_buf, 2);
+ EXPECT_EQ((std::vector<int>{}), get_vector(_buf, 0));
+ EXPECT_EQ((std::vector<int>{}), get_vector(_buf, 1));
+ EXPECT_EQ((std::vector<int>{0, 0, 0}), get_max_vector(_buf, 0));
+ EXPECT_EQ((std::vector<int>{0, 0, 0}), get_max_vector(_buf, 1));
EXPECT_EQ(Counts(0, 0, 6, 0, 0), counts);
}
TEST_F(DynamicArrayBufferTypeTest, fallback_copy)
{
- _buffer_type.initialize_reserved_entries(_buf.get(), 1);
+ _buffer_type.initialize_reserved_entries(_buf, 1);
write_entry1();
EXPECT_EQ(Counts(0, 3, 3, 0, 0), counts);
- auto buf2 = std::make_unique<char[]>(_buf_size);
- _buffer_type.fallback_copy(buf2.get(), _buf.get(), 2);
- EXPECT_EQ((std::vector<int>{}), get_vector(buf2.get(), 0));
- EXPECT_EQ((std::vector<int>{42, 47}), get_vector(buf2.get(), 1));
- EXPECT_EQ((std::vector<int>{0, 0, 0}), get_max_vector(buf2.get(), 0));
- EXPECT_EQ((std::vector<int>{42, 47, 49}), get_max_vector(buf2.get(), 1));
+ auto buf2_alloc = std::make_unique<char[]>(_buf_size + _buffer_underflow_size);
+ char* buf2 = buf2_alloc.get() + _buffer_underflow_size;
+ _buffer_type.fallback_copy(buf2, _buf, 2);
+ EXPECT_EQ((std::vector<int>{}), get_vector(buf2, 0));
+ EXPECT_EQ((std::vector<int>{42, 47}), get_vector(buf2, 1));
+ EXPECT_EQ((std::vector<int>{0, 0, 0}), get_max_vector(buf2, 0));
+ EXPECT_EQ((std::vector<int>{42, 47, 49}), get_max_vector(buf2, 1));
EXPECT_EQ(Counts(0, 3, 9, 0, 0), counts);
}
TEST_F(DynamicArrayBufferTypeTest, destroy_entries)
{
- _buffer_type.initialize_reserved_entries(_buf.get(), 2);
+ _buffer_type.initialize_reserved_entries(_buf, 2);
write_entry1();
- _buffer_type.destroy_entries(_buf.get(), 2);
+ _buffer_type.destroy_entries(_buf, 2);
EXPECT_EQ(Counts(0, 3, 6, 6, 0), counts);
}
TEST_F(DynamicArrayBufferTypeTest, clean_hold)
{
- _buffer_type.initialize_reserved_entries(_buf.get(), 1);
+ _buffer_type.initialize_reserved_entries(_buf, 1);
write_entry1();
MyCleanContext clean_context;
- _buffer_type.clean_hold(_buf.get(), 1, 1, clean_context);
- EXPECT_EQ((std::vector<int>{0, 0}), get_vector(_buf.get(), 1));
- EXPECT_EQ((std::vector<int>{0, 0, 49}), get_max_vector(_buf.get(), 1));
+ _buffer_type.clean_hold(_buf, 1, 1, clean_context);
+ EXPECT_EQ((std::vector<int>{0, 0}), get_vector(_buf, 1));
+ EXPECT_EQ((std::vector<int>{0, 0, 49}), get_max_vector(_buf, 1));
EXPECT_EQ(Counts(0, 3, 3, 0, 2), counts);
- _buffer_type.clean_hold(_buf.get(), 0, 2, clean_context);
+ _buffer_type.clean_hold(_buf, 0, 2, clean_context);
EXPECT_EQ(Counts(0, 3, 3, 0, 4), counts);
}
diff --git a/vespalib/src/vespa/vespalib/datastore/buffer_type.cpp b/vespalib/src/vespa/vespalib/datastore/buffer_type.cpp
index 90f9334da77..1b087a01c58 100644
--- a/vespalib/src/vespa/vespalib/datastore/buffer_type.cpp
+++ b/vespalib/src/vespa/vespalib/datastore/buffer_type.cpp
@@ -27,6 +27,7 @@ BufferTypeBase::CleanContext::extraBytesCleaned(size_t value)
}
BufferTypeBase::BufferTypeBase(uint32_t entry_size_in,
+ uint32_t buffer_underflow_size_in,
uint32_t arraySize,
uint32_t min_entries,
uint32_t max_entries,
@@ -34,6 +35,7 @@ BufferTypeBase::BufferTypeBase(uint32_t entry_size_in,
float allocGrowFactor) noexcept
: _entry_size(entry_size_in),
_arraySize(arraySize),
+ _buffer_underflow_size(buffer_underflow_size_in),
_min_entries(std::min(min_entries, max_entries)),
_max_entries(max_entries),
_num_entries_for_new_buffer(std::min(num_entries_for_new_buffer, max_entries)),
@@ -46,10 +48,11 @@ BufferTypeBase::BufferTypeBase(uint32_t entry_size_in,
}
BufferTypeBase::BufferTypeBase(uint32_t entry_size_in,
+ uint32_t buffer_underflow_size_in,
uint32_t arraySize,
uint32_t min_entries,
uint32_t max_entries) noexcept
- : BufferTypeBase(entry_size_in, arraySize, min_entries, max_entries, 0u, DEFAULT_ALLOC_GROW_FACTOR)
+ : BufferTypeBase(entry_size_in, buffer_underflow_size_in, arraySize, min_entries, max_entries, 0u, DEFAULT_ALLOC_GROW_FACTOR)
{
}
diff --git a/vespalib/src/vespa/vespalib/datastore/buffer_type.h b/vespalib/src/vespa/vespalib/datastore/buffer_type.h
index c79651c3ba2..7b23a238ba2 100644
--- a/vespalib/src/vespa/vespalib/datastore/buffer_type.h
+++ b/vespalib/src/vespa/vespalib/datastore/buffer_type.h
@@ -39,8 +39,8 @@ public:
BufferTypeBase & operator=(const BufferTypeBase &rhs) = delete;
BufferTypeBase(BufferTypeBase &&rhs) noexcept = default;
BufferTypeBase & operator=(BufferTypeBase &&rhs) noexcept = default;
- BufferTypeBase(uint32_t entry_size_in, uint32_t arraySize, uint32_t min_entries, uint32_t max_entries) noexcept;
- BufferTypeBase(uint32_t entry_size_in, uint32_t arraySize, uint32_t min_entries, uint32_t max_entries,
+ BufferTypeBase(uint32_t entry_size_in, uint32_t buffer_underflow_size_in, uint32_t arraySize, uint32_t min_entries, uint32_t max_entries) noexcept;
+ BufferTypeBase(uint32_t entry_size_in, uint32_t buffer_underflow_size_in, uint32_t arraySize, uint32_t min_entries, uint32_t max_entries,
uint32_t num_entries_for_new_buffer, float allocGrowFactor) noexcept;
virtual ~BufferTypeBase();
virtual void destroy_entries(void *buffer, EntryCount num_entries) = 0;
@@ -57,6 +57,7 @@ public:
*/
virtual void initialize_reserved_entries(void *buffer, EntryCount reserved_entries) = 0;
size_t entry_size() const noexcept { return _entry_size; }
+ uint32_t buffer_underflow_size() const noexcept { return _buffer_underflow_size; }
virtual void clean_hold(void *buffer, size_t offset, EntryCount num_entries, CleanContext cleanCtx) = 0;
size_t getArraySize() const noexcept { return _arraySize; }
virtual void on_active(uint32_t bufferId, std::atomic<EntryCount>* used_entries, std::atomic<EntryCount>* dead_entries, void* buffer);
@@ -115,6 +116,16 @@ protected:
uint32_t _entry_size; // Number of bytes in an allocation unit
uint32_t _arraySize; // Number of elements in an allocation unit
+
+ /*
+ * Buffer underflow size is the size of an area before the start
+ * of the logical buffer that is safe to access (part of the same
+ * memory alloation as the buffer itself). This allows for data
+ * belonging to an entry to be placed at the end of what is normally
+ * the last part of the previos entry (e.g. dynamic array size
+ * for the dynamic array buffer type).
+ */
+ uint32_t _buffer_underflow_size;
uint32_t _min_entries; // Minimum number of entries to allocate in a buffer
uint32_t _max_entries; // Maximum number of entries to allocate in a buffer
// Number of entries needed before allocating a new buffer instead of just resizing the first one
diff --git a/vespalib/src/vespa/vespalib/datastore/buffer_type.hpp b/vespalib/src/vespa/vespalib/datastore/buffer_type.hpp
index 375c832d9fb..00d642be9bc 100644
--- a/vespalib/src/vespa/vespalib/datastore/buffer_type.hpp
+++ b/vespalib/src/vespa/vespalib/datastore/buffer_type.hpp
@@ -8,13 +8,13 @@ namespace vespalib::datastore {
template <typename ElemT, typename EmptyT>
BufferType<ElemT, EmptyT>::BufferType(uint32_t arraySize, uint32_t min_entries, uint32_t max_entries) noexcept
- : BufferTypeBase(arraySize * sizeof(ElemT), arraySize, min_entries, max_entries)
+ : BufferTypeBase(arraySize * sizeof(ElemT), 0u, arraySize, min_entries, max_entries)
{ }
template <typename ElemT, typename EmptyT>
BufferType<ElemT, EmptyT>::BufferType(uint32_t arraySize, uint32_t min_entries, uint32_t max_entries,
uint32_t num_entries_for_new_buffer, float allocGrowFactor) noexcept
- : BufferTypeBase(arraySize * sizeof(ElemT), arraySize, min_entries, max_entries, num_entries_for_new_buffer, allocGrowFactor)
+ : BufferTypeBase(arraySize * sizeof(ElemT), 0u, arraySize, min_entries, max_entries, num_entries_for_new_buffer, allocGrowFactor)
{ }
template <typename ElemT, typename EmptyT>
diff --git a/vespalib/src/vespa/vespalib/datastore/bufferstate.cpp b/vespalib/src/vespa/vespalib/datastore/bufferstate.cpp
index f312596d6f7..e7832a1c4e2 100644
--- a/vespalib/src/vespa/vespalib/datastore/bufferstate.cpp
+++ b/vespalib/src/vespa/vespalib/datastore/bufferstate.cpp
@@ -64,13 +64,14 @@ calc_allocation(uint32_t bufferId,
{
size_t alloc_entries = typeHandler.calc_entries_to_alloc(bufferId, free_entries_needed, resizing);
size_t entry_size = typeHandler.entry_size();
- size_t allocBytes = roundUpToMatchAllocator(alloc_entries * entry_size);
- size_t maxAllocBytes = typeHandler.get_max_entries() * entry_size;
+ auto buffer_underflow_size = typeHandler.buffer_underflow_size();
+ size_t allocBytes = roundUpToMatchAllocator(alloc_entries * entry_size + buffer_underflow_size);
+ size_t maxAllocBytes = typeHandler.get_max_entries() * entry_size + buffer_underflow_size;
if (allocBytes > maxAllocBytes) {
// Ensure that allocated bytes does not exceed the maximum handled by this type.
allocBytes = maxAllocBytes;
}
- size_t adjusted_alloc_entries = allocBytes / entry_size;
+ size_t adjusted_alloc_entries = (allocBytes - buffer_underflow_size) / entry_size;
return AllocResult(adjusted_alloc_entries, allocBytes);
}
@@ -102,7 +103,8 @@ BufferState::on_active(uint32_t bufferId, uint32_t typeId,
_buffer = (allocator != nullptr) ? Alloc::alloc_with_allocator(allocator) : Alloc::alloc(0, MemoryAllocator::HUGEPAGE_SIZE);
_buffer.create(alloc.bytes).swap(_buffer);
assert(_buffer.get() != nullptr || alloc.entries == 0u);
- buffer.store(_buffer.get(), std::memory_order_release);
+ auto buffer_underflow_size = typeHandler->buffer_underflow_size();
+ buffer.store(get_buffer(buffer_underflow_size), std::memory_order_release);
_stats.set_alloc_entries(alloc.entries);
_typeHandler.store(typeHandler, std::memory_order_release);
assert(typeId <= std::numeric_limits<uint16_t>::max());
@@ -117,28 +119,30 @@ void
BufferState::onHold(uint32_t buffer_id)
{
assert(getState() == State::ACTIVE);
- assert(getTypeHandler() != nullptr);
+ auto type_handler = getTypeHandler();
+ assert(type_handler != nullptr);
_state.store(State::HOLD, std::memory_order_release);
_compacting = false;
assert(_stats.dead_entries() <= size());
assert(_stats.hold_entries() <= (size() - _stats.dead_entries()));
_stats.set_dead_entries(0);
_stats.set_hold_entries(size());
- getTypeHandler()->on_hold(buffer_id, &_stats.used_entries_ref(), &_stats.dead_entries_ref());
+ type_handler->on_hold(buffer_id, &_stats.used_entries_ref(), &_stats.dead_entries_ref());
_free_list.disable();
}
void
BufferState::onFree(std::atomic<void*>& buffer)
{
- assert(buffer.load(std::memory_order_relaxed) == _buffer.get());
assert(getState() == State::HOLD);
- assert(_typeHandler != nullptr);
+ auto type_handler = getTypeHandler();
+ assert(type_handler != nullptr);
+ assert(buffer.load(std::memory_order_relaxed) == get_buffer(type_handler->buffer_underflow_size()));
assert(_stats.dead_entries() <= size());
assert(_stats.hold_entries() == (size() - _stats.dead_entries()));
- getTypeHandler()->destroy_entries(buffer, size());
+ type_handler->destroy_entries(buffer, size());
Alloc::alloc().swap(_buffer);
- getTypeHandler()->on_free(size());
+ type_handler->on_free(size());
buffer.store(nullptr, std::memory_order_release);
_stats.clear();
_state.store(State::FREE, std::memory_order_release);
@@ -200,9 +204,11 @@ BufferState::free_entries(EntryRef ref, size_t num_entries, size_t ref_offset)
}
_stats.inc_dead_entries(num_entries);
_stats.dec_hold_entries(num_entries);
- getTypeHandler()->clean_hold(_buffer.get(), ref_offset, num_entries,
- BufferTypeBase::CleanContext(_stats.extra_used_bytes_ref(),
- _stats.extra_hold_bytes_ref()));
+ auto type_handler = getTypeHandler();
+ auto buffer_underflow_size = type_handler->buffer_underflow_size();
+ type_handler->clean_hold(get_buffer(buffer_underflow_size), ref_offset, num_entries,
+ BufferTypeBase::CleanContext(_stats.extra_used_bytes_ref(),
+ _stats.extra_hold_bytes_ref()));
}
void
@@ -212,17 +218,19 @@ BufferState::fallback_resize(uint32_t bufferId,
Alloc &holdBuffer)
{
assert(getState() == State::ACTIVE);
- assert(_typeHandler != nullptr);
+ auto type_handler = getTypeHandler();
+ assert(type_handler != nullptr);
assert(holdBuffer.get() == nullptr);
- AllocResult alloc = calc_allocation(bufferId, *_typeHandler, free_entries_needed, true);
+ auto buffer_underflow_size = type_handler->buffer_underflow_size();
+ AllocResult alloc = calc_allocation(bufferId, *type_handler, free_entries_needed, true);
assert(alloc.entries >= size() + free_entries_needed);
assert(alloc.entries > capacity());
Alloc newBuffer = _buffer.create(alloc.bytes);
- getTypeHandler()->fallback_copy(newBuffer.get(), buffer.load(std::memory_order_relaxed), size());
+ type_handler->fallback_copy(get_buffer(newBuffer, buffer_underflow_size), buffer.load(std::memory_order_relaxed), size());
holdBuffer.swap(_buffer);
std::atomic_thread_fence(std::memory_order_release);
_buffer = std::move(newBuffer);
- buffer.store(_buffer.get(), std::memory_order_release);
+ buffer.store(get_buffer(buffer_underflow_size), std::memory_order_release);
_stats.set_alloc_entries(alloc.entries);
}
diff --git a/vespalib/src/vespa/vespalib/datastore/bufferstate.h b/vespalib/src/vespa/vespalib/datastore/bufferstate.h
index 1b9db616888..01439586f5b 100644
--- a/vespalib/src/vespa/vespalib/datastore/bufferstate.h
+++ b/vespalib/src/vespa/vespalib/datastore/bufferstate.h
@@ -48,6 +48,8 @@ private:
bool _disable_entry_hold_list : 1;
bool _compacting : 1;
+ static void *get_buffer(Alloc& buffer, uint32_t buffer_underflow_size) noexcept { return static_cast<char *>(buffer.get()) + buffer_underflow_size; }
+ void *get_buffer(uint32_t buffer_underflow_size) noexcept { return get_buffer(_buffer, buffer_underflow_size); }
public:
/**
* TODO: Check if per-buffer free lists are useful, or if
diff --git a/vespalib/src/vespa/vespalib/datastore/datastorebase.cpp b/vespalib/src/vespa/vespalib/datastore/datastorebase.cpp
index 5926132427c..5c88900ae92 100644
--- a/vespalib/src/vespa/vespalib/datastore/datastorebase.cpp
+++ b/vespalib/src/vespa/vespalib/datastore/datastorebase.cpp
@@ -59,7 +59,8 @@ DataStoreBase::FallbackHold::FallbackHold(size_t bytesSize, BufferState::Alloc &
DataStoreBase::FallbackHold::~FallbackHold()
{
- _typeHandler->destroy_entries(_buffer.get(), _used_entries);
+ auto buffer_underflow_size = _typeHandler->buffer_underflow_size();
+ _typeHandler->destroy_entries(static_cast<char *>(_buffer.get()) + buffer_underflow_size, _used_entries);
}
class DataStoreBase::BufferHold : public GenerationHeldBase {
diff --git a/vespalib/src/vespa/vespalib/datastore/dynamic_array_buffer_type.h b/vespalib/src/vespa/vespalib/datastore/dynamic_array_buffer_type.h
index 2f0f0ae0e26..7ee86b44876 100644
--- a/vespalib/src/vespa/vespalib/datastore/dynamic_array_buffer_type.h
+++ b/vespalib/src/vespa/vespalib/datastore/dynamic_array_buffer_type.h
@@ -26,12 +26,13 @@ class DynamicArrayBufferType : public BufferTypeBase
{
using AllocSpec = ArrayStoreConfig::AllocSpec;
std::shared_ptr<alloc::MemoryAllocator> _memory_allocator;
+
public:
using ElemType = ElemT;
static constexpr size_t entry_min_align = std::max(alignof(uint32_t), alignof(ElemT));
using EntryMinAligner = Aligner<entry_min_align>;
- static constexpr size_t entry_bias = EntryMinAligner::align(sizeof(uint32_t));
+ static constexpr uint32_t buffer_underflow_size = 64u;
protected:
static const ElemType& empty_entry() noexcept;
ElemType* get_entry(void *buffer, size_t offset) noexcept { return get_entry(buffer, offset, entry_size()); }
@@ -55,8 +56,8 @@ public:
const vespalib::alloc::MemoryAllocator* get_memory_allocator() const override;
static size_t calc_entry_size(size_t array_size) noexcept;
static size_t calc_array_size(size_t entry_size) noexcept;
- static ElemType* get_entry(void* buffer, size_t offset, uint32_t entry_size) noexcept { return reinterpret_cast<ElemType*>(static_cast<char*>(buffer) + offset * entry_size + entry_bias); }
- static const ElemType* get_entry(const void* buffer, size_t offset, uint32_t entry_size) noexcept { return reinterpret_cast<const ElemType*>(static_cast<const char*>(buffer) + offset * entry_size + entry_bias); }
+ static ElemType* get_entry(void* buffer, size_t offset, uint32_t entry_size) noexcept { return reinterpret_cast<ElemType*>(static_cast<char*>(buffer) + offset * entry_size); }
+ static const ElemType* get_entry(const void* buffer, size_t offset, uint32_t entry_size) noexcept { return reinterpret_cast<const ElemType*>(static_cast<const char*>(buffer) + offset * entry_size); }
static uint32_t get_dynamic_array_size(const ElemType* buffer) noexcept { return *(reinterpret_cast<const uint32_t*>(buffer) - 1); }
static void set_dynamic_array_size(ElemType* buffer, uint32_t array_size) noexcept { *(reinterpret_cast<uint32_t*>(buffer) - 1) = array_size; }
bool is_dynamic_array_buffer_type() const noexcept override;
diff --git a/vespalib/src/vespa/vespalib/datastore/dynamic_array_buffer_type.hpp b/vespalib/src/vespa/vespalib/datastore/dynamic_array_buffer_type.hpp
index 3ed26db4e7f..57d5b81b0c7 100644
--- a/vespalib/src/vespa/vespalib/datastore/dynamic_array_buffer_type.hpp
+++ b/vespalib/src/vespa/vespalib/datastore/dynamic_array_buffer_type.hpp
@@ -9,7 +9,7 @@ namespace vespalib::datastore {
template <typename ElemT>
DynamicArrayBufferType<ElemT>::DynamicArrayBufferType(uint32_t array_size, const AllocSpec& spec, std::shared_ptr<alloc::MemoryAllocator> memory_allocator) noexcept
- : BufferTypeBase(calc_entry_size(array_size), array_size, spec.min_entries_in_buffer, spec.max_entries_in_buffer, spec.num_entries_for_new_buffer, spec.allocGrowFactor),
+ : BufferTypeBase(calc_entry_size(array_size), buffer_underflow_size, array_size, spec.min_entries_in_buffer, spec.max_entries_in_buffer, spec.num_entries_for_new_buffer, spec.allocGrowFactor),
_memory_allocator(std::move(memory_allocator))
{
}
@@ -24,14 +24,15 @@ template <typename ElemT>
size_t
DynamicArrayBufferType<ElemT>::calc_entry_size(size_t array_size) noexcept
{
- return EntryMinAligner::align(sizeof(ElemType) * array_size + entry_bias);
+ auto entry_size = EntryMinAligner::align(sizeof(ElemType) * array_size + sizeof(uint32_t));
+ return entry_size;
}
template <typename ElemT>
size_t
DynamicArrayBufferType<ElemT>::calc_array_size(size_t entry_size) noexcept
{
- return (entry_size - entry_bias) / sizeof(ElemType);
+ return (entry_size - sizeof(uint32_t)) / sizeof(ElemType);
}
template <typename ElemT>