2021-01-29 09:27:26 +08:00
|
|
|
package proxynode
|
2020-11-19 21:02:31 +08:00
|
|
|
|
|
|
|
import (
|
2020-11-26 16:01:31 +08:00
|
|
|
"container/list"
|
2020-11-19 21:02:31 +08:00
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"time"
|
|
|
|
|
2021-03-05 10:15:27 +08:00
|
|
|
"errors"
|
|
|
|
|
2021-01-29 09:27:26 +08:00
|
|
|
"github.com/zilliztech/milvus-distributed/internal/allocator"
|
|
|
|
|
2021-01-18 19:32:08 +08:00
|
|
|
"github.com/zilliztech/milvus-distributed/internal/proto/commonpb"
|
|
|
|
"github.com/zilliztech/milvus-distributed/internal/proto/datapb"
|
|
|
|
"github.com/zilliztech/milvus-distributed/internal/util/typeutil"
|
2020-11-19 21:02:31 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
SegCountPerRPC = 20000
|
2020-12-24 20:55:40 +08:00
|
|
|
ActiveTimeDuration = 100 //second
|
2020-11-19 21:02:31 +08:00
|
|
|
)
|
|
|
|
|
2021-01-29 09:27:26 +08:00
|
|
|
type Allocator = allocator.Allocator
|
|
|
|
|
|
|
|
type segRequest struct {
|
|
|
|
allocator.BaseRequest
|
2021-01-31 10:15:54 +08:00
|
|
|
count uint32
|
|
|
|
collID UniqueID
|
|
|
|
partitionID UniqueID
|
|
|
|
segInfo map[UniqueID]uint32
|
|
|
|
channelName string
|
|
|
|
timestamp Timestamp
|
2021-01-29 09:27:26 +08:00
|
|
|
}
|
|
|
|
|
2020-12-24 20:55:40 +08:00
|
|
|
type segInfo struct {
|
|
|
|
segID UniqueID
|
|
|
|
count uint32
|
|
|
|
expireTime Timestamp
|
|
|
|
}
|
|
|
|
|
2020-11-19 21:02:31 +08:00
|
|
|
type assignInfo struct {
|
2021-01-18 19:32:08 +08:00
|
|
|
collID UniqueID
|
|
|
|
partitionID UniqueID
|
2021-01-31 10:15:54 +08:00
|
|
|
channelName string
|
2020-12-24 20:55:40 +08:00
|
|
|
segID UniqueID
|
|
|
|
segInfos *list.List
|
|
|
|
segCapacity uint32
|
2020-11-19 21:02:31 +08:00
|
|
|
lastInsertTime time.Time
|
|
|
|
}
|
|
|
|
|
2020-12-24 20:55:40 +08:00
|
|
|
func (info *segInfo) IsExpired(ts Timestamp) bool {
|
|
|
|
return ts > info.expireTime || info.count <= 0
|
2020-12-24 16:53:31 +08:00
|
|
|
}
|
|
|
|
|
2020-12-24 20:55:40 +08:00
|
|
|
func (info *segInfo) Capacity(ts Timestamp) uint32 {
|
|
|
|
if info.IsExpired(ts) {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return info.count
|
|
|
|
}
|
|
|
|
|
|
|
|
func (info *segInfo) Assign(ts Timestamp, count uint32) uint32 {
|
|
|
|
if info.IsExpired(ts) {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
ret := uint32(0)
|
|
|
|
if info.count >= count {
|
|
|
|
info.count -= count
|
|
|
|
ret = count
|
|
|
|
} else {
|
|
|
|
info.count = 0
|
|
|
|
ret = info.count
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
func (info *assignInfo) RemoveExpired(ts Timestamp) {
|
|
|
|
for e := info.segInfos.Front(); e != nil; e = e.Next() {
|
2021-03-04 18:58:16 +08:00
|
|
|
segInfo, ok := e.Value.(*segInfo)
|
|
|
|
if !ok {
|
|
|
|
log.Printf("can not cast to segInfo")
|
|
|
|
continue
|
|
|
|
}
|
2020-12-24 20:55:40 +08:00
|
|
|
if segInfo.IsExpired(ts) {
|
|
|
|
info.segInfos.Remove(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (info *assignInfo) Capacity(ts Timestamp) uint32 {
|
|
|
|
ret := uint32(0)
|
|
|
|
for e := info.segInfos.Front(); e != nil; e = e.Next() {
|
|
|
|
segInfo := e.Value.(*segInfo)
|
|
|
|
ret += segInfo.Capacity(ts)
|
|
|
|
}
|
|
|
|
return ret
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
|
|
|
|
2020-12-24 20:55:40 +08:00
|
|
|
func (info *assignInfo) Assign(ts Timestamp, count uint32) (map[UniqueID]uint32, error) {
|
|
|
|
capacity := info.Capacity(ts)
|
|
|
|
if capacity < count {
|
|
|
|
errMsg := fmt.Sprintf("AssignSegment Failed: capacity:%d is less than count:%d", capacity, count)
|
|
|
|
return nil, errors.New(errMsg)
|
2020-11-26 16:01:31 +08:00
|
|
|
}
|
2020-12-24 20:55:40 +08:00
|
|
|
|
|
|
|
result := make(map[UniqueID]uint32)
|
|
|
|
for e := info.segInfos.Front(); e != nil && count != 0; e = e.Next() {
|
|
|
|
segInfo := e.Value.(*segInfo)
|
|
|
|
cur := segInfo.Assign(ts, count)
|
|
|
|
count -= cur
|
|
|
|
if cur > 0 {
|
|
|
|
result[segInfo.segID] += cur
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (info *assignInfo) IsActive(now time.Time) bool {
|
|
|
|
return now.Sub(info.lastInsertTime) <= ActiveTimeDuration*time.Second
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
type SegIDAssigner struct {
|
|
|
|
Allocator
|
2021-01-31 10:15:54 +08:00
|
|
|
assignInfos map[UniqueID]*list.List // collectionID -> *list.List
|
2021-01-18 19:32:08 +08:00
|
|
|
segReqs []*datapb.SegIDRequest
|
2020-12-24 20:55:40 +08:00
|
|
|
getTickFunc func() Timestamp
|
|
|
|
PeerID UniqueID
|
2021-01-29 09:27:26 +08:00
|
|
|
|
|
|
|
serviceClient DataServiceClient
|
|
|
|
countPerRPC uint32
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
|
|
|
|
2021-01-29 09:27:26 +08:00
|
|
|
func NewSegIDAssigner(ctx context.Context, client DataServiceClient, getTickFunc func() Timestamp) (*SegIDAssigner, error) {
|
2020-11-19 21:02:31 +08:00
|
|
|
ctx1, cancel := context.WithCancel(ctx)
|
|
|
|
sa := &SegIDAssigner{
|
2021-01-29 09:27:26 +08:00
|
|
|
Allocator: Allocator{
|
|
|
|
Ctx: ctx1,
|
|
|
|
CancelFunc: cancel,
|
2020-11-19 21:02:31 +08:00
|
|
|
},
|
2021-01-29 09:27:26 +08:00
|
|
|
countPerRPC: SegCountPerRPC,
|
|
|
|
serviceClient: client,
|
2021-01-31 10:15:54 +08:00
|
|
|
assignInfos: make(map[UniqueID]*list.List),
|
2021-01-29 09:27:26 +08:00
|
|
|
getTickFunc: getTickFunc,
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
2021-01-29 09:27:26 +08:00
|
|
|
sa.TChan = &allocator.Ticker{
|
|
|
|
UpdateInterval: time.Second,
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
2021-01-29 09:27:26 +08:00
|
|
|
sa.Allocator.SyncFunc = sa.syncSegments
|
|
|
|
sa.Allocator.ProcessFunc = sa.processFunc
|
|
|
|
sa.Allocator.CheckSyncFunc = sa.checkSyncFunc
|
|
|
|
sa.Allocator.PickCanDoFunc = sa.pickCanDoFunc
|
|
|
|
sa.Init()
|
2020-11-19 21:02:31 +08:00
|
|
|
return sa, nil
|
|
|
|
}
|
|
|
|
|
2021-01-29 09:27:26 +08:00
|
|
|
func (sa *SegIDAssigner) SetServiceClient(client DataServiceClient) {
|
|
|
|
sa.serviceClient = client
|
|
|
|
}
|
|
|
|
|
2020-11-19 21:02:31 +08:00
|
|
|
func (sa *SegIDAssigner) collectExpired() {
|
2020-12-24 20:55:40 +08:00
|
|
|
ts := sa.getTickFunc()
|
2020-11-26 16:01:31 +08:00
|
|
|
for _, info := range sa.assignInfos {
|
|
|
|
for e := info.Front(); e != nil; e = e.Next() {
|
|
|
|
assign := e.Value.(*assignInfo)
|
2020-12-24 20:55:40 +08:00
|
|
|
assign.RemoveExpired(ts)
|
|
|
|
if assign.Capacity(ts) == 0 {
|
|
|
|
info.Remove(e)
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-24 20:55:40 +08:00
|
|
|
func (sa *SegIDAssigner) pickCanDoFunc() {
|
2021-01-29 09:27:26 +08:00
|
|
|
if sa.ToDoReqs == nil {
|
2020-11-19 21:02:31 +08:00
|
|
|
return
|
|
|
|
}
|
2021-01-31 10:15:54 +08:00
|
|
|
records := make(map[UniqueID]map[UniqueID]map[string]uint32)
|
2021-01-29 09:27:26 +08:00
|
|
|
newTodoReqs := sa.ToDoReqs[0:0]
|
|
|
|
for _, req := range sa.ToDoReqs {
|
2020-11-19 21:02:31 +08:00
|
|
|
segRequest := req.(*segRequest)
|
2021-01-31 10:15:54 +08:00
|
|
|
collID := segRequest.collID
|
|
|
|
partitionID := segRequest.partitionID
|
|
|
|
channelName := segRequest.channelName
|
2020-12-24 20:55:40 +08:00
|
|
|
|
2021-01-31 10:15:54 +08:00
|
|
|
if _, ok := records[collID]; !ok {
|
|
|
|
records[collID] = make(map[UniqueID]map[string]uint32)
|
2020-12-24 20:55:40 +08:00
|
|
|
}
|
2021-01-31 10:15:54 +08:00
|
|
|
if _, ok := records[collID][partitionID]; !ok {
|
|
|
|
records[collID][partitionID] = make(map[string]uint32)
|
2020-12-24 20:55:40 +08:00
|
|
|
}
|
|
|
|
|
2021-01-31 10:15:54 +08:00
|
|
|
if _, ok := records[collID][partitionID][channelName]; !ok {
|
|
|
|
records[collID][partitionID][channelName] = 0
|
2020-12-24 20:55:40 +08:00
|
|
|
}
|
|
|
|
|
2021-01-31 10:15:54 +08:00
|
|
|
records[collID][partitionID][channelName] += segRequest.count
|
2021-03-04 18:58:16 +08:00
|
|
|
assign, err := sa.getAssign(segRequest.collID, segRequest.partitionID, segRequest.channelName)
|
|
|
|
if err != nil || assign.Capacity(segRequest.timestamp) < records[collID][partitionID][channelName] {
|
2021-01-18 19:32:08 +08:00
|
|
|
sa.segReqs = append(sa.segReqs, &datapb.SegIDRequest{
|
2021-01-31 10:15:54 +08:00
|
|
|
ChannelName: channelName,
|
|
|
|
Count: segRequest.count,
|
|
|
|
CollectionID: collID,
|
|
|
|
PartitionID: partitionID,
|
2020-11-19 21:02:31 +08:00
|
|
|
})
|
2020-12-24 20:55:40 +08:00
|
|
|
newTodoReqs = append(newTodoReqs, req)
|
|
|
|
} else {
|
2021-01-29 09:27:26 +08:00
|
|
|
sa.CanDoReqs = append(sa.CanDoReqs, req)
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
|
|
|
}
|
2021-01-29 09:27:26 +08:00
|
|
|
sa.ToDoReqs = newTodoReqs
|
2020-11-26 16:01:31 +08:00
|
|
|
}
|
|
|
|
|
2021-03-04 18:58:16 +08:00
|
|
|
func (sa *SegIDAssigner) getAssign(collID UniqueID, partitionID UniqueID, channelName string) (*assignInfo, error) {
|
2021-01-31 10:15:54 +08:00
|
|
|
assignInfos, ok := sa.assignInfos[collID]
|
2020-11-19 21:02:31 +08:00
|
|
|
if !ok {
|
2021-03-04 18:58:16 +08:00
|
|
|
return nil, fmt.Errorf("can not find collection %d", collID)
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
2020-11-26 16:01:31 +08:00
|
|
|
|
|
|
|
for e := assignInfos.Front(); e != nil; e = e.Next() {
|
|
|
|
info := e.Value.(*assignInfo)
|
2021-01-31 10:15:54 +08:00
|
|
|
if info.partitionID != partitionID || info.channelName != channelName {
|
2020-11-19 21:02:31 +08:00
|
|
|
continue
|
|
|
|
}
|
2021-03-04 18:58:16 +08:00
|
|
|
return info, nil
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
2021-03-04 18:58:16 +08:00
|
|
|
return nil, fmt.Errorf("can not find assign info with collID %d, partitionID %d, channelName %s",
|
|
|
|
collID, partitionID, channelName)
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
|
|
|
|
2020-12-24 20:55:40 +08:00
|
|
|
func (sa *SegIDAssigner) checkSyncFunc(timeout bool) bool {
|
|
|
|
sa.collectExpired()
|
|
|
|
return timeout || len(sa.segReqs) != 0
|
|
|
|
}
|
|
|
|
|
2021-01-18 19:32:08 +08:00
|
|
|
func (sa *SegIDAssigner) checkSegReqEqual(req1, req2 *datapb.SegIDRequest) bool {
|
2020-12-24 20:55:40 +08:00
|
|
|
if req1 == nil || req2 == nil {
|
|
|
|
return false
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
|
|
|
|
2020-12-24 20:55:40 +08:00
|
|
|
if req1 == req2 {
|
|
|
|
return true
|
|
|
|
}
|
2021-01-31 10:15:54 +08:00
|
|
|
return req1.CollectionID == req2.CollectionID && req1.PartitionID == req2.PartitionID && req1.ChannelName == req2.ChannelName
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
|
|
|
|
2020-12-24 20:55:40 +08:00
|
|
|
func (sa *SegIDAssigner) reduceSegReqs() {
|
|
|
|
|
2020-11-19 21:02:31 +08:00
|
|
|
if len(sa.segReqs) == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-01-18 19:32:08 +08:00
|
|
|
var newSegReqs []*datapb.SegIDRequest
|
2020-12-24 20:55:40 +08:00
|
|
|
for _, req1 := range sa.segReqs {
|
2021-01-18 19:32:08 +08:00
|
|
|
var req2 *datapb.SegIDRequest
|
2020-12-24 20:55:40 +08:00
|
|
|
for _, req3 := range newSegReqs {
|
|
|
|
if sa.checkSegReqEqual(req1, req3) {
|
|
|
|
req2 = req3
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if req2 == nil { // not found
|
|
|
|
newSegReqs = append(newSegReqs, req1)
|
|
|
|
} else {
|
|
|
|
req2.Count += req1.Count
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, req := range newSegReqs {
|
|
|
|
if req.Count == 0 {
|
|
|
|
req.Count = sa.countPerRPC
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sa.segReqs = newSegReqs
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sa *SegIDAssigner) syncSegments() bool {
|
|
|
|
if len(sa.segReqs) == 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
sa.reduceSegReqs()
|
2021-02-26 17:44:24 +08:00
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
2020-11-19 21:02:31 +08:00
|
|
|
defer cancel()
|
2021-01-18 19:32:08 +08:00
|
|
|
req := &datapb.AssignSegIDRequest{
|
|
|
|
NodeID: sa.PeerID,
|
2021-01-23 18:56:08 +08:00
|
|
|
PeerRole: typeutil.ProxyNodeRole,
|
2021-01-18 19:32:08 +08:00
|
|
|
SegIDRequests: sa.segReqs,
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
|
|
|
|
2021-01-18 19:32:08 +08:00
|
|
|
sa.segReqs = []*datapb.SegIDRequest{}
|
2021-02-26 17:44:24 +08:00
|
|
|
resp, err := sa.serviceClient.AssignSegmentID(ctx, req)
|
2020-11-19 21:02:31 +08:00
|
|
|
|
2020-12-24 20:55:40 +08:00
|
|
|
if err != nil {
|
|
|
|
log.Println("GRPC AssignSegmentID Failed", resp, err)
|
|
|
|
return false
|
2020-12-24 16:19:42 +08:00
|
|
|
}
|
|
|
|
|
2020-12-24 20:55:40 +08:00
|
|
|
now := time.Now()
|
|
|
|
success := false
|
2021-01-18 19:32:08 +08:00
|
|
|
for _, info := range resp.SegIDAssignments {
|
2020-12-24 20:55:40 +08:00
|
|
|
if info.Status.GetErrorCode() != commonpb.ErrorCode_SUCCESS {
|
|
|
|
log.Println("SyncSegment Error:", info.Status.Reason)
|
|
|
|
continue
|
|
|
|
}
|
2021-03-04 18:58:16 +08:00
|
|
|
assign, err := sa.getAssign(info.CollectionID, info.PartitionID, info.ChannelName)
|
2020-12-24 20:55:40 +08:00
|
|
|
segInfo := &segInfo{
|
|
|
|
segID: info.SegID,
|
|
|
|
count: info.Count,
|
|
|
|
expireTime: info.ExpireTime,
|
|
|
|
}
|
2021-03-04 18:58:16 +08:00
|
|
|
if err != nil {
|
2021-01-31 10:15:54 +08:00
|
|
|
colInfos, ok := sa.assignInfos[info.CollectionID]
|
2020-11-26 16:01:31 +08:00
|
|
|
if !ok {
|
|
|
|
colInfos = list.New()
|
|
|
|
}
|
2020-12-24 20:55:40 +08:00
|
|
|
segInfos := list.New()
|
|
|
|
|
|
|
|
segInfos.PushBack(segInfo)
|
|
|
|
assign = &assignInfo{
|
2021-01-31 10:15:54 +08:00
|
|
|
collID: info.CollectionID,
|
|
|
|
partitionID: info.PartitionID,
|
|
|
|
channelName: info.ChannelName,
|
|
|
|
segInfos: segInfos,
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
2020-12-24 20:55:40 +08:00
|
|
|
colInfos.PushBack(assign)
|
2021-01-31 10:15:54 +08:00
|
|
|
sa.assignInfos[info.CollectionID] = colInfos
|
2020-11-19 21:02:31 +08:00
|
|
|
} else {
|
2020-12-24 20:55:40 +08:00
|
|
|
assign.segInfos.PushBack(segInfo)
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
2020-12-24 20:55:40 +08:00
|
|
|
assign.lastInsertTime = now
|
|
|
|
success = true
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
2020-12-24 20:55:40 +08:00
|
|
|
return success
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
|
|
|
|
2021-01-29 09:27:26 +08:00
|
|
|
func (sa *SegIDAssigner) processFunc(req allocator.Request) error {
|
2020-11-19 21:02:31 +08:00
|
|
|
segRequest := req.(*segRequest)
|
2021-03-04 18:58:16 +08:00
|
|
|
assign, err := sa.getAssign(segRequest.collID, segRequest.partitionID, segRequest.channelName)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
2020-12-24 20:55:40 +08:00
|
|
|
result, err := assign.Assign(segRequest.timestamp, segRequest.count)
|
|
|
|
segRequest.segInfo = result
|
|
|
|
return err
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
|
|
|
|
2021-01-31 10:15:54 +08:00
|
|
|
func (sa *SegIDAssigner) GetSegmentID(collID UniqueID, partitionID UniqueID, channelName string, count uint32, ts Timestamp) (map[UniqueID]uint32, error) {
|
2020-11-19 21:02:31 +08:00
|
|
|
req := &segRequest{
|
2021-01-31 10:15:54 +08:00
|
|
|
BaseRequest: allocator.BaseRequest{Done: make(chan error), Valid: false},
|
|
|
|
collID: collID,
|
|
|
|
partitionID: partitionID,
|
|
|
|
channelName: channelName,
|
|
|
|
count: count,
|
|
|
|
timestamp: ts,
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
2021-01-29 09:27:26 +08:00
|
|
|
sa.Reqs <- req
|
2020-11-19 21:02:31 +08:00
|
|
|
req.Wait()
|
|
|
|
|
|
|
|
if !req.IsValid() {
|
2020-11-26 16:01:31 +08:00
|
|
|
return nil, errors.New("GetSegmentID Failed")
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|
2020-11-26 16:01:31 +08:00
|
|
|
return req.segInfo, nil
|
2020-11-19 21:02:31 +08:00
|
|
|
}
|