mirror of
https://gitee.com/milvus-io/milvus.git
synced 2025-12-08 01:58:34 +08:00
fix: data duplicated when msgdispatcher make splitting (#42827)
issue: #41570 Signed-off-by: chyezh <chyezh@outlook.com>
This commit is contained in:
parent
9865d672f7
commit
2fd8f910b0
@ -415,7 +415,6 @@ func (gc *garbageCollector) checkDroppedSegmentGC(segment *SegmentInfo,
|
|||||||
|
|
||||||
// recycleDroppedSegments scans all segments and remove those dropped segments from meta and oss.
|
// recycleDroppedSegments scans all segments and remove those dropped segments from meta and oss.
|
||||||
func (gc *garbageCollector) recycleDroppedSegments(ctx context.Context) {
|
func (gc *garbageCollector) recycleDroppedSegments(ctx context.Context) {
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
log := log.With(zap.String("gcName", "recycleDroppedSegments"), zap.Time("startAt", start))
|
log := log.With(zap.String("gcName", "recycleDroppedSegments"), zap.Time("startAt", start))
|
||||||
log.Info("start clear dropped segments...")
|
log.Info("start clear dropped segments...")
|
||||||
|
|||||||
@ -22,6 +22,7 @@ package datanode
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|||||||
@ -81,7 +81,7 @@ func TestDispatcher(t *testing.T) {
|
|||||||
target := newTarget(&StreamConfig{
|
target := newTarget(&StreamConfig{
|
||||||
VChannel: vchannel,
|
VChannel: vchannel,
|
||||||
Pos: pos,
|
Pos: pos,
|
||||||
})
|
}, false)
|
||||||
target.ch = ch
|
target.ch = ch
|
||||||
return target
|
return target
|
||||||
}
|
}
|
||||||
@ -104,7 +104,7 @@ func TestDispatcher(t *testing.T) {
|
|||||||
t.Run("test concurrent send and close", func(t *testing.T) {
|
t.Run("test concurrent send and close", func(t *testing.T) {
|
||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
output := make(chan *msgstream.MsgPack, 1024)
|
output := make(chan *msgstream.MsgPack, 1024)
|
||||||
target := newTarget(&StreamConfig{VChannel: "mock_vchannel_0"})
|
target := newTarget(&StreamConfig{VChannel: "mock_vchannel_0"}, false)
|
||||||
target.ch = output
|
target.ch = output
|
||||||
assert.Equal(t, cap(output), cap(target.ch))
|
assert.Equal(t, cap(output), cap(target.ch))
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
@ -145,11 +145,11 @@ func TestGroupMessage(t *testing.T) {
|
|||||||
d, err := NewDispatcher(context.Background(), newMockFactory(), time.Now().UnixNano(), "mock_pchannel_0",
|
d, err := NewDispatcher(context.Background(), newMockFactory(), time.Now().UnixNano(), "mock_pchannel_0",
|
||||||
nil, common.SubscriptionPositionEarliest, false, 0, false)
|
nil, common.SubscriptionPositionEarliest, false, 0, false)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
d.AddTarget(newTarget(&StreamConfig{VChannel: "mock_pchannel_0_1v0"}))
|
d.AddTarget(newTarget(&StreamConfig{VChannel: "mock_pchannel_0_1v0"}, false))
|
||||||
d.AddTarget(newTarget(&StreamConfig{
|
d.AddTarget(newTarget(&StreamConfig{
|
||||||
VChannel: "mock_pchannel_0_2v0",
|
VChannel: "mock_pchannel_0_2v0",
|
||||||
ReplicateConfig: msgstream.GetReplicateConfig("local-test", "foo", "coo"),
|
ReplicateConfig: msgstream.GetReplicateConfig("local-test", "foo", "coo"),
|
||||||
}))
|
}, false))
|
||||||
{
|
{
|
||||||
// no replicate msg
|
// no replicate msg
|
||||||
packs := d.groupAndParseMsgs(msgstream.BuildConsumeMsgPack(&MsgPack{
|
packs := d.groupAndParseMsgs(msgstream.BuildConsumeMsgPack(&MsgPack{
|
||||||
|
|||||||
@ -84,7 +84,7 @@ func NewDispatcherManager(pchannel string, role string, nodeID int64, factory ms
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *dispatcherManager) Add(ctx context.Context, streamConfig *StreamConfig) (<-chan *MsgPack, error) {
|
func (c *dispatcherManager) Add(ctx context.Context, streamConfig *StreamConfig) (<-chan *MsgPack, error) {
|
||||||
t := newTarget(streamConfig)
|
t := newTarget(streamConfig, c.includeSkipWhenSplit)
|
||||||
if _, ok := c.registeredTargets.GetOrInsert(t.vchannel, t); ok {
|
if _, ok := c.registeredTargets.GetOrInsert(t.vchannel, t); ok {
|
||||||
return nil, fmt.Errorf("vchannel %s already exists in the dispatcher", t.vchannel)
|
return nil, fmt.Errorf("vchannel %s already exists in the dispatcher", t.vchannel)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,11 +30,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type target struct {
|
type target struct {
|
||||||
vchannel string
|
vchannel string
|
||||||
ch chan *MsgPack
|
ch chan *MsgPack
|
||||||
subPos SubPos
|
subPos SubPos
|
||||||
pos *Pos
|
pos *Pos
|
||||||
isLagged bool
|
filterSameTimeTick bool
|
||||||
|
latestTimeTick uint64
|
||||||
|
isLagged bool
|
||||||
|
|
||||||
closeMu sync.Mutex
|
closeMu sync.Mutex
|
||||||
closeOnce sync.Once
|
closeOnce sync.Once
|
||||||
@ -46,18 +48,20 @@ type target struct {
|
|||||||
cancelCh lifetime.SafeChan
|
cancelCh lifetime.SafeChan
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTarget(streamConfig *StreamConfig) *target {
|
func newTarget(streamConfig *StreamConfig, filterSameTimeTick bool) *target {
|
||||||
replicateConfig := streamConfig.ReplicateConfig
|
replicateConfig := streamConfig.ReplicateConfig
|
||||||
maxTolerantLag := paramtable.Get().MQCfg.MaxTolerantLag.GetAsDuration(time.Second)
|
maxTolerantLag := paramtable.Get().MQCfg.MaxTolerantLag.GetAsDuration(time.Second)
|
||||||
t := &target{
|
t := &target{
|
||||||
vchannel: streamConfig.VChannel,
|
vchannel: streamConfig.VChannel,
|
||||||
ch: make(chan *MsgPack, paramtable.Get().MQCfg.TargetBufSize.GetAsInt()),
|
ch: make(chan *MsgPack, paramtable.Get().MQCfg.TargetBufSize.GetAsInt()),
|
||||||
subPos: streamConfig.SubPos,
|
subPos: streamConfig.SubPos,
|
||||||
pos: streamConfig.Pos,
|
pos: streamConfig.Pos,
|
||||||
cancelCh: lifetime.NewSafeChan(),
|
filterSameTimeTick: filterSameTimeTick,
|
||||||
maxLag: maxTolerantLag,
|
latestTimeTick: 0,
|
||||||
timer: time.NewTimer(maxTolerantLag),
|
cancelCh: lifetime.NewSafeChan(),
|
||||||
replicateConfig: replicateConfig,
|
maxLag: maxTolerantLag,
|
||||||
|
timer: time.NewTimer(maxTolerantLag),
|
||||||
|
replicateConfig: replicateConfig,
|
||||||
}
|
}
|
||||||
t.closed = false
|
t.closed = false
|
||||||
if replicateConfig != nil {
|
if replicateConfig != nil {
|
||||||
@ -87,6 +91,23 @@ func (t *target) send(pack *MsgPack) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if t.filterSameTimeTick {
|
||||||
|
if pack.EndPositions[0].GetTimestamp() <= t.latestTimeTick {
|
||||||
|
if len(pack.Msgs) > 0 {
|
||||||
|
// only filter out the msg that is only timetick message,
|
||||||
|
// So it's a unexpected behavior if the msgs is not empty
|
||||||
|
log.Warn("some data lost when time tick filtering",
|
||||||
|
zap.String("vchannel", t.vchannel),
|
||||||
|
zap.Uint64("latestTimeTick", t.latestTimeTick),
|
||||||
|
zap.Uint64("packEndTs", pack.EndPositions[0].GetTimestamp()),
|
||||||
|
zap.Int("msgCount", len(pack.Msgs)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// filter out the msg that is already sent with the same timetick.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !t.timer.Stop() {
|
if !t.timer.Stop() {
|
||||||
select {
|
select {
|
||||||
case <-t.timer.C:
|
case <-t.timer.C:
|
||||||
@ -100,8 +121,11 @@ func (t *target) send(pack *MsgPack) error {
|
|||||||
return nil
|
return nil
|
||||||
case <-t.timer.C:
|
case <-t.timer.C:
|
||||||
t.isLagged = true
|
t.isLagged = true
|
||||||
return fmt.Errorf("send target timeout, vchannel=%s, timeout=%s, beginTs=%d, endTs=%d", t.vchannel, t.maxLag, pack.BeginTs, pack.EndTs)
|
return fmt.Errorf("send target timeout, vchannel=%s, timeout=%s, beginTs=%d, endTs=%d, latestTimeTick=%d", t.vchannel, t.maxLag, pack.BeginTs, pack.EndTs, t.latestTimeTick)
|
||||||
case t.ch <- pack:
|
case t.ch <- pack:
|
||||||
|
if len(pack.EndPositions) > 0 {
|
||||||
|
t.latestTimeTick = pack.EndPositions[0].GetTimestamp()
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ func TestSendTimeout(t *testing.T) {
|
|||||||
target := newTarget(&StreamConfig{
|
target := newTarget(&StreamConfig{
|
||||||
VChannel: "test1",
|
VChannel: "test1",
|
||||||
Pos: &msgpb.MsgPosition{},
|
Pos: &msgpb.MsgPosition{},
|
||||||
})
|
}, false)
|
||||||
|
|
||||||
time.Sleep(paramtable.Get().MQCfg.MaxTolerantLag.GetAsDuration(time.Second))
|
time.Sleep(paramtable.Get().MQCfg.MaxTolerantLag.GetAsDuration(time.Second))
|
||||||
|
|
||||||
@ -31,3 +31,25 @@ func TestSendTimeout(t *testing.T) {
|
|||||||
}
|
}
|
||||||
assert.Equal(t, counter, 0)
|
assert.Equal(t, counter, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSendTimeTickFiltering(t *testing.T) {
|
||||||
|
target := newTarget(&StreamConfig{
|
||||||
|
VChannel: "test1",
|
||||||
|
Pos: &msgpb.MsgPosition{},
|
||||||
|
}, true)
|
||||||
|
target.send(&msgstream.MsgPack{
|
||||||
|
EndPositions: []*msgpb.MsgPosition{
|
||||||
|
{
|
||||||
|
Timestamp: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
target.send(&msgstream.MsgPack{
|
||||||
|
EndPositions: []*msgpb.MsgPosition{
|
||||||
|
{
|
||||||
|
Timestamp: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user