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 <andrewstoth@gmail.com>
This commit is contained in:
Lőrinc
2026-04-24 22:14:05 +02:00
parent 7403c0f907
commit 032223f403
2 changed files with 12 additions and 8 deletions

View File

@@ -360,7 +360,10 @@ struct CDBIterator::IteratorImpl {
};
CDBIterator::CDBIterator(const CDBWrapper& _parent, std::unique_ptr<IteratorImpl> _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()
{

View File

@@ -121,6 +121,7 @@ public:
private:
const CDBWrapper &parent;
const std::unique_ptr<IteratorImpl> m_impl_iter;
DataStream m_scratch{};
void SeekImpl(std::span<const std::byte> key);
std::span<const std::byte> GetKeyImpl() const;
@@ -140,10 +141,9 @@ public:
void SeekToFirst();
template<typename K> 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<typename V> 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;
}