diff options
author | Tor Brede Vekterli <vekterli@yahooinc.com> | 2022-03-28 14:30:33 +0000 |
---|---|---|
committer | Tor Brede Vekterli <vekterli@yahooinc.com> | 2022-03-28 14:30:33 +0000 |
commit | d11c7181ef8b80fb20a6b4285da4fe95f577b4ae (patch) | |
tree | 549726516e60849d382560ba0db1cd4f4faf6ec7 /vespalib | |
parent | 19f950ba81d98904b67fd45c48865754af4b590f (diff) |
Let empty entry BufferType sentinel be static instead of global
Avoids issue where a global BufferType with a transitive Alloc instance
binds to a null reference allocator since the global allocator instance
has not yet been initialized as part of global constructor invocation.
Manually hoist empty sentinel ref outside of loops since it might not
be obvious to the compiler that the same object is reused over and over.
Diffstat (limited to 'vespalib')
5 files changed, 18 insertions, 7 deletions
diff --git a/vespalib/src/vespa/vespalib/btree/btreenodestore.h b/vespalib/src/vespa/vespalib/btree/btreenodestore.h index 444bf641899..d4a5ae42ef8 100644 --- a/vespalib/src/vespa/vespalib/btree/btreenodestore.h +++ b/vespalib/src/vespa/vespalib/btree/btreenodestore.h @@ -25,7 +25,7 @@ template <typename EntryType> class BTreeNodeBufferType : public datastore::BufferType<EntryType, FrozenBtreeNode<EntryType>> { using ParentType = datastore::BufferType<EntryType, FrozenBtreeNode<EntryType>>; - using ParentType::_emptyEntry; + using ParentType::empty_entry; using ParentType::_arraySize; using ElemCount = typename ParentType::ElemCount; using CleanContext = typename ParentType::CleanContext; diff --git a/vespalib/src/vespa/vespalib/datastore/buffer_type.h b/vespalib/src/vespa/vespalib/datastore/buffer_type.h index 7d041646ca5..3394af18b04 100644 --- a/vespalib/src/vespa/vespalib/datastore/buffer_type.h +++ b/vespalib/src/vespa/vespalib/datastore/buffer_type.h @@ -133,7 +133,7 @@ template <typename EntryType, typename EmptyType = EntryType> class BufferType : public BufferTypeBase { protected: - static EntryType _emptyEntry; + static const EntryType& empty_entry() noexcept; public: BufferType() noexcept : BufferType(1,1,1) {} diff --git a/vespalib/src/vespa/vespalib/datastore/buffer_type.hpp b/vespalib/src/vespa/vespalib/datastore/buffer_type.hpp index ae2659ef65b..72c8f574a70 100644 --- a/vespalib/src/vespa/vespalib/datastore/buffer_type.hpp +++ b/vespalib/src/vespa/vespalib/datastore/buffer_type.hpp @@ -51,8 +51,9 @@ void BufferType<EntryType, EmptyType>::initializeReservedElements(void *buffer, ElemCount reservedElems) { EntryType *e = static_cast<EntryType *>(buffer); + const auto& empty = empty_entry(); for (size_t j = reservedElems; j != 0; --j) { - new (static_cast<void *>(e)) EntryType(_emptyEntry); + new (static_cast<void *>(e)) EntryType(empty); ++e; } } @@ -62,13 +63,22 @@ void BufferType<EntryType, EmptyType>::cleanHold(void *buffer, size_t offset, ElemCount numElems, CleanContext) { EntryType *e = static_cast<EntryType *>(buffer) + offset; + const auto& empty = empty_entry(); for (size_t j = numElems; j != 0; --j) { - *e = _emptyEntry; + *e = empty; ++e; } } template <typename EntryType, typename EmptyType> -EntryType BufferType<EntryType, EmptyType>::_emptyEntry = EmptyType(); +const EntryType& +BufferType<EntryType, EmptyType>::empty_entry() noexcept +{ + // It's possible for EntryType to wrap e.g. an Alloc instance, which has a transitive + // dependency on globally constructed allocator object(s). To avoid issues with global + // construction order, initialize the sentinel on the first access. + static EntryType empty = EmptyType(); + return empty; +} } diff --git a/vespalib/src/vespa/vespalib/datastore/large_array_buffer_type.h b/vespalib/src/vespa/vespalib/datastore/large_array_buffer_type.h index 50d15d4a27c..ccaedaa9b64 100644 --- a/vespalib/src/vespa/vespalib/datastore/large_array_buffer_type.h +++ b/vespalib/src/vespa/vespalib/datastore/large_array_buffer_type.h @@ -20,7 +20,7 @@ class LargeArrayBufferType : public BufferType<Array<EntryT>> using AllocSpec = ArrayStoreConfig::AllocSpec; using ArrayType = Array<EntryT>; using ParentType = BufferType<ArrayType>; - using ParentType::_emptyEntry; + using ParentType::empty_entry; using CleanContext = typename ParentType::CleanContext; std::shared_ptr<alloc::MemoryAllocator> _memory_allocator; public: diff --git a/vespalib/src/vespa/vespalib/datastore/large_array_buffer_type.hpp b/vespalib/src/vespa/vespalib/datastore/large_array_buffer_type.hpp index aeeef8166c6..3042bbff73f 100644 --- a/vespalib/src/vespa/vespalib/datastore/large_array_buffer_type.hpp +++ b/vespalib/src/vespa/vespalib/datastore/large_array_buffer_type.hpp @@ -22,9 +22,10 @@ void LargeArrayBufferType<EntryT>::cleanHold(void* buffer, size_t offset, ElemCount numElems, CleanContext cleanCtx) { ArrayType* elem = static_cast<ArrayType*>(buffer) + offset; + const auto& empty = empty_entry(); for (size_t i = 0; i < numElems; ++i) { cleanCtx.extraBytesCleaned(sizeof(EntryT) * elem->size()); - *elem = _emptyEntry; + *elem = empty; ++elem; } } |