mirror of https://github.com/milvus-io/milvus.git
parent
81d3546b7c
commit
dea0a4e522
|
@ -0,0 +1,34 @@
|
|||
package datanode
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Cache struct {
|
||||
cacheMu sync.RWMutex
|
||||
cacheMap map[UniqueID]bool
|
||||
}
|
||||
|
||||
func newCache() *Cache {
|
||||
return &Cache{
|
||||
cacheMap: make(map[UniqueID]bool),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cache) checkIfCached(key UniqueID) bool {
|
||||
c.cacheMu.Lock()
|
||||
defer c.cacheMu.Unlock()
|
||||
|
||||
if _, ok := c.cacheMap[key]; !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *Cache) Cache(segID UniqueID) {
|
||||
c.cacheMu.Lock()
|
||||
defer c.cacheMu.Unlock()
|
||||
|
||||
c.cacheMap[segID] = true
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package datanode
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSegmentCache(t *testing.T) {
|
||||
segCache := newCache()
|
||||
|
||||
assert.False(t, segCache.checkIfCached(0))
|
||||
|
||||
segCache.Cache(UniqueID(0))
|
||||
assert.True(t, segCache.checkIfCached(0))
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
// Package datanode implements data persistence logic.
|
||||
//
|
||||
// Data node persists definition language (ddl) strings and insert logs into persistent storage like minIO/S3.
|
||||
// Data node persists insert logs into persistent storage like minIO/S3.
|
||||
package datanode
|
||||
|
||||
import (
|
||||
|
@ -68,6 +68,7 @@ type DataNode struct {
|
|||
vchan2SyncService map[string]*dataSyncService // vchannel name
|
||||
vchan2FlushCh map[string]chan<- *flushMsg // vchannel name
|
||||
clearSignal chan UniqueID // collection ID
|
||||
segmentCache *Cache
|
||||
|
||||
masterService types.MasterService
|
||||
dataService types.DataService
|
||||
|
@ -92,6 +93,7 @@ func NewDataNode(ctx context.Context, factory msgstream.Factory) *DataNode {
|
|||
masterService: nil,
|
||||
dataService: nil,
|
||||
msFactory: factory,
|
||||
segmentCache: newCache(),
|
||||
|
||||
vchan2SyncService: make(map[string]*dataSyncService),
|
||||
vchan2FlushCh: make(map[string]chan<- *flushMsg),
|
||||
|
@ -200,16 +202,13 @@ func (node *DataNode) ReleaseDataSyncService(vchanName string) {
|
|||
log.Info("Release flowgraph resources begin", zap.String("Vchannel", vchanName))
|
||||
|
||||
node.chanMut.Lock()
|
||||
defer node.chanMut.Unlock()
|
||||
if dss, ok := node.vchan2SyncService[vchanName]; ok {
|
||||
dss.close()
|
||||
}
|
||||
|
||||
delete(node.vchan2SyncService, vchanName)
|
||||
node.chanMut.Unlock()
|
||||
|
||||
node.chanMut.Lock()
|
||||
delete(node.vchan2FlushCh, vchanName)
|
||||
node.chanMut.Unlock()
|
||||
|
||||
log.Debug("Release flowgraph resources end", zap.String("Vchannel", vchanName))
|
||||
}
|
||||
|
@ -325,14 +324,14 @@ func (node *DataNode) ReadyToFlush() error {
|
|||
if len(node.vchan2SyncService) == 0 && len(node.vchan2FlushCh) == 0 {
|
||||
// Healthy but Idle
|
||||
msg := "DataNode HEALTHY but IDLE, please try WatchDmChannels to make it work"
|
||||
log.Info(msg)
|
||||
log.Warn(msg)
|
||||
return errors.New(msg)
|
||||
}
|
||||
|
||||
if len(node.vchan2SyncService) != len(node.vchan2FlushCh) {
|
||||
// TODO restart
|
||||
msg := "DataNode HEALTHY but abnormal inside, restarting..."
|
||||
log.Info(msg)
|
||||
log.Warn(msg)
|
||||
return errors.New(msg)
|
||||
}
|
||||
return nil
|
||||
|
@ -365,6 +364,7 @@ func (node *DataNode) FlushSegments(ctx context.Context, req *datapb.FlushSegmen
|
|||
return status, nil
|
||||
}
|
||||
|
||||
numOfFlushingSeg := len(req.SegmentIDs)
|
||||
log.Debug("FlushSegments ...", zap.Int("num", len(req.SegmentIDs)), zap.Int64s("segments", req.SegmentIDs))
|
||||
dmlFlushedCh := make(chan []*datapb.ID2PathList, len(req.SegmentIDs))
|
||||
for _, id := range req.SegmentIDs {
|
||||
|
@ -375,6 +375,15 @@ func (node *DataNode) FlushSegments(ctx context.Context, req *datapb.FlushSegmen
|
|||
return status, errors.New(status.GetReason())
|
||||
}
|
||||
|
||||
if node.segmentCache.checkIfCached(id) {
|
||||
// Segment in flushing or flushed, ignore
|
||||
log.Info("Segment in flushing, ignore it", zap.Int64("ID", id))
|
||||
numOfFlushingSeg--
|
||||
continue
|
||||
}
|
||||
|
||||
node.segmentCache.Cache(id)
|
||||
|
||||
node.chanMut.RLock()
|
||||
flushCh, ok := node.vchan2FlushCh[chanName]
|
||||
node.chanMut.RUnlock()
|
||||
|
@ -394,8 +403,9 @@ func (node *DataNode) FlushSegments(ctx context.Context, req *datapb.FlushSegmen
|
|||
flushCh <- flushmsg
|
||||
|
||||
}
|
||||
|
||||
failedSegments := ""
|
||||
for range req.SegmentIDs {
|
||||
for i := 0; i < numOfFlushingSeg; i++ {
|
||||
msg := <-dmlFlushedCh
|
||||
if len(msg) != 1 {
|
||||
panic("flush size expect to 1")
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
package datanode
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"os"
|
||||
"testing"
|
||||
|
@ -36,12 +37,13 @@ func TestMain(t *testing.M) {
|
|||
}
|
||||
|
||||
func TestDataNode(t *testing.T) {
|
||||
t.Skip()
|
||||
node := newIDLEDataNodeMock()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
node := newIDLEDataNodeMock(ctx)
|
||||
node.Start()
|
||||
|
||||
t.Run("Test WatchDmChannels", func(t *testing.T) {
|
||||
node1 := newIDLEDataNodeMock()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
node1 := newIDLEDataNodeMock(ctx)
|
||||
node1.Start()
|
||||
vchannels := []*datapb.VchannelInfo{}
|
||||
for _, ch := range []string{"datanode-01-test-WatchDmChannel",
|
||||
|
@ -79,6 +81,7 @@ func TestDataNode(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(node1.vchan2SyncService))
|
||||
|
||||
cancel()
|
||||
<-node1.ctx.Done()
|
||||
node1.Stop()
|
||||
})
|
||||
|
@ -90,7 +93,8 @@ func TestDataNode(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("Test NewDataSyncService", func(t *testing.T) {
|
||||
node2 := newIDLEDataNodeMock()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
node2 := newIDLEDataNodeMock(ctx)
|
||||
node2.Start()
|
||||
dmChannelName := "fake-dm-channel-test-NewDataSyncService"
|
||||
|
||||
|
@ -112,11 +116,14 @@ func TestDataNode(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(node2.vchan2FlushCh))
|
||||
assert.Equal(t, 1, len(node2.vchan2SyncService))
|
||||
|
||||
cancel()
|
||||
<-node2.ctx.Done()
|
||||
node2.Stop()
|
||||
})
|
||||
|
||||
t.Run("Test FlushSegments", func(t *testing.T) {
|
||||
t.Skipf("Fix latter")
|
||||
dmChannelName := "fake-dm-channel-test-HEALTHDataNodeMock"
|
||||
|
||||
node1 := newHEALTHDataNodeMock(dmChannelName)
|
||||
|
@ -221,6 +228,7 @@ func TestDataNode(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("Test BackGroundGC", func(t *testing.T) {
|
||||
t.Skipf("Skip for data race")
|
||||
collIDCh := make(chan UniqueID)
|
||||
go node.BackGroundGC(collIDCh)
|
||||
|
||||
|
@ -253,6 +261,7 @@ func TestDataNode(t *testing.T) {
|
|||
assert.Nil(t, s)
|
||||
})
|
||||
|
||||
cancel()
|
||||
<-node.ctx.Done()
|
||||
node.Stop()
|
||||
}
|
||||
|
|
|
@ -611,9 +611,16 @@ func (ibNode *insertBufferNode) Operate(in []flowgraph.Msg) []flowgraph.Msg {
|
|||
return nil
|
||||
}
|
||||
|
||||
func flushSegment(collMeta *etcdpb.CollectionMeta, segID, partitionID, collID UniqueID,
|
||||
insertData *sync.Map, kv kv.BaseKV, flushUnit chan<- segmentFlushUnit, wgFinish *sync.WaitGroup,
|
||||
ibNode *insertBufferNode, idAllocator allocatorInterface) {
|
||||
func flushSegment(
|
||||
collMeta *etcdpb.CollectionMeta,
|
||||
segID, partitionID, collID UniqueID,
|
||||
insertData *sync.Map,
|
||||
kv kv.BaseKV,
|
||||
flushUnit chan<- segmentFlushUnit,
|
||||
wgFinish *sync.WaitGroup,
|
||||
ibNode *insertBufferNode,
|
||||
idAllocator allocatorInterface) {
|
||||
|
||||
if wgFinish != nil {
|
||||
defer wgFinish.Done()
|
||||
}
|
||||
|
|
|
@ -42,20 +42,7 @@ import (
|
|||
const ctxTimeInMillisecond = 5000
|
||||
const debug = false
|
||||
|
||||
func newIDLEDataNodeMock() *DataNode {
|
||||
var ctx context.Context
|
||||
|
||||
if debug {
|
||||
ctx = context.Background()
|
||||
} else {
|
||||
var cancel context.CancelFunc
|
||||
d := time.Now().Add(ctxTimeInMillisecond * time.Millisecond)
|
||||
ctx, cancel = context.WithDeadline(context.Background(), d)
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
cancel()
|
||||
}()
|
||||
}
|
||||
func newIDLEDataNodeMock(ctx context.Context) *DataNode {
|
||||
|
||||
msFactory := msgstream.NewPmsFactory()
|
||||
node := NewDataNode(ctx, msFactory)
|
||||
|
|
Loading…
Reference in New Issue