Fix segment loader skip wait if all segments are loading (#25643)

Signed-off-by: Congqi Xia <congqi.xia@zilliz.com>
This commit is contained in:
congqixia 2023-07-17 19:51:18 +08:00 committed by GitHub
parent 49655d2f13
commit c490b30db7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -131,17 +131,16 @@ func (loader *segmentLoader) Load(ctx context.Context,
zap.String("segmentType", segmentType.String()), zap.String("segmentType", segmentType.String()),
) )
if len(segments) == 0 {
log.Info("no segment to load")
return nil, nil
}
// Filter out loaded & loading segments // Filter out loaded & loading segments
infos := loader.prepare(segmentType, segments...) infos := loader.prepare(segmentType, segments...)
defer loader.unregister(infos...) defer loader.unregister(infos...)
segmentNum := len(infos) // continue to wait other task done
if segmentNum == 0 { log.Info("start loading...", zap.Int("segmentNum", len(segments)), zap.Int("afterFilter", len(infos)))
log.Info("no segment to load")
return nil, nil
}
log.Info("start loading...", zap.Int("segmentNum", segmentNum))
// Check memory & storage limit // Check memory & storage limit
memUsage, diskUsage, concurrencyLevel, err := loader.requestResource(infos...) memUsage, diskUsage, concurrencyLevel, err := loader.requestResource(infos...)
@ -210,12 +209,10 @@ func (loader *segmentLoader) Load(ctx context.Context,
log.Info("load segment done", zap.Int64("segmentID", segmentID)) log.Info("load segment done", zap.Int64("segmentID", segmentID))
metrics.QueryNodeLoadSegmentLatency.WithLabelValues(fmt.Sprint(paramtable.GetNodeID())).Observe(float64(tr.ElapseSpan().Milliseconds())) metrics.QueryNodeLoadSegmentLatency.WithLabelValues(fmt.Sprint(paramtable.GetNodeID())).Observe(float64(tr.ElapseSpan().Milliseconds()))
waitCh, ok := loader.loadingSegments.Get(loadInfo.GetSegmentID())
waitCh, ok := loader.loadingSegments.Get(segmentID) if ok {
if !ok { close(waitCh)
return errors.New("segment was removed from the loading map early")
} }
close(waitCh)
return nil return nil
} }
@ -223,9 +220,9 @@ func (loader *segmentLoader) Load(ctx context.Context,
// Start to load, // Start to load,
// Make sure we can always benefit from concurrency, and not spawn too many idle goroutines // Make sure we can always benefit from concurrency, and not spawn too many idle goroutines
log.Info("start to load segments in parallel", log.Info("start to load segments in parallel",
zap.Int("segmentNum", segmentNum), zap.Int("segmentNum", len(infos)),
zap.Int("concurrencyLevel", concurrencyLevel)) zap.Int("concurrencyLevel", concurrencyLevel))
err = funcutil.ProcessFuncParallel(segmentNum, err = funcutil.ProcessFuncParallel(len(infos),
concurrencyLevel, loadSegmentFunc, "loadSegmentFunc") concurrencyLevel, loadSegmentFunc, "loadSegmentFunc")
if err != nil { if err != nil {
clearAll() clearAll()
@ -290,7 +287,14 @@ func (loader *segmentLoader) unregister(segments ...*querypb.SegmentLoadInfo) {
loader.mut.Lock() loader.mut.Lock()
defer loader.mut.Unlock() defer loader.mut.Unlock()
for i := range segments { for i := range segments {
loader.loadingSegments.GetAndRemove(segments[i].GetSegmentID()) waitCh, ok := loader.loadingSegments.GetAndRemove(segments[i].GetSegmentID())
if ok {
select {
case <-waitCh:
default: // close wait channel for failed task
close(waitCh)
}
}
} }
} }
@ -302,26 +306,32 @@ func (loader *segmentLoader) requestResource(infos ...*querypb.SegmentLoadInfo)
concurrencyLevel := funcutil.Min(runtime.GOMAXPROCS(0), len(infos)) concurrencyLevel := funcutil.Min(runtime.GOMAXPROCS(0), len(infos))
logNum := 0 var memUsage, diskUsage uint64
for _, field := range infos[0].GetBinlogPaths() { for _, info := range infos {
logNum += len(field.GetBinlogs()) logNum := 0
} for _, field := range info.GetBinlogPaths() {
if logNum > 0 { logNum += len(field.GetBinlogs())
// IO pool will be run out even with the new smaller level }
concurrencyLevel = funcutil.Min(concurrencyLevel, funcutil.Max(loader.ioPool.Free()/logNum, 1)) if logNum > 0 {
} // IO pool will be run out even with the new smaller level
concurrencyLevel = funcutil.Min(concurrencyLevel, funcutil.Max(loader.ioPool.Free()/logNum, 1))
for ; concurrencyLevel > 1; concurrencyLevel /= 2 {
_, _, err := loader.checkSegmentSize(infos, concurrencyLevel)
if err == nil {
break
} }
}
memUsage, diskUsage, err := loader.checkSegmentSize(infos, concurrencyLevel) for ; concurrencyLevel > 1; concurrencyLevel /= 2 {
if err != nil { _, _, err := loader.checkSegmentSize(infos, concurrencyLevel)
log.Warn("no sufficient resource to load segments", zap.Error(err)) if err == nil {
return 0, 0, 0, err break
}
}
mu, du, err := loader.checkSegmentSize(infos, concurrencyLevel)
if err != nil {
log.Warn("no sufficient resource to load segments", zap.Error(err))
return 0, 0, 0, err
}
memUsage += mu
diskUsage += du
} }
loader.committedMemSize += memUsage loader.committedMemSize += memUsage