Skip to content

Commit

Permalink
[IMPROVED] Last msg lookup (KV Get) when subject is a literal subject (
Browse files Browse the repository at this point in the history
…#4232)

When messages were very small and the key space was very large the
performance of last message gets in the store layer (both file and
memory) would degrade.

If the subject is literal we can optimize and avoid sequence scans that
are needed when multiple subject states need to be considered.

Signed-off-by: Derek Collison <derek@nats.io>

Resolves #4221
  • Loading branch information
derekcollison committed Jun 10, 2023
2 parents 8c513ad + f81bc80 commit 783e949
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 3 deletions.
11 changes: 10 additions & 1 deletion server/filestore.go
Expand Up @@ -4665,7 +4665,16 @@ func (fs *fileStore) loadLast(subj string, sm *StoreMsg) (lsm *StoreMsg, err err
mb.mu.Unlock()
return nil, err
}
_, _, l := mb.filteredPendingLocked(subj, wc, mb.first.seq)
var l uint64
// Optimize if subject is not a wildcard.
if !wc {
if ss := mb.fss[subj]; ss != nil {
l = ss.Last
}
}
if l == 0 {
_, _, l = mb.filteredPendingLocked(subj, wc, mb.first.seq)
}
if l > 0 {
if mb.cacheNotLoaded() {
if err := mb.loadMsgsWithLock(); err != nil {
Expand Down
8 changes: 6 additions & 2 deletions server/memstore.go
Expand Up @@ -864,6 +864,10 @@ func (ms *memStore) LoadLastMsg(subject string, smp *StoreMsg) (*StoreMsg, error

if subject == _EMPTY_ || subject == fwcs {
sm, ok = ms.msgs[ms.state.LastSeq]
} else if subjectIsLiteral(subject) {
if ss := ms.fss[subject]; ss != nil && ss.Msgs > 0 {
sm, ok = ms.msgs[ss.Last]
}
} else if ss := ms.filteredStateLocked(1, subject, true); ss.Msgs > 0 {
sm, ok = ms.msgs[ss.Last]
}
Expand Down Expand Up @@ -895,8 +899,8 @@ func (ms *memStore) LoadNextMsg(filter string, wc bool, start uint64, smp *Store

isAll := filter == _EMPTY_ || filter == fwcs

// Skip scan of mb.fss is number of messages in the block are less than
// 1/2 the number of subjects in mb.fss. Or we have a wc and lots of fss entries.
// Skip scan of ms.fss is number of messages in the block are less than
// 1/2 the number of subjects in ms.fss. Or we have a wc and lots of fss entries.
const linearScanMaxFSS = 256
doLinearScan := isAll || 2*int(ms.state.LastSeq-start) < len(ms.fss) || (wc && len(ms.fss) > linearScanMaxFSS)

Expand Down

0 comments on commit 783e949

Please sign in to comment.