diff --git a/server/filestore.go b/server/filestore.go index 984fd9f1d4c..77576244c66 100644 --- a/server/filestore.go +++ b/server/filestore.go @@ -545,7 +545,7 @@ func newFileStoreWithCreated(fcfg FileStoreConfig, cfg StreamConfig, created tim // recovered first sequence number is before our configured first // sequence. Need to do this locked as by now the age check timer // has started. - if cfg.FirstSeq > 0 && firstSeq <= cfg.FirstSeq { + if cfg.FirstSeq > 0 && firstSeq < cfg.FirstSeq { if _, err := fs.purge(cfg.FirstSeq, true); err != nil { return nil, err } diff --git a/server/jetstream_test.go b/server/jetstream_test.go index bbc3acedeed..657fe015652 100644 --- a/server/jetstream_test.go +++ b/server/jetstream_test.go @@ -26263,3 +26263,53 @@ func TestJetStreamMirrorCrossAccountWithFilteredSubjectAndSubjectTransform(t *te checkMsg("M2", "public.b", 5) checkMsg("M3", "public.d", 6) } + +func TestJetStreamFileStoreFirstSeqAfterRestart(t *testing.T) { + s := RunBasicJetStreamServer(t) + defer s.Shutdown() + + nc, js := jsClientConnect(t, s) + defer nc.Close() + + // Create a stream with a first sequence. + fseq := uint64(10_000) + si, err := js.AddStream(&nats.StreamConfig{ + Name: "TEST", + Subjects: []string{"foo"}, + Storage: nats.FileStorage, + Retention: nats.LimitsPolicy, + FirstSeq: fseq, + }) + require_NoError(t, err) + require_Equal(t, si.State.FirstSeq, fseq) + require_Equal(t, si.State.LastSeq, fseq-1) + + // Publish one message to have some data in the stream. + pubAck, err := js.Publish("foo", nil) + require_NoError(t, err) + require_Equal(t, pubAck.Sequence, fseq) + + // Confirm initial stream state. + si, err = js.StreamInfo("TEST") + require_NoError(t, err) + require_Equal(t, si.State.Msgs, 1) + require_Equal(t, si.State.FirstSeq, fseq) + require_Equal(t, si.State.LastSeq, fseq) + + // Restart the server. + sd := s.JetStreamConfig().StoreDir + s.Shutdown() + nc.Close() + + s = RunJetStreamServerOnPort(-1, sd) + defer s.Shutdown() + nc, js = jsClientConnect(t, s) + defer nc.Close() + + // Stream should come back up with the same state prior to restart. + si, err = js.StreamInfo("TEST") + require_NoError(t, err) + require_Equal(t, si.State.Msgs, 1) + require_Equal(t, si.State.FirstSeq, fseq) + require_Equal(t, si.State.LastSeq, fseq) +}