mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-05-31 16:24:48 +02:00
dbwrapper: guard CDBBatch scratch streams
`CDBBatch` already owns key and value serialization buffers, but manually reserved and cleared them on each call. Reserve those scratch buffers once in the constructor, then guard `Write()` and `Erase()` use with `ScopedDataStreamUsage`, requiring empty streams on entry and clearing them on every exit path. `WriteImpl()` and `EraseImpl()` pass the bytes immediately to LevelDB's write batch, which copies them and does not retain pointers. `Clear()` now asserts the guards left both scratch streams clean. Co-authored-by: Andrew Toth <andrewstoth@gmail.com>
This commit is contained in:
@@ -163,6 +163,8 @@ CDBBatch::CDBBatch(const CDBWrapper& _parent)
|
||||
: parent{_parent},
|
||||
m_impl_batch{std::make_unique<CDBBatch::WriteBatchImpl>()}
|
||||
{
|
||||
m_key_scratch.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
|
||||
m_value_scratch.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE);
|
||||
Clear();
|
||||
};
|
||||
|
||||
@@ -171,13 +173,15 @@ CDBBatch::~CDBBatch() = default;
|
||||
void CDBBatch::Clear()
|
||||
{
|
||||
m_impl_batch->batch.Clear();
|
||||
assert(m_key_scratch.empty());
|
||||
assert(m_value_scratch.empty());
|
||||
}
|
||||
|
||||
void CDBBatch::WriteImpl(std::span<const std::byte> key, DataStream& ssValue)
|
||||
void CDBBatch::WriteImpl(std::span<const std::byte> key, DataStream& value)
|
||||
{
|
||||
leveldb::Slice slKey(CharCast(key.data()), key.size());
|
||||
dbwrapper_private::GetObfuscation(parent)(ssValue);
|
||||
leveldb::Slice slValue(CharCast(ssValue.data()), ssValue.size());
|
||||
dbwrapper_private::GetObfuscation(parent)(value);
|
||||
leveldb::Slice slValue(CharCast(value.data()), value.size());
|
||||
m_impl_batch->batch.Put(slKey, slValue);
|
||||
}
|
||||
|
||||
|
||||
@@ -79,10 +79,10 @@ private:
|
||||
struct WriteBatchImpl;
|
||||
const std::unique_ptr<WriteBatchImpl> m_impl_batch;
|
||||
|
||||
DataStream ssKey{};
|
||||
DataStream ssValue{};
|
||||
DataStream m_key_scratch{};
|
||||
DataStream m_value_scratch{};
|
||||
|
||||
void WriteImpl(std::span<const std::byte> key, DataStream& ssValue);
|
||||
void WriteImpl(std::span<const std::byte> key, DataStream& value);
|
||||
void EraseImpl(std::span<const std::byte> key);
|
||||
|
||||
public:
|
||||
@@ -96,22 +96,18 @@ public:
|
||||
template <typename K, typename V>
|
||||
void Write(const K& key, const V& value)
|
||||
{
|
||||
ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
|
||||
ssValue.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE);
|
||||
ssKey << key;
|
||||
ssValue << value;
|
||||
WriteImpl(ssKey, ssValue);
|
||||
ssKey.clear();
|
||||
ssValue.clear();
|
||||
ScopedDataStreamUsage scoped_key{m_key_scratch}, scoped_value{m_value_scratch};
|
||||
m_key_scratch << key;
|
||||
m_value_scratch << value;
|
||||
WriteImpl(m_key_scratch, m_value_scratch);
|
||||
}
|
||||
|
||||
template <typename K>
|
||||
void Erase(const K& key)
|
||||
{
|
||||
ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
|
||||
ssKey << key;
|
||||
EraseImpl(ssKey);
|
||||
ssKey.clear();
|
||||
ScopedDataStreamUsage scoped_key{m_key_scratch};
|
||||
m_key_scratch << key;
|
||||
EraseImpl(m_key_scratch);
|
||||
}
|
||||
|
||||
size_t ApproximateSize() const;
|
||||
|
||||
Reference in New Issue
Block a user