diff --git a/server/filestore.go b/server/filestore.go index b8e948b065a..448c5c046a4 100644 --- a/server/filestore.go +++ b/server/filestore.go @@ -7537,7 +7537,14 @@ func (mb *msgBlock) cacheLookupNoCopy(seq uint64, sm *StoreMsg) (*StoreMsg, erro // Will do a lookup from cache. // Lock should be held. func (mb *msgBlock) cacheLookupEx(seq uint64, sm *StoreMsg, doCopy bool) (*StoreMsg, error) { - if seq < atomic.LoadUint64(&mb.first.seq) || seq > atomic.LoadUint64(&mb.last.seq) { + fseq, lseq := atomic.LoadUint64(&mb.first.seq), atomic.LoadUint64(&mb.last.seq) + switch { + case lseq == fseq-1: + // The block is empty, no messages have been written yet. This works because + // newMsgBlockForWrite sets fseq=fs.State.LastSeq+1 and lseq=fs.State.LastSeq. + return nil, ErrStoreMsgNotFound + case seq < fseq || seq > lseq: + // Sequence is out of range for this block. return nil, ErrStoreMsgNotFound } diff --git a/server/filestore_test.go b/server/filestore_test.go index 80b4ce5a0fb..8925f955e79 100644 --- a/server/filestore_test.go +++ b/server/filestore_test.go @@ -10586,3 +10586,30 @@ func BenchmarkFileStoreGetSeqFromTime(b *testing.B) { } }) } + +func TestFileStoreCacheLookupOnEmptyBlock(t *testing.T) { + testFileStoreAllPermutations(t, func(t *testing.T, fcfg FileStoreConfig) { + cfg := StreamConfig{Name: "zzz", Subjects: []string{"foo"}, Storage: FileStorage} + created := time.Now() + fs, err := newFileStoreWithCreated(fcfg, cfg, created, prf(&fcfg), nil) + require_NoError(t, err) + defer fs.Stop() + + fs.mu.RLock() + lmb := fs.lmb + fs.mu.RUnlock() + + // First make sure that we haven't got a strong reference to the cache. + require_NotNil(t, lmb) + lmb.finishedWithCache() + require_True(t, lmb.cache == nil) + + // Specifically we want ErrStoreMsgNotFound, not errNoCache. + _, err = lmb.cacheLookup(atomic.LoadUint64(&lmb.first.seq), nil) + require_Error(t, err, ErrStoreMsgNotFound) + + // Now make sure that we didn't strengthen the reference. This proves + // that we short-circuited properly. + require_True(t, lmb.cache == nil) + }) +}