mirror of
https://gitee.com/milvus-io/milvus.git
synced 2025-12-07 17:48:29 +08:00
related: #44439 Signed-off-by: MrPresent-Han <chun.han@gmail.com> Co-authored-by: MrPresent-Han <chun.han@gmail.com>
This commit is contained in:
parent
0e5fb8ac6f
commit
1b7562a766
@ -6,7 +6,7 @@ require (
|
|||||||
github.com/blang/semver/v4 v4.0.0
|
github.com/blang/semver/v4 v4.0.0
|
||||||
github.com/cockroachdb/errors v1.9.1
|
github.com/cockroachdb/errors v1.9.1
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
|
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
|
||||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250911093549-4cc2bace3f8c
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.3-0.20250918113553-d15826602cc9
|
||||||
github.com/milvus-io/milvus/pkg/v2 v2.0.0-20250319085209-5a6b4e56d59e
|
github.com/milvus-io/milvus/pkg/v2 v2.0.0-20250319085209-5a6b4e56d59e
|
||||||
github.com/quasilyte/go-ruleguard/dsl v0.3.22
|
github.com/quasilyte/go-ruleguard/dsl v0.3.22
|
||||||
github.com/samber/lo v1.27.0
|
github.com/samber/lo v1.27.0
|
||||||
|
|||||||
@ -320,6 +320,8 @@ github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/le
|
|||||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250911093549-4cc2bace3f8c h1:B7zmZ30lWHE4wNjT/g2NPe3q0gcUtw7cA5shMtWAmDc=
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250911093549-4cc2bace3f8c h1:B7zmZ30lWHE4wNjT/g2NPe3q0gcUtw7cA5shMtWAmDc=
|
||||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250911093549-4cc2bace3f8c/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs=
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250911093549-4cc2bace3f8c/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs=
|
||||||
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.3-0.20250918113553-d15826602cc9 h1:7ojrhnBHitGaqebExGP00x0wDTioMgPniEBmNdFPiDI=
|
||||||
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.3-0.20250918113553-d15826602cc9/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs=
|
||||||
github.com/milvus-io/milvus/pkg/v2 v2.0.0-20250319085209-5a6b4e56d59e h1:VCr43pG4efacDbM4au70fh8/5hNTftoWzm1iEumvDWM=
|
github.com/milvus-io/milvus/pkg/v2 v2.0.0-20250319085209-5a6b4e56d59e h1:VCr43pG4efacDbM4au70fh8/5hNTftoWzm1iEumvDWM=
|
||||||
github.com/milvus-io/milvus/pkg/v2 v2.0.0-20250319085209-5a6b4e56d59e/go.mod h1:37AWzxVs2NS4QUJrkcbeLUwi+4Av0h5mEdjLI62EANU=
|
github.com/milvus-io/milvus/pkg/v2 v2.0.0-20250319085209-5a6b4e56d59e/go.mod h1:37AWzxVs2NS4QUJrkcbeLUwi+4Av0h5mEdjLI62EANU=
|
||||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||||
|
|||||||
2
go.mod
2
go.mod
@ -21,7 +21,7 @@ require (
|
|||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
|
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
|
||||||
github.com/klauspost/compress v1.17.9
|
github.com/klauspost/compress v1.17.9
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d
|
||||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250911093549-4cc2bace3f8c
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.3-0.20250918113553-d15826602cc9
|
||||||
github.com/minio/minio-go/v7 v7.0.73
|
github.com/minio/minio-go/v7 v7.0.73
|
||||||
github.com/panjf2000/ants/v2 v2.11.3 // indirect
|
github.com/panjf2000/ants/v2 v2.11.3 // indirect
|
||||||
github.com/pingcap/log v1.1.1-0.20221015072633-39906604fb81
|
github.com/pingcap/log v1.1.1-0.20221015072633-39906604fb81
|
||||||
|
|||||||
2
go.sum
2
go.sum
@ -793,6 +793,8 @@ github.com/milvus-io/gorocksdb v0.0.0-20220624081344-8c5f4212846b h1:TfeY0NxYxZz
|
|||||||
github.com/milvus-io/gorocksdb v0.0.0-20220624081344-8c5f4212846b/go.mod h1:iwW+9cWfIzzDseEBCCeDSN5SD16Tidvy8cwQ7ZY8Qj4=
|
github.com/milvus-io/gorocksdb v0.0.0-20220624081344-8c5f4212846b/go.mod h1:iwW+9cWfIzzDseEBCCeDSN5SD16Tidvy8cwQ7ZY8Qj4=
|
||||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250911093549-4cc2bace3f8c h1:B7zmZ30lWHE4wNjT/g2NPe3q0gcUtw7cA5shMtWAmDc=
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250911093549-4cc2bace3f8c h1:B7zmZ30lWHE4wNjT/g2NPe3q0gcUtw7cA5shMtWAmDc=
|
||||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250911093549-4cc2bace3f8c/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs=
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250911093549-4cc2bace3f8c/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs=
|
||||||
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.3-0.20250918113553-d15826602cc9 h1:7ojrhnBHitGaqebExGP00x0wDTioMgPniEBmNdFPiDI=
|
||||||
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.3-0.20250918113553-d15826602cc9/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs=
|
||||||
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs=
|
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs=
|
||||||
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
|
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
|
||||||
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI=
|
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI=
|
||||||
|
|||||||
@ -14,6 +14,7 @@ type LevelZeroSegmentsView struct {
|
|||||||
label *CompactionGroupLabel
|
label *CompactionGroupLabel
|
||||||
segments []*SegmentView
|
segments []*SegmentView
|
||||||
earliestGrowingSegmentPos *msgpb.MsgPosition
|
earliestGrowingSegmentPos *msgpb.MsgPosition
|
||||||
|
triggerID int64
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ CompactionView = (*LevelZeroSegmentsView)(nil)
|
var _ CompactionView = (*LevelZeroSegmentsView)(nil)
|
||||||
@ -86,12 +87,61 @@ func (v *LevelZeroSegmentsView) ForceTrigger() (CompactionView, string) {
|
|||||||
label: v.label,
|
label: v.label,
|
||||||
segments: targetViews,
|
segments: targetViews,
|
||||||
earliestGrowingSegmentPos: v.earliestGrowingSegmentPos,
|
earliestGrowingSegmentPos: v.earliestGrowingSegmentPos,
|
||||||
|
triggerID: v.triggerID,
|
||||||
}, reason
|
}, reason
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, ""
|
return nil, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *LevelZeroSegmentsView) ForceTriggerAll() ([]CompactionView, string) {
|
||||||
|
// Only choose segments with position less than the earliest growing segment position
|
||||||
|
validSegments := lo.Filter(v.segments, func(view *SegmentView, _ int) bool {
|
||||||
|
return view.dmlPos.GetTimestamp() < v.earliestGrowingSegmentPos.GetTimestamp()
|
||||||
|
})
|
||||||
|
|
||||||
|
if len(validSegments) == 0 {
|
||||||
|
return nil, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultViews []CompactionView
|
||||||
|
var lastReason string
|
||||||
|
remainingSegments := validSegments
|
||||||
|
|
||||||
|
// Multi-round force trigger loop
|
||||||
|
for len(remainingSegments) > 0 {
|
||||||
|
targetViews, reason := v.forceTrigger(remainingSegments)
|
||||||
|
if len(targetViews) == 0 {
|
||||||
|
// No more segments can be force triggered, break the loop
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new LevelZeroSegmentsView for this round's target views
|
||||||
|
roundView := &LevelZeroSegmentsView{
|
||||||
|
label: v.label,
|
||||||
|
segments: targetViews,
|
||||||
|
earliestGrowingSegmentPos: v.earliestGrowingSegmentPos,
|
||||||
|
triggerID: v.triggerID,
|
||||||
|
}
|
||||||
|
resultViews = append(resultViews, roundView)
|
||||||
|
lastReason = reason
|
||||||
|
|
||||||
|
// Remove the target segments from remaining segments for next round
|
||||||
|
targetSegmentIDs := lo.Map(targetViews, func(view *SegmentView, _ int) int64 {
|
||||||
|
return view.ID
|
||||||
|
})
|
||||||
|
remainingSegments = lo.Filter(remainingSegments, func(view *SegmentView, _ int) bool {
|
||||||
|
return !lo.Contains(targetSegmentIDs, view.ID)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultViews, lastReason
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *LevelZeroSegmentsView) GetTriggerID() int64 {
|
||||||
|
return v.triggerID
|
||||||
|
}
|
||||||
|
|
||||||
// Trigger triggers all qualified LevelZeroSegments according to views
|
// Trigger triggers all qualified LevelZeroSegments according to views
|
||||||
func (v *LevelZeroSegmentsView) Trigger() (CompactionView, string) {
|
func (v *LevelZeroSegmentsView) Trigger() (CompactionView, string) {
|
||||||
// Only choose segments with position less than the earliest growing segment position
|
// Only choose segments with position less than the earliest growing segment position
|
||||||
@ -105,6 +155,7 @@ func (v *LevelZeroSegmentsView) Trigger() (CompactionView, string) {
|
|||||||
label: v.label,
|
label: v.label,
|
||||||
segments: targetViews,
|
segments: targetViews,
|
||||||
earliestGrowingSegmentPos: v.earliestGrowingSegmentPos,
|
earliestGrowingSegmentPos: v.earliestGrowingSegmentPos,
|
||||||
|
triggerID: v.triggerID,
|
||||||
}, reason
|
}, reason
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -45,7 +45,10 @@ func (s *LevelZeroSegmentsViewSuite) SetupTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
targetView := &LevelZeroSegmentsView{
|
targetView := &LevelZeroSegmentsView{
|
||||||
label, segments, &msgpb.MsgPosition{Timestamp: 10000},
|
label: label,
|
||||||
|
segments: segments,
|
||||||
|
earliestGrowingSegmentPos: &msgpb.MsgPosition{Timestamp: 10000},
|
||||||
|
triggerID: 10000,
|
||||||
}
|
}
|
||||||
|
|
||||||
s.True(label.Equal(targetView.GetGroupLabel()))
|
s.True(label.Equal(targetView.GetGroupLabel()))
|
||||||
|
|||||||
@ -306,6 +306,14 @@ func (v *ClusteringSegmentsView) Trigger() (CompactionView, string) {
|
|||||||
return v, ""
|
return v, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *ClusteringSegmentsView) GetTriggerID() int64 {
|
||||||
|
return v.triggerID
|
||||||
|
}
|
||||||
|
|
||||||
func (v *ClusteringSegmentsView) ForceTrigger() (CompactionView, string) {
|
func (v *ClusteringSegmentsView) ForceTrigger() (CompactionView, string) {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *ClusteringSegmentsView) ForceTriggerAll() ([]CompactionView, string) {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package datacoord
|
package datacoord
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -8,8 +9,10 @@ import (
|
|||||||
"go.uber.org/atomic"
|
"go.uber.org/atomic"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
|
"github.com/milvus-io/milvus/internal/datacoord/allocator"
|
||||||
"github.com/milvus-io/milvus/pkg/v2/log"
|
"github.com/milvus-io/milvus/pkg/v2/log"
|
||||||
"github.com/milvus-io/milvus/pkg/v2/proto/datapb"
|
"github.com/milvus-io/milvus/pkg/v2/proto/datapb"
|
||||||
|
"github.com/milvus-io/milvus/pkg/v2/util/merr"
|
||||||
"github.com/milvus-io/milvus/pkg/v2/util/paramtable"
|
"github.com/milvus-io/milvus/pkg/v2/util/paramtable"
|
||||||
"github.com/milvus-io/milvus/pkg/v2/util/typeutil"
|
"github.com/milvus-io/milvus/pkg/v2/util/typeutil"
|
||||||
)
|
)
|
||||||
@ -18,16 +21,18 @@ type l0CompactionPolicy struct {
|
|||||||
meta *meta
|
meta *meta
|
||||||
|
|
||||||
activeCollections *activeCollections
|
activeCollections *activeCollections
|
||||||
|
allocator allocator.Allocator
|
||||||
|
|
||||||
// key: collectionID, value: reference count
|
// key: collectionID, value: reference count
|
||||||
skipCompactionCollections map[int64]int
|
skipCompactionCollections map[int64]int
|
||||||
skipLocker sync.RWMutex
|
skipLocker sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func newL0CompactionPolicy(meta *meta) *l0CompactionPolicy {
|
func newL0CompactionPolicy(meta *meta, allocator allocator.Allocator) *l0CompactionPolicy {
|
||||||
return &l0CompactionPolicy{
|
return &l0CompactionPolicy{
|
||||||
meta: meta,
|
meta: meta,
|
||||||
activeCollections: newActiveCollections(),
|
activeCollections: newActiveCollections(),
|
||||||
|
allocator: allocator,
|
||||||
skipCompactionCollections: make(map[int64]int),
|
skipCompactionCollections: make(map[int64]int),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,8 +74,7 @@ func (policy *l0CompactionPolicy) OnCollectionUpdate(collectionID int64) {
|
|||||||
policy.activeCollections.Record(collectionID)
|
policy.activeCollections.Record(collectionID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (policy *l0CompactionPolicy) Trigger() (events map[CompactionTriggerType][]CompactionView, err error) {
|
func (policy *l0CompactionPolicy) Trigger(ctx context.Context) (events map[CompactionTriggerType][]CompactionView, err error) {
|
||||||
events = make(map[CompactionTriggerType][]CompactionView)
|
|
||||||
latestCollSegs := policy.meta.GetCompactableSegmentGroupByCollection()
|
latestCollSegs := policy.meta.GetCompactableSegmentGroupByCollection()
|
||||||
|
|
||||||
// 1. Get active collections
|
// 1. Get active collections
|
||||||
@ -82,6 +86,12 @@ func (policy *l0CompactionPolicy) Trigger() (events map[CompactionTriggerType][]
|
|||||||
|
|
||||||
idleCollsSet := typeutil.NewUniqueSet(idleColls...)
|
idleCollsSet := typeutil.NewUniqueSet(idleColls...)
|
||||||
activeL0Views, idleL0Views := []CompactionView{}, []CompactionView{}
|
activeL0Views, idleL0Views := []CompactionView{}, []CompactionView{}
|
||||||
|
newTriggerID, err := policy.allocator.AllocID(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("fail to allocate triggerID to trigger l0 compaction", zap.Error(err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
events = make(map[CompactionTriggerType][]CompactionView)
|
||||||
for collID, segments := range latestCollSegs {
|
for collID, segments := range latestCollSegs {
|
||||||
if policy.isSkipCollection(collID) {
|
if policy.isSkipCollection(collID) {
|
||||||
continue
|
continue
|
||||||
@ -94,8 +104,7 @@ func (policy *l0CompactionPolicy) Trigger() (events map[CompactionTriggerType][]
|
|||||||
if len(levelZeroSegments) == 0 {
|
if len(levelZeroSegments) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
labelViews := policy.groupL0ViewsByPartChan(collID, GetViewsByInfo(levelZeroSegments...), newTriggerID)
|
||||||
labelViews := policy.groupL0ViewsByPartChan(collID, GetViewsByInfo(levelZeroSegments...))
|
|
||||||
if idleCollsSet.Contain(collID) {
|
if idleCollsSet.Contain(collID) {
|
||||||
idleL0Views = append(idleL0Views, labelViews...)
|
idleL0Views = append(idleL0Views, labelViews...)
|
||||||
} else {
|
} else {
|
||||||
@ -113,7 +122,7 @@ func (policy *l0CompactionPolicy) Trigger() (events map[CompactionTriggerType][]
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (policy *l0CompactionPolicy) groupL0ViewsByPartChan(collectionID UniqueID, levelZeroSegments []*SegmentView) []CompactionView {
|
func (policy *l0CompactionPolicy) groupL0ViewsByPartChan(collectionID UniqueID, levelZeroSegments []*SegmentView, triggerID UniqueID) []CompactionView {
|
||||||
partChanView := make(map[string]*LevelZeroSegmentsView) // "part-chan" as key
|
partChanView := make(map[string]*LevelZeroSegmentsView) // "part-chan" as key
|
||||||
for _, view := range levelZeroSegments {
|
for _, view := range levelZeroSegments {
|
||||||
key := view.label.Key()
|
key := view.label.Key()
|
||||||
@ -122,6 +131,7 @@ func (policy *l0CompactionPolicy) groupL0ViewsByPartChan(collectionID UniqueID,
|
|||||||
label: view.label,
|
label: view.label,
|
||||||
segments: []*SegmentView{view},
|
segments: []*SegmentView{view},
|
||||||
earliestGrowingSegmentPos: policy.meta.GetEarliestStartPositionOfGrowingSegments(view.label),
|
earliestGrowingSegmentPos: policy.meta.GetEarliestStartPositionOfGrowingSegments(view.label),
|
||||||
|
triggerID: triggerID,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
partChanView[key].Append(view)
|
partChanView[key].Append(view)
|
||||||
@ -133,6 +143,33 @@ func (policy *l0CompactionPolicy) groupL0ViewsByPartChan(collectionID UniqueID,
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (policy *l0CompactionPolicy) triggerOneCollection(ctx context.Context, collectionID int64) ([]CompactionView, int64, error) {
|
||||||
|
log := log.Ctx(ctx).With(zap.Int64("collectionID", collectionID))
|
||||||
|
log.Info("start trigger collection l0 compaction")
|
||||||
|
if policy.isSkipCollection(collectionID) {
|
||||||
|
return nil, 0, merr.WrapErrCollectionNotLoaded(collectionID, "the collection being paused by importing cannot do force l0 compaction")
|
||||||
|
}
|
||||||
|
allL0Segments := policy.meta.SelectSegments(ctx, WithCollection(collectionID), SegmentFilterFunc(func(segment *SegmentInfo) bool {
|
||||||
|
return isSegmentHealthy(segment) &&
|
||||||
|
isFlushed(segment) &&
|
||||||
|
!segment.isCompacting && // not compacting now
|
||||||
|
!segment.GetIsImporting() && // not importing now
|
||||||
|
segment.GetLevel() == datapb.SegmentLevel_L0
|
||||||
|
}))
|
||||||
|
|
||||||
|
if len(allL0Segments) == 0 {
|
||||||
|
return nil, 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
newTriggerID, err := policy.allocator.AllocID(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("fail to allocate triggerID for l0 compaction", zap.Error(err))
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
views := policy.groupL0ViewsByPartChan(collectionID, GetViewsByInfo(allL0Segments...), newTriggerID)
|
||||||
|
return views, newTriggerID, nil
|
||||||
|
}
|
||||||
|
|
||||||
type activeCollection struct {
|
type activeCollection struct {
|
||||||
ID int64
|
ID int64
|
||||||
lastRefresh time.Time
|
lastRefresh time.Time
|
||||||
|
|||||||
@ -16,15 +16,17 @@
|
|||||||
package datacoord
|
package datacoord
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"github.com/milvus-io/milvus-proto/go-api/v2/commonpb"
|
"github.com/milvus-io/milvus-proto/go-api/v2/commonpb"
|
||||||
"github.com/milvus-io/milvus-proto/go-api/v2/msgpb"
|
"github.com/milvus-io/milvus-proto/go-api/v2/msgpb"
|
||||||
"github.com/milvus-io/milvus/internal/allocator"
|
"github.com/milvus-io/milvus/internal/datacoord/allocator"
|
||||||
"github.com/milvus-io/milvus/pkg/v2/log"
|
"github.com/milvus-io/milvus/pkg/v2/log"
|
||||||
"github.com/milvus-io/milvus/pkg/v2/proto/datapb"
|
"github.com/milvus-io/milvus/pkg/v2/proto/datapb"
|
||||||
"github.com/milvus-io/milvus/pkg/v2/util/paramtable"
|
"github.com/milvus-io/milvus/pkg/v2/util/paramtable"
|
||||||
@ -58,8 +60,8 @@ func (s *L0CompactionPolicySuite) SetupTest() {
|
|||||||
for id, segment := range segments {
|
for id, segment := range segments {
|
||||||
meta.segments.SetSegment(id, segment)
|
meta.segments.SetSegment(id, segment)
|
||||||
}
|
}
|
||||||
|
s.mockAlloc = allocator.NewMockAllocator(s.T())
|
||||||
s.l0_policy = newL0CompactionPolicy(meta)
|
s.l0_policy = newL0CompactionPolicy(meta, s.mockAlloc)
|
||||||
}
|
}
|
||||||
|
|
||||||
const MB = 1024 * 1024
|
const MB = 1024 * 1024
|
||||||
@ -68,13 +70,14 @@ func (s *L0CompactionPolicySuite) TestActiveToIdle() {
|
|||||||
paramtable.Get().Save(paramtable.Get().DataCoordCfg.L0CompactionTriggerInterval.Key, "1")
|
paramtable.Get().Save(paramtable.Get().DataCoordCfg.L0CompactionTriggerInterval.Key, "1")
|
||||||
defer paramtable.Get().Reset(paramtable.Get().DataCoordCfg.L0CompactionTriggerInterval.Key)
|
defer paramtable.Get().Reset(paramtable.Get().DataCoordCfg.L0CompactionTriggerInterval.Key)
|
||||||
|
|
||||||
|
s.mockAlloc.EXPECT().AllocID(mock.Anything).Return(1, nil)
|
||||||
s.l0_policy.OnCollectionUpdate(1)
|
s.l0_policy.OnCollectionUpdate(1)
|
||||||
s.Require().EqualValues(1, s.l0_policy.activeCollections.GetActiveCollections()[0])
|
s.Require().EqualValues(1, s.l0_policy.activeCollections.GetActiveCollections()[0])
|
||||||
|
|
||||||
<-time.After(3 * time.Second)
|
<-time.After(3 * time.Second)
|
||||||
|
|
||||||
for range 3 {
|
for range 3 {
|
||||||
gotViews, err := s.l0_policy.Trigger()
|
gotViews, err := s.l0_policy.Trigger(context.Background())
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
s.NotNil(gotViews)
|
s.NotNil(gotViews)
|
||||||
s.NotEmpty(gotViews)
|
s.NotEmpty(gotViews)
|
||||||
@ -83,7 +86,7 @@ func (s *L0CompactionPolicySuite) TestActiveToIdle() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.Empty(s.l0_policy.activeCollections.GetActiveCollections())
|
s.Empty(s.l0_policy.activeCollections.GetActiveCollections())
|
||||||
gotViews, err := s.l0_policy.Trigger()
|
gotViews, err := s.l0_policy.Trigger(context.Background())
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
s.NotNil(gotViews)
|
s.NotNil(gotViews)
|
||||||
s.NotEmpty(gotViews)
|
s.NotEmpty(gotViews)
|
||||||
@ -93,8 +96,8 @@ func (s *L0CompactionPolicySuite) TestActiveToIdle() {
|
|||||||
|
|
||||||
func (s *L0CompactionPolicySuite) TestTriggerIdle() {
|
func (s *L0CompactionPolicySuite) TestTriggerIdle() {
|
||||||
s.Require().Empty(s.l0_policy.activeCollections.GetActiveCollections())
|
s.Require().Empty(s.l0_policy.activeCollections.GetActiveCollections())
|
||||||
|
s.mockAlloc.EXPECT().AllocID(mock.Anything).Return(1, nil)
|
||||||
events, err := s.l0_policy.Trigger()
|
events, err := s.l0_policy.Trigger(context.Background())
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
s.NotEmpty(events)
|
s.NotEmpty(events)
|
||||||
|
|
||||||
@ -118,18 +121,18 @@ func (s *L0CompactionPolicySuite) TestTriggerIdle() {
|
|||||||
s.l0_policy.AddSkipCollection(1)
|
s.l0_policy.AddSkipCollection(1)
|
||||||
s.l0_policy.AddSkipCollection(1)
|
s.l0_policy.AddSkipCollection(1)
|
||||||
// Test for skip collection
|
// Test for skip collection
|
||||||
events, err = s.l0_policy.Trigger()
|
events, err = s.l0_policy.Trigger(context.Background())
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
s.Empty(events)
|
s.Empty(events)
|
||||||
|
|
||||||
// Test for skip collection with ref count
|
// Test for skip collection with ref count
|
||||||
s.l0_policy.RemoveSkipCollection(1)
|
s.l0_policy.RemoveSkipCollection(1)
|
||||||
events, err = s.l0_policy.Trigger()
|
events, err = s.l0_policy.Trigger(context.Background())
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
s.Empty(events)
|
s.Empty(events)
|
||||||
|
|
||||||
s.l0_policy.RemoveSkipCollection(1)
|
s.l0_policy.RemoveSkipCollection(1)
|
||||||
events, err = s.l0_policy.Trigger()
|
events, err = s.l0_policy.Trigger(context.Background())
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
s.Equal(1, len(events))
|
s.Equal(1, len(events))
|
||||||
gotViews, ok = events[TriggerTypeLevelZeroViewIDLE]
|
gotViews, ok = events[TriggerTypeLevelZeroViewIDLE]
|
||||||
@ -166,9 +169,10 @@ func (s *L0CompactionPolicySuite) TestTriggerViewChange() {
|
|||||||
meta.segments.SetSegment(id, segment)
|
meta.segments.SetSegment(id, segment)
|
||||||
}
|
}
|
||||||
s.l0_policy.meta = meta
|
s.l0_policy.meta = meta
|
||||||
|
s.mockAlloc.EXPECT().AllocID(mock.Anything).Return(1, nil)
|
||||||
|
|
||||||
s.l0_policy.OnCollectionUpdate(s.testLabel.CollectionID)
|
s.l0_policy.OnCollectionUpdate(s.testLabel.CollectionID)
|
||||||
events, err := s.l0_policy.Trigger()
|
events, err := s.l0_policy.Trigger(context.Background())
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
s.Equal(1, len(events))
|
s.Equal(1, len(events))
|
||||||
gotViews, ok := events[TriggerTypeLevelZeroViewChange]
|
gotViews, ok := events[TriggerTypeLevelZeroViewChange]
|
||||||
@ -180,6 +184,11 @@ func (s *L0CompactionPolicySuite) TestTriggerViewChange() {
|
|||||||
s.Empty(gotViews)
|
s.Empty(gotViews)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *L0CompactionPolicySuite) TestManualTrigger() {
|
||||||
|
s.mockAlloc.EXPECT().AllocID(mock.Anything).Return(1, nil)
|
||||||
|
s.l0_policy.triggerOneCollection(context.Background(), s.testLabel.CollectionID)
|
||||||
|
}
|
||||||
|
|
||||||
func genSegmentsForMeta(label *CompactionGroupLabel) map[int64]*SegmentInfo {
|
func genSegmentsForMeta(label *CompactionGroupLabel) map[int64]*SegmentInfo {
|
||||||
segArgs := []struct {
|
segArgs := []struct {
|
||||||
ID UniqueID
|
ID UniqueID
|
||||||
|
|||||||
@ -307,3 +307,11 @@ func (v *MixSegmentView) Trigger() (CompactionView, string) {
|
|||||||
func (v *MixSegmentView) ForceTrigger() (CompactionView, string) {
|
func (v *MixSegmentView) ForceTrigger() (CompactionView, string) {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *MixSegmentView) ForceTriggerAll() ([]CompactionView, string) {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *MixSegmentView) GetTriggerID() int64 {
|
||||||
|
return v.triggerID
|
||||||
|
}
|
||||||
|
|||||||
@ -38,6 +38,7 @@ type CompactionTriggerType int8
|
|||||||
const (
|
const (
|
||||||
TriggerTypeLevelZeroViewChange CompactionTriggerType = iota + 1
|
TriggerTypeLevelZeroViewChange CompactionTriggerType = iota + 1
|
||||||
TriggerTypeLevelZeroViewIDLE
|
TriggerTypeLevelZeroViewIDLE
|
||||||
|
TriggerTypeLevelZeroViewManual
|
||||||
TriggerTypeSegmentSizeViewChange
|
TriggerTypeSegmentSizeViewChange
|
||||||
TriggerTypeClustering
|
TriggerTypeClustering
|
||||||
TriggerTypeSingle
|
TriggerTypeSingle
|
||||||
@ -50,6 +51,8 @@ func (t CompactionTriggerType) String() string {
|
|||||||
return "LevelZeroViewChange"
|
return "LevelZeroViewChange"
|
||||||
case TriggerTypeLevelZeroViewIDLE:
|
case TriggerTypeLevelZeroViewIDLE:
|
||||||
return "LevelZeroViewIDLE"
|
return "LevelZeroViewIDLE"
|
||||||
|
case TriggerTypeLevelZeroViewManual:
|
||||||
|
return "LevelZeroViewManual"
|
||||||
case TriggerTypeSegmentSizeViewChange:
|
case TriggerTypeSegmentSizeViewChange:
|
||||||
return "SegmentSizeViewChange"
|
return "SegmentSizeViewChange"
|
||||||
case TriggerTypeClustering:
|
case TriggerTypeClustering:
|
||||||
@ -67,7 +70,7 @@ type TriggerManager interface {
|
|||||||
Start()
|
Start()
|
||||||
Stop()
|
Stop()
|
||||||
OnCollectionUpdate(collectionID int64)
|
OnCollectionUpdate(collectionID int64)
|
||||||
ManualTrigger(ctx context.Context, collectionID int64, clusteringCompaction bool) (UniqueID, error)
|
ManualTrigger(ctx context.Context, collectionID int64, clusteringCompaction bool, l0Compaction bool) (UniqueID, error)
|
||||||
GetPauseCompactionChan(jobID, collectionID int64) <-chan struct{}
|
GetPauseCompactionChan(jobID, collectionID int64) <-chan struct{}
|
||||||
GetResumeCompactionChan(jobID, collectionID int64) <-chan struct{}
|
GetResumeCompactionChan(jobID, collectionID int64) <-chan struct{}
|
||||||
}
|
}
|
||||||
@ -119,7 +122,7 @@ func NewCompactionTriggerManager(alloc allocator.Allocator, handler Handler, ins
|
|||||||
}
|
}
|
||||||
m.l0SigLock = &sync.Mutex{}
|
m.l0SigLock = &sync.Mutex{}
|
||||||
m.l0TickSig = sync.NewCond(m.l0SigLock)
|
m.l0TickSig = sync.NewCond(m.l0SigLock)
|
||||||
m.l0Policy = newL0CompactionPolicy(meta)
|
m.l0Policy = newL0CompactionPolicy(meta, alloc)
|
||||||
m.clusteringPolicy = newClusteringCompactionPolicy(meta, m.allocator, m.handler)
|
m.clusteringPolicy = newClusteringCompactionPolicy(meta, m.allocator, m.handler)
|
||||||
m.singlePolicy = newSingleCompactionPolicy(meta, m.allocator, m.handler)
|
m.singlePolicy = newSingleCompactionPolicy(meta, m.allocator, m.handler)
|
||||||
return m
|
return m
|
||||||
@ -231,7 +234,7 @@ func (m *CompactionTriggerManager) loop(ctx context.Context) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
m.setL0Triggering(true)
|
m.setL0Triggering(true)
|
||||||
events, err := m.l0Policy.Trigger()
|
events, err := m.l0Policy.Trigger(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("Fail to trigger L0 policy", zap.Error(err))
|
log.Warn("Fail to trigger L0 policy", zap.Error(err))
|
||||||
m.setL0Triggering(false)
|
m.setL0Triggering(false)
|
||||||
@ -291,14 +294,27 @@ func (m *CompactionTriggerManager) loop(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *CompactionTriggerManager) ManualTrigger(ctx context.Context, collectionID int64, clusteringCompaction bool) (UniqueID, error) {
|
func (m *CompactionTriggerManager) ManualTrigger(ctx context.Context, collectionID int64, clusteringCompaction bool, l0Compaction bool) (UniqueID, error) {
|
||||||
log.Ctx(ctx).Info("receive manual trigger", zap.Int64("collectionID", collectionID))
|
log.Ctx(ctx).Info("receive manual trigger", zap.Int64("collectionID", collectionID),
|
||||||
views, triggerID, err := m.clusteringPolicy.triggerOneCollection(ctx, collectionID, true)
|
zap.Bool("clusteringCompaction", clusteringCompaction), zap.Bool("l0Compaction", l0Compaction))
|
||||||
|
|
||||||
|
var triggerID UniqueID
|
||||||
|
var err error
|
||||||
|
var views []CompactionView
|
||||||
|
|
||||||
|
events := make(map[CompactionTriggerType][]CompactionView, 0)
|
||||||
|
if l0Compaction {
|
||||||
|
m.setL0Triggering(true)
|
||||||
|
defer m.setL0Triggering(false)
|
||||||
|
views, triggerID, err = m.l0Policy.triggerOneCollection(ctx, collectionID)
|
||||||
|
events[TriggerTypeLevelZeroViewManual] = views
|
||||||
|
} else if clusteringCompaction {
|
||||||
|
views, triggerID, err = m.clusteringPolicy.triggerOneCollection(ctx, collectionID, true)
|
||||||
|
events[TriggerTypeClustering] = views
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
events := make(map[CompactionTriggerType][]CompactionView, 0)
|
|
||||||
events[TriggerTypeClustering] = views
|
|
||||||
if len(events) > 0 {
|
if len(events) > 0 {
|
||||||
for triggerType, views := range events {
|
for triggerType, views := range events {
|
||||||
m.notify(ctx, triggerType, views)
|
m.notify(ctx, triggerType, views)
|
||||||
@ -307,31 +323,41 @@ func (m *CompactionTriggerManager) ManualTrigger(ctx context.Context, collection
|
|||||||
return triggerID, nil
|
return triggerID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *CompactionTriggerManager) triggerViewForCompaction(ctx context.Context, eventType CompactionTriggerType,
|
||||||
|
view CompactionView) ([]CompactionView, string) {
|
||||||
|
if eventType == TriggerTypeLevelZeroViewIDLE {
|
||||||
|
view, reason := view.ForceTrigger()
|
||||||
|
return []CompactionView{view}, reason
|
||||||
|
} else if eventType == TriggerTypeLevelZeroViewManual {
|
||||||
|
return view.ForceTriggerAll()
|
||||||
|
}
|
||||||
|
outView, reason := view.Trigger()
|
||||||
|
return []CompactionView{outView}, reason
|
||||||
|
}
|
||||||
|
|
||||||
func (m *CompactionTriggerManager) notify(ctx context.Context, eventType CompactionTriggerType, views []CompactionView) {
|
func (m *CompactionTriggerManager) notify(ctx context.Context, eventType CompactionTriggerType, views []CompactionView) {
|
||||||
log := log.Ctx(ctx)
|
log := log.Ctx(ctx)
|
||||||
log.Debug("Start to trigger compactions", zap.String("eventType", eventType.String()))
|
log.Debug("Start to trigger compactions", zap.String("eventType", eventType.String()))
|
||||||
for _, view := range views {
|
for _, view := range views {
|
||||||
outView, reason := view.Trigger()
|
outViews, reason := m.triggerViewForCompaction(ctx, eventType, view)
|
||||||
if outView == nil && eventType == TriggerTypeLevelZeroViewIDLE {
|
for _, outView := range outViews {
|
||||||
log.Info("Start to force trigger a level zero compaction")
|
if outView != nil {
|
||||||
outView, reason = view.ForceTrigger()
|
log.Info("Success to trigger a compaction, try to submit",
|
||||||
}
|
zap.String("eventType", eventType.String()),
|
||||||
|
zap.String("reason", reason),
|
||||||
|
zap.String("output view", outView.String()),
|
||||||
|
zap.Int64("triggerID", outView.GetTriggerID()))
|
||||||
|
|
||||||
if outView != nil {
|
switch eventType {
|
||||||
log.Info("Success to trigger a compaction, try to submit",
|
case TriggerTypeLevelZeroViewChange, TriggerTypeLevelZeroViewIDLE, TriggerTypeLevelZeroViewManual:
|
||||||
zap.String("eventType", eventType.String()),
|
m.SubmitL0ViewToScheduler(ctx, outView)
|
||||||
zap.String("reason", reason),
|
case TriggerTypeClustering:
|
||||||
zap.String("output view", outView.String()))
|
m.SubmitClusteringViewToScheduler(ctx, outView)
|
||||||
|
case TriggerTypeSingle:
|
||||||
switch eventType {
|
m.SubmitSingleViewToScheduler(ctx, outView, datapb.CompactionType_MixCompaction)
|
||||||
case TriggerTypeLevelZeroViewChange, TriggerTypeLevelZeroViewIDLE:
|
case TriggerTypeSort:
|
||||||
m.SubmitL0ViewToScheduler(ctx, outView)
|
m.SubmitSingleViewToScheduler(ctx, outView, datapb.CompactionType_SortCompaction)
|
||||||
case TriggerTypeClustering:
|
}
|
||||||
m.SubmitClusteringViewToScheduler(ctx, outView)
|
|
||||||
case TriggerTypeSingle:
|
|
||||||
m.SubmitSingleViewToScheduler(ctx, outView, datapb.CompactionType_MixCompaction)
|
|
||||||
case TriggerTypeSort:
|
|
||||||
m.SubmitSingleViewToScheduler(ctx, outView, datapb.CompactionType_SortCompaction)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -366,7 +392,7 @@ func (m *CompactionTriggerManager) SubmitL0ViewToScheduler(ctx context.Context,
|
|||||||
})
|
})
|
||||||
|
|
||||||
task := &datapb.CompactionTask{
|
task := &datapb.CompactionTask{
|
||||||
TriggerID: taskID, // inner trigger, use task id as trigger id
|
TriggerID: view.GetTriggerID(),
|
||||||
PlanID: taskID,
|
PlanID: taskID,
|
||||||
Type: datapb.CompactionType_Level0DeleteCompaction,
|
Type: datapb.CompactionType_Level0DeleteCompaction,
|
||||||
StartTime: time.Now().Unix(),
|
StartTime: time.Now().Unix(),
|
||||||
|
|||||||
@ -87,7 +87,7 @@ func (s *CompactionTriggerManagerSuite) TestNotifyByViewIDLE() {
|
|||||||
expectedSegID := seg1.ID
|
expectedSegID := seg1.ID
|
||||||
|
|
||||||
s.Require().Equal(1, len(latestL0Segments))
|
s.Require().Equal(1, len(latestL0Segments))
|
||||||
levelZeroViews := s.triggerManager.l0Policy.groupL0ViewsByPartChan(1, latestL0Segments)
|
levelZeroViews := s.triggerManager.l0Policy.groupL0ViewsByPartChan(1, latestL0Segments, 10000)
|
||||||
s.Require().Equal(1, len(levelZeroViews))
|
s.Require().Equal(1, len(levelZeroViews))
|
||||||
cView, ok := levelZeroViews[0].(*LevelZeroSegmentsView)
|
cView, ok := levelZeroViews[0].(*LevelZeroSegmentsView)
|
||||||
s.True(ok)
|
s.True(ok)
|
||||||
@ -130,7 +130,7 @@ func (s *CompactionTriggerManagerSuite) TestNotifyByViewChange() {
|
|||||||
|
|
||||||
latestL0Segments := GetViewsByInfo(levelZeroSegments...)
|
latestL0Segments := GetViewsByInfo(levelZeroSegments...)
|
||||||
s.Require().NotEmpty(latestL0Segments)
|
s.Require().NotEmpty(latestL0Segments)
|
||||||
levelZeroViews := s.triggerManager.l0Policy.groupL0ViewsByPartChan(1, latestL0Segments)
|
levelZeroViews := s.triggerManager.l0Policy.groupL0ViewsByPartChan(1, latestL0Segments, 10000)
|
||||||
s.Require().Equal(1, len(levelZeroViews))
|
s.Require().Equal(1, len(levelZeroViews))
|
||||||
cView, ok := levelZeroViews[0].(*LevelZeroSegmentsView)
|
cView, ok := levelZeroViews[0].(*LevelZeroSegmentsView)
|
||||||
s.True(ok)
|
s.True(ok)
|
||||||
@ -398,3 +398,48 @@ func TestCompactionAndImport(t *testing.T) {
|
|||||||
defer triggerManager.Stop()
|
defer triggerManager.Stop()
|
||||||
time.Sleep(3 * time.Second)
|
time.Sleep(3 * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *CompactionTriggerManagerSuite) TestManualTriggerL0Compaction() {
|
||||||
|
handler := NewNMockHandler(s.T())
|
||||||
|
handler.EXPECT().GetCollection(mock.Anything, mock.Anything).Return(&collectionInfo{}, nil)
|
||||||
|
s.triggerManager.handler = handler
|
||||||
|
|
||||||
|
collSegs := s.meta.GetCompactableSegmentGroupByCollection()
|
||||||
|
segments, found := collSegs[1]
|
||||||
|
s.Require().True(found)
|
||||||
|
|
||||||
|
levelZeroSegments := lo.Filter(segments, func(info *SegmentInfo, _ int) bool {
|
||||||
|
return info.GetLevel() == datapb.SegmentLevel_L0
|
||||||
|
})
|
||||||
|
s.Require().NotEmpty(levelZeroSegments)
|
||||||
|
|
||||||
|
// Mock allocator for trigger ID
|
||||||
|
s.mockAlloc.EXPECT().AllocID(mock.Anything).Return(int64(12345), nil)
|
||||||
|
s.mockAlloc.EXPECT().AllocID(mock.Anything).Return(int64(19530), nil).Maybe()
|
||||||
|
|
||||||
|
// Mock inspector to expect compaction enqueue
|
||||||
|
s.inspector.EXPECT().enqueueCompaction(mock.Anything).
|
||||||
|
RunAndReturn(func(task *datapb.CompactionTask) error {
|
||||||
|
s.EqualValues(19530, task.GetTriggerID())
|
||||||
|
s.Equal(s.testLabel.CollectionID, task.GetCollectionID())
|
||||||
|
s.Equal(s.testLabel.PartitionID, task.GetPartitionID())
|
||||||
|
s.Equal(s.testLabel.Channel, task.GetChannel())
|
||||||
|
s.Equal(datapb.CompactionType_Level0DeleteCompaction, task.GetType())
|
||||||
|
|
||||||
|
expectedSegs := []int64{100, 101, 102}
|
||||||
|
s.ElementsMatch(expectedSegs, task.GetInputSegments())
|
||||||
|
return nil
|
||||||
|
}).Return(nil).Once()
|
||||||
|
|
||||||
|
// Test L0 manual trigger
|
||||||
|
triggerID, err := s.triggerManager.ManualTrigger(context.Background(), s.testLabel.CollectionID, false, true)
|
||||||
|
s.NoError(err)
|
||||||
|
s.Equal(int64(12345), triggerID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CompactionTriggerManagerSuite) TestManualTriggerInvalidParams() {
|
||||||
|
// Test with both clustering and L0 compaction false
|
||||||
|
triggerID, err := s.triggerManager.ManualTrigger(context.Background(), s.testLabel.CollectionID, false, false)
|
||||||
|
s.NoError(err)
|
||||||
|
s.Equal(int64(0), triggerID)
|
||||||
|
}
|
||||||
|
|||||||
@ -34,6 +34,8 @@ type CompactionView interface {
|
|||||||
String() string
|
String() string
|
||||||
Trigger() (CompactionView, string)
|
Trigger() (CompactionView, string)
|
||||||
ForceTrigger() (CompactionView, string)
|
ForceTrigger() (CompactionView, string)
|
||||||
|
ForceTriggerAll() ([]CompactionView, string)
|
||||||
|
GetTriggerID() int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type FullViews struct {
|
type FullViews struct {
|
||||||
|
|||||||
@ -119,9 +119,9 @@ func (_c *MockTriggerManager_GetResumeCompactionChan_Call) RunAndReturn(run func
|
|||||||
return _c
|
return _c
|
||||||
}
|
}
|
||||||
|
|
||||||
// ManualTrigger provides a mock function with given fields: ctx, collectionID, clusteringCompaction
|
// ManualTrigger provides a mock function with given fields: ctx, collectionID, clusteringCompaction, l0Compaction
|
||||||
func (_m *MockTriggerManager) ManualTrigger(ctx context.Context, collectionID int64, clusteringCompaction bool) (int64, error) {
|
func (_m *MockTriggerManager) ManualTrigger(ctx context.Context, collectionID int64, clusteringCompaction bool, l0Compaction bool) (int64, error) {
|
||||||
ret := _m.Called(ctx, collectionID, clusteringCompaction)
|
ret := _m.Called(ctx, collectionID, clusteringCompaction, l0Compaction)
|
||||||
|
|
||||||
if len(ret) == 0 {
|
if len(ret) == 0 {
|
||||||
panic("no return value specified for ManualTrigger")
|
panic("no return value specified for ManualTrigger")
|
||||||
@ -129,17 +129,17 @@ func (_m *MockTriggerManager) ManualTrigger(ctx context.Context, collectionID in
|
|||||||
|
|
||||||
var r0 int64
|
var r0 int64
|
||||||
var r1 error
|
var r1 error
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, int64, bool) (int64, error)); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, int64, bool, bool) (int64, error)); ok {
|
||||||
return rf(ctx, collectionID, clusteringCompaction)
|
return rf(ctx, collectionID, clusteringCompaction, l0Compaction)
|
||||||
}
|
}
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, int64, bool) int64); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, int64, bool, bool) int64); ok {
|
||||||
r0 = rf(ctx, collectionID, clusteringCompaction)
|
r0 = rf(ctx, collectionID, clusteringCompaction, l0Compaction)
|
||||||
} else {
|
} else {
|
||||||
r0 = ret.Get(0).(int64)
|
r0 = ret.Get(0).(int64)
|
||||||
}
|
}
|
||||||
|
|
||||||
if rf, ok := ret.Get(1).(func(context.Context, int64, bool) error); ok {
|
if rf, ok := ret.Get(1).(func(context.Context, int64, bool, bool) error); ok {
|
||||||
r1 = rf(ctx, collectionID, clusteringCompaction)
|
r1 = rf(ctx, collectionID, clusteringCompaction, l0Compaction)
|
||||||
} else {
|
} else {
|
||||||
r1 = ret.Error(1)
|
r1 = ret.Error(1)
|
||||||
}
|
}
|
||||||
@ -156,13 +156,14 @@ type MockTriggerManager_ManualTrigger_Call struct {
|
|||||||
// - ctx context.Context
|
// - ctx context.Context
|
||||||
// - collectionID int64
|
// - collectionID int64
|
||||||
// - clusteringCompaction bool
|
// - clusteringCompaction bool
|
||||||
func (_e *MockTriggerManager_Expecter) ManualTrigger(ctx interface{}, collectionID interface{}, clusteringCompaction interface{}) *MockTriggerManager_ManualTrigger_Call {
|
// - l0Compaction bool
|
||||||
return &MockTriggerManager_ManualTrigger_Call{Call: _e.mock.On("ManualTrigger", ctx, collectionID, clusteringCompaction)}
|
func (_e *MockTriggerManager_Expecter) ManualTrigger(ctx interface{}, collectionID interface{}, clusteringCompaction interface{}, l0Compaction interface{}) *MockTriggerManager_ManualTrigger_Call {
|
||||||
|
return &MockTriggerManager_ManualTrigger_Call{Call: _e.mock.On("ManualTrigger", ctx, collectionID, clusteringCompaction, l0Compaction)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_c *MockTriggerManager_ManualTrigger_Call) Run(run func(ctx context.Context, collectionID int64, clusteringCompaction bool)) *MockTriggerManager_ManualTrigger_Call {
|
func (_c *MockTriggerManager_ManualTrigger_Call) Run(run func(ctx context.Context, collectionID int64, clusteringCompaction bool, l0Compaction bool)) *MockTriggerManager_ManualTrigger_Call {
|
||||||
_c.Call.Run(func(args mock.Arguments) {
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
run(args[0].(context.Context), args[1].(int64), args[2].(bool))
|
run(args[0].(context.Context), args[1].(int64), args[2].(bool), args[3].(bool))
|
||||||
})
|
})
|
||||||
return _c
|
return _c
|
||||||
}
|
}
|
||||||
@ -172,7 +173,7 @@ func (_c *MockTriggerManager_ManualTrigger_Call) Return(_a0 int64, _a1 error) *M
|
|||||||
return _c
|
return _c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_c *MockTriggerManager_ManualTrigger_Call) RunAndReturn(run func(context.Context, int64, bool) (int64, error)) *MockTriggerManager_ManualTrigger_Call {
|
func (_c *MockTriggerManager_ManualTrigger_Call) RunAndReturn(run func(context.Context, int64, bool, bool) (int64, error)) *MockTriggerManager_ManualTrigger_Call {
|
||||||
_c.Call.Return(run)
|
_c.Call.Return(run)
|
||||||
return _c
|
return _c
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1706,6 +1706,25 @@ func TestManualCompaction(t *testing.T) {
|
|||||||
assert.Equal(t, commonpb.ErrorCode_Success, resp.GetStatus().GetErrorCode())
|
assert.Equal(t, commonpb.ErrorCode_Success, resp.GetStatus().GetErrorCode())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("test manual l0 compaction successfully", func(t *testing.T) {
|
||||||
|
svr := &Server{allocator: allocator.NewMockAllocator(t)}
|
||||||
|
svr.stateCode.Store(commonpb.StateCode_Healthy)
|
||||||
|
mockTriggerManager := NewMockTriggerManager(t)
|
||||||
|
svr.compactionTriggerManager = mockTriggerManager
|
||||||
|
mockTriggerManager.EXPECT().ManualTrigger(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(1, nil)
|
||||||
|
|
||||||
|
mockHandler := NewMockCompactionInspector(t)
|
||||||
|
mockHandler.EXPECT().getCompactionTasksNumBySignalID(mock.Anything).Return(1)
|
||||||
|
svr.compactionInspector = mockHandler
|
||||||
|
resp, err := svr.ManualCompaction(context.TODO(), &milvuspb.ManualCompactionRequest{
|
||||||
|
CollectionID: 1,
|
||||||
|
Timetravel: 1,
|
||||||
|
L0Compaction: true,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, commonpb.ErrorCode_Success, resp.GetStatus().GetErrorCode())
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("test manual compaction failure", func(t *testing.T) {
|
t.Run("test manual compaction failure", func(t *testing.T) {
|
||||||
svr := &Server{allocator: allocator.NewMockAllocator(t)}
|
svr := &Server{allocator: allocator.NewMockAllocator(t)}
|
||||||
svr.stateCode.Store(commonpb.StateCode_Healthy)
|
svr.stateCode.Store(commonpb.StateCode_Healthy)
|
||||||
|
|||||||
@ -1346,8 +1346,8 @@ func (s *Server) ManualCompaction(ctx context.Context, req *milvuspb.ManualCompa
|
|||||||
|
|
||||||
var id int64
|
var id int64
|
||||||
var err error
|
var err error
|
||||||
if req.MajorCompaction {
|
if req.GetMajorCompaction() || req.GetL0Compaction() {
|
||||||
id, err = s.compactionTriggerManager.ManualTrigger(ctx, req.CollectionID, req.GetMajorCompaction())
|
id, err = s.compactionTriggerManager.ManualTrigger(ctx, req.CollectionID, req.GetMajorCompaction(), req.GetL0Compaction())
|
||||||
} else {
|
} else {
|
||||||
id, err = s.compactionTrigger.TriggerCompaction(ctx, NewCompactionSignal().
|
id, err = s.compactionTrigger.TriggerCompaction(ctx, NewCompactionSignal().
|
||||||
WithIsForce(true).
|
WithIsForce(true).
|
||||||
@ -1372,7 +1372,8 @@ func (s *Server) ManualCompaction(ctx context.Context, req *milvuspb.ManualCompa
|
|||||||
resp.CompactionPlanCount = int32(taskCnt)
|
resp.CompactionPlanCount = int32(taskCnt)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("success to trigger manual compaction", zap.Bool("isMajor", req.GetMajorCompaction()), zap.Int64("compactionID", id), zap.Int("taskNum", taskCnt))
|
log.Info("success to trigger manual compaction", zap.Bool("isL0Compaction", req.GetL0Compaction()),
|
||||||
|
zap.Bool("isMajorCompaction", req.GetMajorCompaction()), zap.Int64("compactionID", id), zap.Int("taskNum", taskCnt))
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ require (
|
|||||||
github.com/jolestar/go-commons-pool/v2 v2.1.2
|
github.com/jolestar/go-commons-pool/v2 v2.1.2
|
||||||
github.com/json-iterator/go v1.1.12
|
github.com/json-iterator/go v1.1.12
|
||||||
github.com/klauspost/compress v1.17.9
|
github.com/klauspost/compress v1.17.9
|
||||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250911093549-4cc2bace3f8c
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.3-0.20250918113553-d15826602cc9
|
||||||
github.com/minio/minio-go/v7 v7.0.73
|
github.com/minio/minio-go/v7 v7.0.73
|
||||||
github.com/panjf2000/ants/v2 v2.11.3
|
github.com/panjf2000/ants/v2 v2.11.3
|
||||||
github.com/prometheus/client_golang v1.20.5
|
github.com/prometheus/client_golang v1.20.5
|
||||||
|
|||||||
@ -599,6 +599,8 @@ github.com/milvus-io/gorocksdb v0.0.0-20220624081344-8c5f4212846b h1:TfeY0NxYxZz
|
|||||||
github.com/milvus-io/gorocksdb v0.0.0-20220624081344-8c5f4212846b/go.mod h1:iwW+9cWfIzzDseEBCCeDSN5SD16Tidvy8cwQ7ZY8Qj4=
|
github.com/milvus-io/gorocksdb v0.0.0-20220624081344-8c5f4212846b/go.mod h1:iwW+9cWfIzzDseEBCCeDSN5SD16Tidvy8cwQ7ZY8Qj4=
|
||||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250911093549-4cc2bace3f8c h1:B7zmZ30lWHE4wNjT/g2NPe3q0gcUtw7cA5shMtWAmDc=
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250911093549-4cc2bace3f8c h1:B7zmZ30lWHE4wNjT/g2NPe3q0gcUtw7cA5shMtWAmDc=
|
||||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250911093549-4cc2bace3f8c/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs=
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250911093549-4cc2bace3f8c/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs=
|
||||||
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.3-0.20250918113553-d15826602cc9 h1:7ojrhnBHitGaqebExGP00x0wDTioMgPniEBmNdFPiDI=
|
||||||
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.3-0.20250918113553-d15826602cc9/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs=
|
||||||
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||||
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||||
github.com/minio/minio-go/v7 v7.0.73 h1:qr2vi96Qm7kZ4v7LLebjte+MQh621fFWnv93p12htEo=
|
github.com/minio/minio-go/v7 v7.0.73 h1:qr2vi96Qm7kZ4v7LLebjte+MQh621fFWnv93p12htEo=
|
||||||
|
|||||||
@ -51,7 +51,7 @@ require (
|
|||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250911093549-4cc2bace3f8c // indirect
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.3-0.20250918113553-d15826602cc9 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/opencontainers/runtime-spec v1.0.2 // indirect
|
github.com/opencontainers/runtime-spec v1.0.2 // indirect
|
||||||
|
|||||||
@ -320,6 +320,8 @@ github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/le
|
|||||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250911093549-4cc2bace3f8c h1:B7zmZ30lWHE4wNjT/g2NPe3q0gcUtw7cA5shMtWAmDc=
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250911093549-4cc2bace3f8c h1:B7zmZ30lWHE4wNjT/g2NPe3q0gcUtw7cA5shMtWAmDc=
|
||||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250911093549-4cc2bace3f8c/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs=
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250911093549-4cc2bace3f8c/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs=
|
||||||
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.3-0.20250918113553-d15826602cc9 h1:7ojrhnBHitGaqebExGP00x0wDTioMgPniEBmNdFPiDI=
|
||||||
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.3-0.20250918113553-d15826602cc9/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs=
|
||||||
github.com/milvus-io/milvus/pkg/v2 v2.0.0-20250319085209-5a6b4e56d59e h1:VCr43pG4efacDbM4au70fh8/5hNTftoWzm1iEumvDWM=
|
github.com/milvus-io/milvus/pkg/v2 v2.0.0-20250319085209-5a6b4e56d59e h1:VCr43pG4efacDbM4au70fh8/5hNTftoWzm1iEumvDWM=
|
||||||
github.com/milvus-io/milvus/pkg/v2 v2.0.0-20250319085209-5a6b4e56d59e/go.mod h1:37AWzxVs2NS4QUJrkcbeLUwi+4Av0h5mEdjLI62EANU=
|
github.com/milvus-io/milvus/pkg/v2 v2.0.0-20250319085209-5a6b4e56d59e/go.mod h1:37AWzxVs2NS4QUJrkcbeLUwi+4Av0h5mEdjLI62EANU=
|
||||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user