From 1db5902436ee972d625f72fec2c7efc6d3ad01bb Mon Sep 17 00:00:00 2001 From: mh0lt Date: Thu, 30 Jul 2026 16:44:19 +0000 Subject: [PATCH] db/kv/membatchwithdb: surface DomainReader read errors instead of swallowing them MemoryMutation and OverlayTemporalReadView GetAsOf/HistorySeek used `err == nil && ok` to gate the DomainReader result, so a reader error fell through to the committed tx and was hidden. Propagate the error; keep the ok-based committed fallback (a tombstone is ok=true, so it is not resurrected). --- db/kv/membatchwithdb/memory_mutation.go | 32 ++++++++++++++++++------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/db/kv/membatchwithdb/memory_mutation.go b/db/kv/membatchwithdb/memory_mutation.go index e80f2f29453..1d24f6ce070 100644 --- a/db/kv/membatchwithdb/memory_mutation.go +++ b/db/kv/membatchwithdb/memory_mutation.go @@ -952,8 +952,12 @@ func (m *MemoryMutation) GetLatest(name kv.Domain, k []byte) (v []byte, step kv. func (m *MemoryMutation) GetAsOf(name kv.Domain, k []byte, ts uint64) (v []byte, ok bool, err error) { if m.DomainReader != nil { - if val, ok, err := m.DomainReader.GetAsOf(name, k, ts); err == nil && ok { - return val, ok, nil + val, ok, err := m.DomainReader.GetAsOf(name, k, ts) + if err != nil { + return nil, false, err + } + if ok { + return val, true, nil } } if m.db == nil { @@ -985,8 +989,12 @@ func (m *MemoryMutation) RangeAsOf(name kv.Domain, fromKey, toKey []byte, ts uin func (m *MemoryMutation) HistorySeek(name kv.Domain, k []byte, ts uint64) (v []byte, ok bool, err error) { if m.DomainReader != nil { - if val, ok, err := m.DomainReader.HistorySeek(name, k, ts); err == nil && ok { - return val, ok, nil + val, ok, err := m.DomainReader.HistorySeek(name, k, ts) + if err != nil { + return nil, false, err + } + if ok { + return val, true, nil } } if m.db == nil { @@ -1151,8 +1159,12 @@ func (v *OverlayTemporalReadView) GetAsOf(name kv.Domain, k []byte, ts uint64) ( // Check DomainReader independently — this method shadows MemoryMutation.GetAsOf // and falls through to v.temporalTx (not m.db), so the embedded check never fires. if v.MemoryMutation != nil && v.MemoryMutation.DomainReader != nil { - if val, ok, err := v.MemoryMutation.DomainReader.GetAsOf(name, k, ts); err == nil && ok { - return val, ok, nil + val, ok, err := v.MemoryMutation.DomainReader.GetAsOf(name, k, ts) + if err != nil { + return nil, false, err + } + if ok { + return val, true, nil } } return v.temporalTx.GetAsOf(name, k, ts) @@ -1170,8 +1182,12 @@ func (v *OverlayTemporalReadView) HistorySeek(name kv.Domain, k []byte, ts uint6 // Check DomainReader independently — this method shadows MemoryMutation.HistorySeek // and falls through to v.temporalTx (not m.db), so the embedded check never fires. if v.MemoryMutation != nil && v.MemoryMutation.DomainReader != nil { - if val, ok, err := v.MemoryMutation.DomainReader.HistorySeek(name, k, ts); err == nil && ok { - return val, ok, nil + val, ok, err := v.MemoryMutation.DomainReader.HistorySeek(name, k, ts) + if err != nil { + return nil, false, err + } + if ok { + return val, true, nil } } return v.temporalTx.HistorySeek(name, k, ts)