From a744e1d5c9adfe74db16fa28f0fb645dc88a07d8 Mon Sep 17 00:00:00 2001 From: Derek Collison Date: Tue, 18 Apr 2023 22:23:11 -0700 Subject: [PATCH 1/3] Added ability to set initial minimum value for seqset when known. We know the minimum value when creating a new filestore msgBlk. Signed-off-by: Derek Collison --- server/avl/seqset.go | 25 +++++++++++++++++++++---- server/avl/seqset_test.go | 17 +++++++++++++++++ server/filestore.go | 2 ++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/server/avl/seqset.go b/server/avl/seqset.go index 140726f8..294173b5 100644 --- a/server/avl/seqset.go +++ b/server/avl/seqset.go @@ -62,17 +62,31 @@ func (ss *SequenceSet) Exists(seq uint64) bool { return false } +// SetInitialMin should be used to set the initial minimum sequence when known. +// This will more effectively utilize space versus self selecting. +// The set should be empty. +func (ss *SequenceSet) SetInitialMin(min uint64) error { + if !ss.IsEmpty() { + return ErrSetNotEmpty + } + ss.root = &node{base: min, h: 1} + return nil +} + // Delete will remove the sequence from the set. -// Wil optionally remove nodes and rebalance. -func (ss *SequenceSet) Delete(seq uint64) { +// Will optionally remove nodes and rebalance. +// Returns where the sequence was set. +func (ss *SequenceSet) Delete(seq uint64) bool { if ss == nil || ss.root == nil { - return + return false } ss.root = ss.root.delete(seq, &ss.changed, &ss.nodes) if ss.changed { ss.changed = false ss.size-- + return true } + return false } // Size returns the number of items in the set. @@ -228,7 +242,10 @@ func (ss SequenceSet) Encode(buf []byte) ([]byte, error) { } // ErrBadEncoding is returned when we can not decode properly. -var ErrBadEncoding = errors.New("ss: bad encoding") +var ( + ErrBadEncoding = errors.New("ss: bad encoding") + ErrSetNotEmpty = errors.New("ss: set not empty") +) func Decode(buf []byte) (*SequenceSet, error) { if len(buf) < minLen || buf[0] != magic || buf[1] != version { diff --git a/server/avl/seqset_test.go b/server/avl/seqset_test.go index 8a90971d..d4fe2cd7 100644 --- a/server/avl/seqset_test.go +++ b/server/avl/seqset_test.go @@ -218,6 +218,23 @@ func TestSeqSetUnion(t *testing.T) { } } +func TestSeqSetFirst(t *testing.T) { + var ss SequenceSet + + seqs := []uint64{22, 222, 2222, 222_222} + for _, seq := range seqs { + // Normal case where we pick first/base. + ss.Insert(seq) + require_True(t, ss.root.base == (seq/numEntries)*numEntries) + ss.Empty() + // Where we set the minimum start value. + ss.SetInitialMin(seq) + ss.Insert(seq) + require_True(t, ss.root.base == seq) + ss.Empty() + } +} + func require_NoError(t *testing.T, err error) { t.Helper() if err != nil { diff --git a/server/filestore.go b/server/filestore.go index 33a230dc..adf1f716 100644 --- a/server/filestore.go +++ b/server/filestore.go @@ -2221,6 +2221,8 @@ func (fs *fileStore) newMsgBlockForWrite() (*msgBlock, error) { // Remember our last sequence number. mb.first.seq = fs.state.LastSeq + 1 mb.last.seq = fs.state.LastSeq + // Mark initial base for delete set. + mb.dmap.SetInitialMin(mb.first.seq) mb.mu.Unlock() // If we know we will need this so go ahead and spin up. From aa66c87d53090129bc59c757eefd0f8c2dc15a55 Mon Sep 17 00:00:00 2001 From: Derek Collison Date: Tue, 18 Apr 2023 22:34:13 -0700 Subject: [PATCH 2/3] Make sure to set node count to 1 Signed-off-by: Derek Collison --- server/avl/seqset.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/avl/seqset.go b/server/avl/seqset.go index 294173b5..53f68ad2 100644 --- a/server/avl/seqset.go +++ b/server/avl/seqset.go @@ -69,7 +69,7 @@ func (ss *SequenceSet) SetInitialMin(min uint64) error { if !ss.IsEmpty() { return ErrSetNotEmpty } - ss.root = &node{base: min, h: 1} + ss.root, ss.nodes = &node{base: min, h: 1}, 1 return nil } From a45c7106b8ebc568d6da0914086b8e799ace7190 Mon Sep 17 00:00:00 2001 From: Derek Collison Date: Tue, 18 Apr 2023 22:50:57 -0700 Subject: [PATCH 3/3] Only set minimum when removing first item Signed-off-by: Derek Collison --- server/avl/seqset.go | 3 +++ server/filestore.go | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/server/avl/seqset.go b/server/avl/seqset.go index 53f68ad2..3e0e6c32 100644 --- a/server/avl/seqset.go +++ b/server/avl/seqset.go @@ -84,6 +84,9 @@ func (ss *SequenceSet) Delete(seq uint64) bool { if ss.changed { ss.changed = false ss.size-- + if ss.size == 0 { + ss.Empty() + } return true } return false diff --git a/server/filestore.go b/server/filestore.go index adf1f716..4a98b6d5 100644 --- a/server/filestore.go +++ b/server/filestore.go @@ -2221,8 +2221,6 @@ func (fs *fileStore) newMsgBlockForWrite() (*msgBlock, error) { // Remember our last sequence number. mb.first.seq = fs.state.LastSeq + 1 mb.last.seq = fs.state.LastSeq - // Mark initial base for delete set. - mb.dmap.SetInitialMin(mb.first.seq) mb.mu.Unlock() // If we know we will need this so go ahead and spin up. @@ -2790,6 +2788,10 @@ func (fs *fileStore) removeMsg(seq uint64, secure, viaLimits, needFSLock bool) ( } } } else if !isEmpty { + if mb.dmap.IsEmpty() { + // Mark initial base for delete set. + mb.dmap.SetInitialMin(mb.first.seq) + } // Out of order delete. mb.dmap.Insert(seq) // Check if <25% utilization and minimum size met.