From 032223f403d320c3c47c7d5932e333f306efcdc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C5=91rinc?= Date: Fri, 24 Apr 2026 22:14:05 +0200 Subject: [PATCH] dbwrapper: reuse iterator scratch stream `CDBIterator::Seek()` and `CDBIterator::GetValue()` only need a temporary owning buffer for immediate use. Keep one preallocated `DataStream` scratch member on the non-copyable iterator and guard each use with `ScopedDataStreamUsage`. `SeekImpl()` consumes the serialized key during the immediate LevelDB seek, and `GetValue()` still copies LevelDB value bytes into the owning scratch stream before in-place deobfuscation. A single stream is enough because these methods cannot overlap on the same iterator without re-entering or concurrently using it, which the guard asserts against. The preceding test covers repeated seeks and failed value deserialization followed by a successful read from the same entry. Co-authored-by: Andrew Toth --- src/dbwrapper.cpp | 5 ++++- src/dbwrapper.h | 15 ++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index 5bfdc75e654..3743d434820 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -360,7 +360,10 @@ struct CDBIterator::IteratorImpl { }; CDBIterator::CDBIterator(const CDBWrapper& _parent, std::unique_ptr _piter) : parent(_parent), - m_impl_iter(std::move(_piter)) {} + m_impl_iter(std::move(_piter)) +{ + m_scratch.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); +} CDBIterator* CDBWrapper::NewIterator() { diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 6957f32721d..51775ee6365 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -121,6 +121,7 @@ public: private: const CDBWrapper &parent; const std::unique_ptr m_impl_iter; + DataStream m_scratch{}; void SeekImpl(std::span key); std::span GetKeyImpl() const; @@ -140,10 +141,9 @@ public: void SeekToFirst(); template void Seek(const K& key) { - DataStream ssKey{}; - ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); - ssKey << key; - SeekImpl(ssKey); + ScopedDataStreamUsage scoped_scratch{m_scratch}; + m_scratch << key; + SeekImpl(m_scratch); } void Next(); @@ -160,9 +160,10 @@ public: template bool GetValue(V& value) { try { - DataStream ssValue{GetValueImpl()}; - dbwrapper_private::GetObfuscation(parent)(ssValue); - ssValue >> value; + ScopedDataStreamUsage scoped_scratch{m_scratch}; + m_scratch.write(GetValueImpl()); + dbwrapper_private::GetObfuscation(parent)(m_scratch); + m_scratch >> value; } catch (const std::exception&) { return false; }