Skip to content

Commit bc8495d

Browse files
[stats only] Fix broken scorch stats (#2380)
- When introducing a merge, we always incremented `File` based stats even when the merge could have originated from in-memory segment merge. Fix this by tracking the origin of the merge request and updating the respective stat. - Made merge related stats symmetric across file and memory-based merge, added: - `TotMemMergeIntroductions` - `TotMemMergeIntroductionsDone` - `TotMemMergeZapIntroductionTime` - `MaxMemMergeZapIntroductionTime` - Removed unused `TotIntroduceRevertBeg` and `TotIntroduceRevertEnd` stats as we do not support any revert operation anyway. - Fix a data race when computing the `MaxMemMergeZapTime` stat.
1 parent 8fb0f1b commit bc8495d

3 files changed

Lines changed: 91 additions & 55 deletions

File tree

index/scorch/introducer.go

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -361,29 +361,29 @@ func (s *Scorch) introduceMerge(nextMerge *segmentMerge) {
361361

362362
var running, docsToPersistCount, memSegments, fileSegments uint64
363363
var droppedSegmentFiles []string
364-
newSegmentDeleted := make([]*roaring.Bitmap, len(nextMerge.new))
365-
for i := range newSegmentDeleted {
364+
newSegmentsDeleted := make([]*roaring.Bitmap, len(nextMerge.newSegments))
365+
for i := range newSegmentsDeleted {
366366
// create a bitmaps to track the obsoletes per newly merged segments
367-
newSegmentDeleted[i] = roaring.NewBitmap()
367+
newSegmentsDeleted[i] = roaring.NewBitmap()
368368
}
369369

370370
// iterate through current segments
371371
for i := range root.segment {
372372
segmentID := root.segment[i].id
373-
if segSnapAtMerge, ok := nextMerge.mergedSegHistory[segmentID]; ok {
373+
if history, ok := nextMerge.mergedSegHistory[segmentID]; ok {
374374
// this segment is going away, see if anything else was deleted since we started the merge
375-
if segSnapAtMerge != nil && root.segment[i].deleted != nil {
375+
if history != nil && root.segment[i].deleted != nil {
376376
// assume all these deletes are new
377377
deletedSince := root.segment[i].deleted
378378
// if we already knew about some of them, remove
379-
if segSnapAtMerge.oldSegment.deleted != nil {
380-
deletedSince = roaring.AndNot(root.segment[i].deleted, segSnapAtMerge.oldSegment.deleted)
379+
if history.oldSegment.deleted != nil {
380+
deletedSince = roaring.AndNot(root.segment[i].deleted, history.oldSegment.deleted)
381381
}
382382
deletedSinceItr := deletedSince.Iterator()
383383
for deletedSinceItr.HasNext() {
384384
oldDocNum := deletedSinceItr.Next()
385-
newDocNum := segSnapAtMerge.oldNewDocIDs[oldDocNum]
386-
newSegmentDeleted[segSnapAtMerge.batchID].Add(uint32(newDocNum))
385+
newDocNum := history.oldNewDocIDs[oldDocNum]
386+
newSegmentsDeleted[history.batchID].Add(uint32(newDocNum))
387387
}
388388
}
389389

@@ -430,28 +430,36 @@ func (s *Scorch) introduceMerge(nextMerge *segmentMerge) {
430430
for obsoletedIter.HasNext() {
431431
oldDocNum := obsoletedIter.Next()
432432
newDocNum := ss.oldNewDocIDs[oldDocNum]
433-
newSegmentDeleted[ss.batchID].Add(uint32(newDocNum))
433+
newSegmentsDeleted[ss.batchID].Add(uint32(newDocNum))
434434
}
435435
}
436436
}
437437

438-
skipped := make([]bool, len(nextMerge.new))
438+
skipped := make([]bool, len(nextMerge.newSegments))
439439
// make the newly merged segments part of the newSnapshot being constructed
440-
for i, newMergedSegment := range nextMerge.new {
440+
for i, newMergedSegment := range nextMerge.newSegments {
441+
if newMergedSegment == nil {
442+
if nextMerge.fileMerge {
443+
atomic.AddUint64(&s.stats.TotFileMergeIntroductionsSkipped, 1)
444+
} else {
445+
atomic.AddUint64(&s.stats.TotMemMergeIntroductionsSkipped, 1)
446+
}
447+
skipped[i] = true
448+
continue
449+
}
441450
// checking if this newly merged segment is worth keeping based on
442451
// obsoleted doc count since the merge intro started
443-
if newMergedSegment != nil &&
444-
newMergedSegment.Count() > newSegmentDeleted[i].GetCardinality() {
452+
if newMergedSegment.Count() > newSegmentsDeleted[i].GetCardinality() {
445453
stats := newFieldStats()
446454
if fsr, ok := newMergedSegment.(segment.FieldStatsReporter); ok {
447455
fsr.UpdateFieldStats(stats)
448456
}
449457

450458
// put the merged segment at the end of newSnapshot
451459
newSnapshot.segment = append(newSnapshot.segment, &SegmentSnapshot{
452-
id: nextMerge.id[i],
453-
segment: newMergedSegment, // take ownership for nextMerge.new's ref-count
454-
deleted: newSegmentDeleted[i],
460+
id: nextMerge.newSegmentIDs[i],
461+
segment: newMergedSegment, // take ownership for newMergedSegment's ref-count
462+
deleted: newSegmentsDeleted[i],
455463
stats: stats,
456464
cachedDocs: &cachedDocs{cache: nil},
457465
cachedMeta: newCachedMeta(),
@@ -465,13 +473,17 @@ func (s *Scorch) introduceMerge(nextMerge *segmentMerge) {
465473
case segment.PersistedSegment:
466474
fileSegments++
467475
default:
468-
docsToPersistCount += newMergedSegment.Count() - newSegmentDeleted[i].GetCardinality()
476+
docsToPersistCount += newMergedSegment.Count() - newSegmentsDeleted[i].GetCardinality()
469477
memSegments++
470478
}
471479
atomic.AddUint64(&s.stats.TotIntroducedSegmentsMerge, 1)
472480
skipped[i] = false
473481
} else {
474-
atomic.AddUint64(&s.stats.TotFileMergeIntroductionsObsoleted, 1)
482+
if nextMerge.fileMerge {
483+
atomic.AddUint64(&s.stats.TotFileMergeIntroductionsObsoleted, 1)
484+
} else {
485+
atomic.AddUint64(&s.stats.TotMemMergeIntroductionsObsoleted, 1)
486+
}
475487
skipped[i] = true
476488
}
477489
}

index/scorch/merge.go

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -185,13 +185,13 @@ func (s *Scorch) ForceMerge(ctx context.Context,
185185
mo *mergeplan.MergePlanOptions) error {
186186
// check whether force merge is already under processing
187187
s.rootLock.Lock()
188-
if s.stats.TotFileMergeForceOpsStarted >
189-
s.stats.TotFileMergeForceOpsCompleted {
188+
if atomic.LoadUint64(&s.stats.TotFileMergeForceOpsStarted) >
189+
atomic.LoadUint64(&s.stats.TotFileMergeForceOpsCompleted) {
190190
s.rootLock.Unlock()
191191
return fmt.Errorf("force merge already in progress")
192192
}
193193

194-
s.stats.TotFileMergeForceOpsStarted++
194+
atomic.AddUint64(&s.stats.TotFileMergeForceOpsStarted, 1)
195195
s.rootLock.Unlock()
196196

197197
if mo != nil {
@@ -296,6 +296,7 @@ type mergeBatch struct {
296296
newID uint64
297297
newDocNums [][]uint64
298298
newFilename string
299+
newTime uint64
299300
}
300301

301302
// planMergeAtSnapshot plans and executes the merge operations for a given snapshot
@@ -397,6 +398,7 @@ func (s *Scorch) planMergeAtSnapshot(ctrlMsg *mergerCtrl, ourSnapshot *IndexSnap
397398
newID: newSegmentID,
398399
newDocNums: nil,
399400
newFilename: zapFileName(newSegmentID),
401+
newTime: 0,
400402
}
401403
mergeBatches[batchID] = batch
402404

@@ -428,17 +430,16 @@ func (s *Scorch) planMergeAtSnapshot(ctrlMsg *mergerCtrl, ourSnapshot *IndexSnap
428430
s.markIneligibleForRemoval(batch.newFilename)
429431
path := s.path + string(os.PathSeparator) + batch.newFilename
430432

433+
prevBytesReadTotal := cumulateBytesRead(batch.segments)
431434
fileMergeZapStartTime := time.Now()
432435
atomic.AddUint64(&s.stats.TotFileMergeZapBeg, 1)
433-
prevBytesReadTotal := cumulateBytesRead(batch.segments)
434436
batch.newDocNums, _, err = s.segPlugin.MergeUsing(batch.segments, batch.drops, path,
435437
cw.cancelCh, s, s.segmentConfig)
436438
atomic.AddUint64(&s.stats.TotFileMergeZapEnd, 1)
437-
438-
fileMergeZapTime := uint64(time.Since(fileMergeZapStartTime))
439-
atomic.AddUint64(&s.stats.TotFileMergeZapTime, fileMergeZapTime)
440-
if atomic.LoadUint64(&s.stats.MaxFileMergeZapTime) < fileMergeZapTime {
441-
atomic.StoreUint64(&s.stats.MaxFileMergeZapTime, fileMergeZapTime)
439+
batch.newTime = uint64(time.Since(fileMergeZapStartTime))
440+
atomic.AddUint64(&s.stats.TotFileMergeZapTime, batch.newTime)
441+
if atomic.LoadUint64(&s.stats.MaxFileMergeZapTime) < batch.newTime {
442+
atomic.StoreUint64(&s.stats.MaxFileMergeZapTime, batch.newTime)
442443
}
443444
if err != nil {
444445
atomic.AddUint64(&s.stats.TotFileMergePlanTasksErr, 1)
@@ -473,11 +474,12 @@ func (s *Scorch) planMergeAtSnapshot(ctrlMsg *mergerCtrl, ourSnapshot *IndexSnap
473474
}
474475

475476
sm := &segmentMerge{
476-
id: newSegmentIDs,
477-
new: newSegments,
477+
newSegmentIDs: newSegmentIDs,
478+
newSegments: newSegments,
478479
mergedSegHistory: mergedSegHistory,
479480
notifyCh: make(chan *mergeTaskIntroStatus),
480481
mmaped: 1,
482+
fileMerge: true,
481483
}
482484

483485
s.fireEvent(EventKindMergeTaskIntroductionStart, 0)
@@ -532,11 +534,12 @@ type mergedSegmentHistory struct {
532534
}
533535

534536
type segmentMerge struct {
535-
id []uint64
536-
new []segment.Segment
537+
newSegmentIDs []uint64
538+
newSegments []segment.Segment
537539
mergedSegHistory map[uint64]*mergedSegmentHistory
538540
notifyCh chan *mergeTaskIntroStatus
539541
mmaped uint32
542+
fileMerge bool
540543
}
541544

542545
func cumulateBytesRead(sbs []segment.Segment) uint64 {
@@ -577,6 +580,7 @@ func (s *Scorch) mergeAndPersistInMemorySegments(flushes []*flushable, po *persi
577580
var err error
578581
defer func() {
579582
if err != nil {
583+
atomic.AddUint64(&s.stats.TotMemMergeErr, 1)
580584
errM.Lock()
581585
errs = append(errs, err)
582586
errM.Unlock()
@@ -597,10 +601,10 @@ func (s *Scorch) mergeAndPersistInMemorySegments(flushes []*flushable, po *persi
597601
newID: newSegmentID,
598602
newDocNums: nil,
599603
newFilename: zapFileName(newSegmentID),
604+
newTime: 0,
600605
}
601606
mergeBatches[batchID] = batch
602607

603-
atomic.AddUint64(&numMergedSegments, uint64(len(flush.sbsBatch)))
604608
s.markIneligibleForRemoval(batch.newFilename)
605609
path := s.path + string(os.PathSeparator) + batch.newFilename
606610

@@ -609,26 +613,32 @@ func (s *Scorch) mergeAndPersistInMemorySegments(flushes []*flushable, po *persi
609613
batch.newDocNums, _, err = s.segPlugin.MergeUsing(batch.segments, batch.drops, path,
610614
s.closeCh, s, s.segmentConfig)
611615
atomic.AddUint64(&s.stats.TotMemMergeZapEnd, 1)
612-
memMergeZapTime := uint64(time.Since(memMergeZapStartTime))
613-
atomic.AddUint64(&s.stats.TotMemMergeZapTime, memMergeZapTime)
614-
if atomic.LoadUint64(&s.stats.MaxMemMergeZapTime) < memMergeZapTime {
615-
atomic.StoreUint64(&s.stats.MaxMemMergeZapTime, memMergeZapTime)
616-
}
616+
batch.newTime = uint64(time.Since(memMergeZapStartTime))
617+
atomic.AddUint64(&s.stats.TotMemMergeZapTime, batch.newTime)
617618
if err != nil {
618-
atomic.AddUint64(&s.stats.TotMemMergeErr, 1)
619619
return
620620
}
621-
622621
batch.new, err = s.segPlugin.OpenUsing(path, s.segmentConfig)
623622
if err != nil {
624-
atomic.AddUint64(&s.stats.TotMemMergeErr, 1)
625623
return
626624
}
625+
atomic.AddUint64(&numMergedSegments, uint64(len(batch.segments)))
627626
}(batchID)
628627
}
629628
wg.Wait()
630629
close(sem)
631630

631+
var maxZapTime uint64
632+
for _, batch := range mergeBatches {
633+
if batch.newTime > maxZapTime {
634+
maxZapTime = batch.newTime
635+
}
636+
}
637+
if maxZapTime > atomic.LoadUint64(&s.stats.MaxMemMergeZapTime) {
638+
atomic.StoreUint64(&s.stats.MaxMemMergeZapTime, maxZapTime)
639+
}
640+
atomic.AddUint64(&s.stats.TotMemMergeSegments, numMergedSegments)
641+
632642
if len(errs) > 0 {
633643
var errf error
634644
numClosed := 0
@@ -666,22 +676,31 @@ func (s *Scorch) mergeAndPersistInMemorySegments(flushes []*flushable, po *persi
666676
}
667677

668678
sm := &segmentMerge{
669-
id: newSegmentIDs,
670-
new: newSegments,
679+
newSegmentIDs: newSegmentIDs,
680+
newSegments: newSegments,
671681
mergedSegHistory: mergedSegHistory,
672682
notifyCh: make(chan *mergeTaskIntroStatus),
673683
mmaped: 1,
684+
fileMerge: false,
674685
}
675686

676687
select {
677688
case <-s.closeCh:
678689
err = segment.ErrClosed
679690
return nil, nil, err
680691
case s.merges <- sm:
692+
atomic.AddUint64(&s.stats.TotMemMergeIntroductions, uint64(numBatches))
681693
}
682694

695+
introStartTime := time.Now()
683696
// blockingly wait for the introduction to complete
684697
introStatus := <-sm.notifyCh
698+
introTime := uint64(time.Since(introStartTime))
699+
atomic.AddUint64(&s.stats.TotMemMergeZapIntroductionTime, introTime)
700+
if atomic.LoadUint64(&s.stats.MaxMemMergeZapIntroductionTime) < introTime {
701+
atomic.StoreUint64(&s.stats.MaxMemMergeZapIntroductionTime, introTime)
702+
}
703+
atomic.AddUint64(&s.stats.TotMemMergeIntroductionsDone, uint64(numBatches))
685704
introducedSnapshot := introStatus.indexSnapshot
686705
introducedSegmentIDs := make(map[uint64]struct{}, numBatches)
687706
for batchID, skipped := range introStatus.skipped {
@@ -703,8 +722,6 @@ func (s *Scorch) mergeAndPersistInMemorySegments(flushes []*flushable, po *persi
703722
return nil, nil, nil
704723
}
705724

706-
atomic.AddUint64(&s.stats.TotMemMergeSegments, numMergedSegments)
707-
708725
return introducedSnapshot, introducedSegmentIDs, nil
709726
}
710727

index/scorch/stats.go

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,6 @@ type Stats struct {
6464
TotIntroducePersistEnd uint64
6565
TotIntroduceMergeBeg uint64
6666
TotIntroduceMergeEnd uint64
67-
TotIntroduceRevertBeg uint64
68-
TotIntroduceRevertEnd uint64
6967

7068
TotIntroducedItems uint64
7169
TotIntroducedSegmentsBatch uint64
@@ -127,14 +125,23 @@ type Stats struct {
127125
CurFilesIneligibleForRemoval uint64
128126
TotSnapshotsRemovedFromMetaStore uint64
129127

130-
TotMemMergeBeg uint64
131-
TotMemMergeErr uint64
132-
TotMemMergeDone uint64
133-
TotMemMergeZapBeg uint64
134-
TotMemMergeZapEnd uint64
135-
TotMemMergeZapTime uint64
136-
MaxMemMergeZapTime uint64
137-
TotMemMergeSegments uint64
128+
TotMemMergeBeg uint64
129+
TotMemMergeErr uint64
130+
TotMemMergeDone uint64
131+
TotMemMergeSegments uint64
132+
133+
TotMemMergeZapBeg uint64
134+
TotMemMergeZapEnd uint64
135+
TotMemMergeZapTime uint64
136+
MaxMemMergeZapTime uint64
137+
TotMemMergeZapIntroductionTime uint64
138+
MaxMemMergeZapIntroductionTime uint64
139+
140+
TotMemMergeIntroductions uint64
141+
TotMemMergeIntroductionsDone uint64
142+
TotMemMergeIntroductionsSkipped uint64
143+
TotMemMergeIntroductionsObsoleted uint64
144+
138145
TotMemorySegmentsAtRoot uint64
139146

140147
TotTrainedSamples uint64

0 commit comments

Comments
 (0)