2021-01-22 14:28:06 +08:00
|
|
|
package queryservice
|
2021-01-15 15:28:54 +08:00
|
|
|
|
2021-01-16 15:31:10 +08:00
|
|
|
import (
|
2021-01-22 14:28:06 +08:00
|
|
|
"context"
|
2021-01-27 09:50:52 +08:00
|
|
|
"fmt"
|
2021-01-26 15:13:20 +08:00
|
|
|
"sort"
|
2021-01-22 14:28:06 +08:00
|
|
|
"strconv"
|
|
|
|
"sync/atomic"
|
|
|
|
|
2021-01-26 15:13:20 +08:00
|
|
|
nodeclient "github.com/zilliztech/milvus-distributed/internal/distributed/querynode/client"
|
2021-01-22 14:28:06 +08:00
|
|
|
"github.com/zilliztech/milvus-distributed/internal/errors"
|
|
|
|
"github.com/zilliztech/milvus-distributed/internal/proto/commonpb"
|
2021-01-26 15:13:20 +08:00
|
|
|
"github.com/zilliztech/milvus-distributed/internal/proto/datapb"
|
2021-01-16 15:31:10 +08:00
|
|
|
"github.com/zilliztech/milvus-distributed/internal/proto/internalpb2"
|
2021-01-26 15:13:20 +08:00
|
|
|
"github.com/zilliztech/milvus-distributed/internal/proto/milvuspb"
|
2021-01-16 15:31:10 +08:00
|
|
|
"github.com/zilliztech/milvus-distributed/internal/proto/querypb"
|
2021-01-22 14:28:06 +08:00
|
|
|
"github.com/zilliztech/milvus-distributed/internal/querynode"
|
2021-01-16 15:31:10 +08:00
|
|
|
)
|
2021-01-15 15:28:54 +08:00
|
|
|
|
2021-01-26 15:13:20 +08:00
|
|
|
type MasterServiceInterface interface {
|
|
|
|
ShowPartitions(in *milvuspb.ShowPartitionRequest) (*milvuspb.ShowPartitionResponse, error)
|
|
|
|
ShowSegments(in *milvuspb.ShowSegmentRequest) (*milvuspb.ShowSegmentResponse, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
type DataServiceInterface interface {
|
|
|
|
GetSegmentStates(req *datapb.SegmentStatesRequest) (*datapb.SegmentStatesResponse, error)
|
2021-02-04 19:34:35 +08:00
|
|
|
GetInsertChannels(req *datapb.InsertChannelRequest) (*internalpb2.StringList, error)
|
2021-01-26 15:13:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
type QueryNodeInterface interface {
|
|
|
|
GetComponentStates() (*internalpb2.ComponentStates, error)
|
|
|
|
|
|
|
|
AddQueryChannel(in *querypb.AddQueryChannelsRequest) (*commonpb.Status, error)
|
|
|
|
RemoveQueryChannel(in *querypb.RemoveQueryChannelsRequest) (*commonpb.Status, error)
|
|
|
|
WatchDmChannels(in *querypb.WatchDmChannelsRequest) (*commonpb.Status, error)
|
|
|
|
LoadSegments(in *querypb.LoadSegmentRequest) (*commonpb.Status, error)
|
|
|
|
ReleaseSegments(in *querypb.ReleaseSegmentRequest) (*commonpb.Status, error)
|
2021-02-04 11:40:14 +08:00
|
|
|
GetSegmentInfo(req *querypb.SegmentInfoRequest) (*querypb.SegmentInfoResponse, error)
|
2021-01-26 15:13:20 +08:00
|
|
|
}
|
2021-01-22 14:28:06 +08:00
|
|
|
|
2021-01-15 15:28:54 +08:00
|
|
|
type QueryService struct {
|
2021-01-22 14:28:06 +08:00
|
|
|
loopCtx context.Context
|
|
|
|
loopCancel context.CancelFunc
|
|
|
|
|
2021-01-26 15:13:20 +08:00
|
|
|
queryServiceID uint64
|
2021-01-22 14:28:06 +08:00
|
|
|
replica metaReplica
|
|
|
|
|
2021-01-26 15:13:20 +08:00
|
|
|
dataServiceClient DataServiceInterface
|
|
|
|
masterServiceClient MasterServiceInterface
|
2021-02-04 17:47:19 +08:00
|
|
|
queryNodes map[UniqueID]*queryNodeInfo
|
2021-02-02 11:52:41 +08:00
|
|
|
numRegisterNode uint64
|
|
|
|
numQueryChannel uint64
|
2021-01-22 14:28:06 +08:00
|
|
|
|
2021-01-26 15:13:20 +08:00
|
|
|
stateCode atomic.Value
|
|
|
|
isInit atomic.Value
|
|
|
|
enableGrpc bool
|
2021-01-22 14:28:06 +08:00
|
|
|
}
|
|
|
|
|
2021-01-21 10:01:29 +08:00
|
|
|
func (qs *QueryService) Init() error {
|
2021-01-26 15:13:20 +08:00
|
|
|
Params.Init()
|
2021-01-22 14:28:06 +08:00
|
|
|
qs.isInit.Store(true)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-01-21 10:01:29 +08:00
|
|
|
func (qs *QueryService) Start() error {
|
2021-01-22 14:28:06 +08:00
|
|
|
isInit := qs.isInit.Load().(bool)
|
|
|
|
if !isInit {
|
|
|
|
return errors.New("call start before init")
|
|
|
|
}
|
|
|
|
qs.stateCode.Store(internalpb2.StateCode_HEALTHY)
|
|
|
|
return nil
|
2021-01-16 15:31:10 +08:00
|
|
|
}
|
|
|
|
|
2021-01-21 10:01:29 +08:00
|
|
|
func (qs *QueryService) Stop() error {
|
2021-01-22 14:28:06 +08:00
|
|
|
qs.loopCancel()
|
|
|
|
qs.stateCode.Store(internalpb2.StateCode_ABNORMAL)
|
|
|
|
return nil
|
2021-01-16 15:31:10 +08:00
|
|
|
}
|
|
|
|
|
2021-01-20 11:02:29 +08:00
|
|
|
func (qs *QueryService) GetComponentStates() (*internalpb2.ComponentStates, error) {
|
2021-01-22 14:28:06 +08:00
|
|
|
serviceComponentInfo := &internalpb2.ComponentInfo{
|
|
|
|
NodeID: Params.QueryServiceID,
|
|
|
|
StateCode: qs.stateCode.Load().(internalpb2.StateCode),
|
|
|
|
}
|
|
|
|
subComponentInfos := make([]*internalpb2.ComponentInfo, 0)
|
2021-01-26 15:13:20 +08:00
|
|
|
for nodeID, node := range qs.queryNodes {
|
|
|
|
componentStates, err := node.GetComponentStates()
|
2021-01-22 14:28:06 +08:00
|
|
|
if err != nil {
|
|
|
|
subComponentInfos = append(subComponentInfos, &internalpb2.ComponentInfo{
|
2021-02-04 17:47:19 +08:00
|
|
|
NodeID: nodeID,
|
2021-01-22 14:28:06 +08:00
|
|
|
StateCode: internalpb2.StateCode_ABNORMAL,
|
|
|
|
})
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
subComponentInfos = append(subComponentInfos, componentStates.State)
|
|
|
|
}
|
|
|
|
return &internalpb2.ComponentStates{
|
2021-01-26 15:13:20 +08:00
|
|
|
Status: &commonpb.Status{
|
|
|
|
ErrorCode: commonpb.ErrorCode_SUCCESS,
|
|
|
|
},
|
2021-01-22 14:28:06 +08:00
|
|
|
State: serviceComponentInfo,
|
|
|
|
SubcomponentStates: subComponentInfos,
|
|
|
|
}, nil
|
2021-01-16 15:31:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (qs *QueryService) GetTimeTickChannel() (string, error) {
|
2021-01-22 14:28:06 +08:00
|
|
|
return Params.TimeTickChannelName, nil
|
2021-01-16 15:31:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (qs *QueryService) GetStatisticsChannel() (string, error) {
|
2021-01-22 14:28:06 +08:00
|
|
|
return Params.StatsChannelName, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (qs *QueryService) RegisterNode(req *querypb.RegisterNodeRequest) (*querypb.RegisterNodeResponse, error) {
|
2021-01-27 09:50:52 +08:00
|
|
|
fmt.Println("register query node =", req.Address)
|
2021-01-27 13:52:01 +08:00
|
|
|
// TODO:: add mutex
|
2021-02-04 17:47:19 +08:00
|
|
|
allocatedID := len(qs.queryNodes)
|
2021-01-22 14:28:06 +08:00
|
|
|
|
|
|
|
registerNodeAddress := req.Address.Ip + ":" + strconv.FormatInt(req.Address.Port, 10)
|
2021-02-02 11:52:41 +08:00
|
|
|
var node *queryNodeInfo
|
2021-01-26 15:13:20 +08:00
|
|
|
if qs.enableGrpc {
|
|
|
|
client := nodeclient.NewClient(registerNodeAddress)
|
2021-02-04 17:47:19 +08:00
|
|
|
node = newQueryNodeInfo(client)
|
2021-01-22 14:28:06 +08:00
|
|
|
} else {
|
2021-02-04 17:47:19 +08:00
|
|
|
client := querynode.NewQueryNode(qs.loopCtx, uint64(allocatedID))
|
|
|
|
node = newQueryNodeInfo(client)
|
2021-01-22 14:28:06 +08:00
|
|
|
}
|
2021-02-04 17:47:19 +08:00
|
|
|
qs.queryNodes[UniqueID(allocatedID)] = node
|
2021-01-22 14:28:06 +08:00
|
|
|
|
2021-02-02 11:52:41 +08:00
|
|
|
//TODO::return init params to queryNode
|
2021-01-22 14:28:06 +08:00
|
|
|
return &querypb.RegisterNodeResponse{
|
|
|
|
Status: &commonpb.Status{
|
|
|
|
ErrorCode: commonpb.ErrorCode_SUCCESS,
|
|
|
|
},
|
|
|
|
InitParams: &internalpb2.InitParams{
|
|
|
|
NodeID: int64(allocatedID),
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (qs *QueryService) ShowCollections(req *querypb.ShowCollectionRequest) (*querypb.ShowCollectionResponse, error) {
|
|
|
|
dbID := req.DbID
|
2021-02-02 11:52:41 +08:00
|
|
|
collections, err := qs.replica.getCollections(dbID)
|
|
|
|
collectionIDs := make([]UniqueID, 0)
|
|
|
|
for _, collection := range collections {
|
|
|
|
collectionIDs = append(collectionIDs, collection.id)
|
|
|
|
}
|
2021-01-22 14:28:06 +08:00
|
|
|
if err != nil {
|
2021-02-02 11:52:41 +08:00
|
|
|
return &querypb.ShowCollectionResponse{
|
|
|
|
Status: &commonpb.Status{
|
|
|
|
ErrorCode: commonpb.ErrorCode_UNEXPECTED_ERROR,
|
|
|
|
Reason: err.Error(),
|
|
|
|
},
|
|
|
|
}, err
|
2021-01-22 14:28:06 +08:00
|
|
|
}
|
|
|
|
return &querypb.ShowCollectionResponse{
|
|
|
|
Status: &commonpb.Status{
|
|
|
|
ErrorCode: commonpb.ErrorCode_SUCCESS,
|
|
|
|
},
|
|
|
|
CollectionIDs: collectionIDs,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (qs *QueryService) LoadCollection(req *querypb.LoadCollectionRequest) (*commonpb.Status, error) {
|
2021-01-26 15:13:20 +08:00
|
|
|
dbID := req.DbID
|
|
|
|
collectionID := req.CollectionID
|
|
|
|
fn := func(err error) *commonpb.Status {
|
2021-02-02 11:52:41 +08:00
|
|
|
if err != nil {
|
|
|
|
return &commonpb.Status{
|
|
|
|
ErrorCode: commonpb.ErrorCode_UNEXPECTED_ERROR,
|
|
|
|
Reason: err.Error(),
|
|
|
|
}
|
|
|
|
}
|
2021-01-26 15:13:20 +08:00
|
|
|
return &commonpb.Status{
|
2021-02-02 11:52:41 +08:00
|
|
|
ErrorCode: commonpb.ErrorCode_SUCCESS,
|
2021-01-26 15:13:20 +08:00
|
|
|
}
|
|
|
|
}
|
2021-02-02 11:52:41 +08:00
|
|
|
collection, err := qs.replica.loadCollection(dbID, collectionID)
|
|
|
|
if err != nil {
|
|
|
|
return fn(err), err
|
|
|
|
}
|
2021-02-04 17:47:19 +08:00
|
|
|
|
|
|
|
if len(collection.dmChannelNames) != 0 {
|
2021-02-02 11:52:41 +08:00
|
|
|
return fn(nil), nil
|
|
|
|
}
|
2021-01-26 15:13:20 +08:00
|
|
|
|
2021-02-04 17:47:19 +08:00
|
|
|
channelRequest := datapb.InsertChannelRequest{
|
|
|
|
DbID: req.DbID,
|
|
|
|
CollectionID: req.CollectionID,
|
|
|
|
}
|
2021-02-04 19:34:35 +08:00
|
|
|
resp, err := qs.dataServiceClient.GetInsertChannels(&channelRequest)
|
|
|
|
if resp == nil {
|
|
|
|
err = errors.New("get insert channels resp is nil")
|
|
|
|
}
|
|
|
|
if resp.Status.ErrorCode != commonpb.ErrorCode_SUCCESS {
|
|
|
|
err = errors.New(resp.Status.Reason)
|
|
|
|
}
|
2021-02-04 17:47:19 +08:00
|
|
|
if err != nil {
|
|
|
|
return fn(err), err
|
|
|
|
}
|
2021-02-04 19:34:35 +08:00
|
|
|
dmChannels := resp.Values
|
2021-02-04 17:47:19 +08:00
|
|
|
|
2021-01-26 15:13:20 +08:00
|
|
|
// get partitionIDs
|
|
|
|
showPartitionRequest := &milvuspb.ShowPartitionRequest{
|
|
|
|
Base: &commonpb.MsgBase{
|
|
|
|
MsgType: commonpb.MsgType_kShowPartitions,
|
|
|
|
},
|
|
|
|
CollectionID: collectionID,
|
|
|
|
}
|
|
|
|
|
|
|
|
showPartitionResponse, err := qs.masterServiceClient.ShowPartitions(showPartitionRequest)
|
|
|
|
if err != nil {
|
|
|
|
return fn(err), err
|
|
|
|
}
|
|
|
|
if showPartitionResponse.Status.ErrorCode != commonpb.ErrorCode_SUCCESS {
|
2021-02-02 11:52:41 +08:00
|
|
|
return showPartitionResponse.Status, err
|
2021-01-26 15:13:20 +08:00
|
|
|
}
|
|
|
|
partitionIDs := showPartitionResponse.PartitionIDs
|
|
|
|
|
2021-02-04 17:47:19 +08:00
|
|
|
if len(partitionIDs) == 0 {
|
|
|
|
loadSegmentRequest := &querypb.LoadSegmentRequest{
|
|
|
|
CollectionID: collectionID,
|
|
|
|
}
|
|
|
|
for _, node := range qs.queryNodes {
|
|
|
|
_, err := node.LoadSegments(loadSegmentRequest)
|
|
|
|
if err != nil {
|
|
|
|
return fn(err), err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nodeIDs := qs.shuffleChannelsToQueryNode(dmChannels)
|
|
|
|
err = qs.watchDmChannels(dmChannels, nodeIDs, collection)
|
|
|
|
return fn(err), err
|
|
|
|
}
|
|
|
|
|
2021-01-26 15:13:20 +08:00
|
|
|
loadPartitionsRequest := &querypb.LoadPartitionRequest{
|
|
|
|
Base: req.Base,
|
|
|
|
DbID: dbID,
|
|
|
|
CollectionID: collectionID,
|
|
|
|
PartitionIDs: partitionIDs,
|
|
|
|
}
|
|
|
|
|
|
|
|
status, err := qs.LoadPartitions(loadPartitionsRequest)
|
|
|
|
|
|
|
|
return status, err
|
2021-01-16 15:31:10 +08:00
|
|
|
}
|
|
|
|
|
2021-01-22 14:28:06 +08:00
|
|
|
func (qs *QueryService) ReleaseCollection(req *querypb.ReleaseCollectionRequest) (*commonpb.Status, error) {
|
2021-01-26 15:13:20 +08:00
|
|
|
dbID := req.DbID
|
|
|
|
collectionID := req.CollectionID
|
2021-02-02 11:52:41 +08:00
|
|
|
partitions, err := qs.replica.getPartitions(dbID, collectionID)
|
2021-01-26 15:13:20 +08:00
|
|
|
if err != nil {
|
2021-02-02 11:52:41 +08:00
|
|
|
return &commonpb.Status{
|
|
|
|
ErrorCode: commonpb.ErrorCode_UNEXPECTED_ERROR,
|
|
|
|
Reason: err.Error(),
|
|
|
|
}, err
|
2021-01-26 15:13:20 +08:00
|
|
|
}
|
2021-02-02 11:52:41 +08:00
|
|
|
|
|
|
|
partitionIDs := make([]UniqueID, 0)
|
|
|
|
for _, partition := range partitions {
|
|
|
|
partitionIDs = append(partitionIDs, partition.id)
|
|
|
|
}
|
|
|
|
|
2021-01-26 15:13:20 +08:00
|
|
|
releasePartitionRequest := &querypb.ReleasePartitionRequest{
|
|
|
|
Base: req.Base,
|
|
|
|
DbID: dbID,
|
|
|
|
CollectionID: collectionID,
|
2021-02-02 11:52:41 +08:00
|
|
|
PartitionIDs: partitionIDs,
|
2021-01-26 15:13:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
status, err := qs.ReleasePartitions(releasePartitionRequest)
|
|
|
|
|
2021-02-04 17:47:19 +08:00
|
|
|
err = qs.replica.releaseCollection(dbID, collectionID)
|
|
|
|
if err != nil {
|
|
|
|
return &commonpb.Status{
|
|
|
|
ErrorCode: commonpb.ErrorCode_UNEXPECTED_ERROR,
|
|
|
|
Reason: err.Error(),
|
|
|
|
}, err
|
|
|
|
}
|
|
|
|
//TODO:: queryNode cancel subscribe dmChannels
|
2021-01-26 15:13:20 +08:00
|
|
|
return status, err
|
2021-01-15 15:28:54 +08:00
|
|
|
}
|
|
|
|
|
2021-01-22 14:28:06 +08:00
|
|
|
func (qs *QueryService) ShowPartitions(req *querypb.ShowPartitionRequest) (*querypb.ShowPartitionResponse, error) {
|
|
|
|
dbID := req.DbID
|
|
|
|
collectionID := req.CollectionID
|
2021-02-02 11:52:41 +08:00
|
|
|
partitions, err := qs.replica.getPartitions(dbID, collectionID)
|
|
|
|
partitionIDs := make([]UniqueID, 0)
|
|
|
|
for _, partition := range partitions {
|
|
|
|
partitionIDs = append(partitionIDs, partition.id)
|
|
|
|
}
|
2021-01-22 14:28:06 +08:00
|
|
|
if err != nil {
|
2021-02-02 11:52:41 +08:00
|
|
|
return &querypb.ShowPartitionResponse{
|
|
|
|
Status: &commonpb.Status{
|
|
|
|
ErrorCode: commonpb.ErrorCode_UNEXPECTED_ERROR,
|
|
|
|
Reason: err.Error(),
|
|
|
|
},
|
|
|
|
}, err
|
2021-01-22 14:28:06 +08:00
|
|
|
}
|
|
|
|
return &querypb.ShowPartitionResponse{
|
|
|
|
Status: &commonpb.Status{
|
|
|
|
ErrorCode: commonpb.ErrorCode_SUCCESS,
|
|
|
|
},
|
|
|
|
PartitionIDs: partitionIDs,
|
|
|
|
}, nil
|
2021-01-15 15:28:54 +08:00
|
|
|
}
|
|
|
|
|
2021-01-22 14:28:06 +08:00
|
|
|
func (qs *QueryService) LoadPartitions(req *querypb.LoadPartitionRequest) (*commonpb.Status, error) {
|
2021-02-02 11:52:41 +08:00
|
|
|
//TODO::suggest different partitions have different dm channel
|
2021-01-26 15:13:20 +08:00
|
|
|
dbID := req.DbID
|
|
|
|
collectionID := req.CollectionID
|
|
|
|
partitionIDs := req.PartitionIDs
|
2021-02-04 17:47:19 +08:00
|
|
|
|
2021-01-26 15:13:20 +08:00
|
|
|
fn := func(err error) *commonpb.Status {
|
2021-02-04 17:47:19 +08:00
|
|
|
if err != nil {
|
|
|
|
return &commonpb.Status{
|
|
|
|
ErrorCode: commonpb.ErrorCode_UNEXPECTED_ERROR,
|
|
|
|
Reason: err.Error(),
|
|
|
|
}
|
|
|
|
}
|
2021-01-26 15:13:20 +08:00
|
|
|
return &commonpb.Status{
|
2021-02-04 17:47:19 +08:00
|
|
|
ErrorCode: commonpb.ErrorCode_SUCCESS,
|
2021-01-26 15:13:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-04 17:47:19 +08:00
|
|
|
if len(partitionIDs) == 0 {
|
|
|
|
err := errors.New("partitionIDs are empty")
|
|
|
|
return fn(err), err
|
|
|
|
}
|
|
|
|
|
|
|
|
var collection *collection = nil
|
|
|
|
var err error
|
|
|
|
if collection, err = qs.replica.loadCollection(dbID, collectionID); err != nil {
|
|
|
|
return fn(err), err
|
|
|
|
}
|
|
|
|
|
2021-01-26 15:13:20 +08:00
|
|
|
for _, partitionID := range partitionIDs {
|
2021-02-04 17:47:19 +08:00
|
|
|
partition, err := qs.replica.loadPartition(dbID, collectionID, partitionID)
|
|
|
|
if err != nil {
|
|
|
|
return fn(err), err
|
|
|
|
}
|
|
|
|
|
|
|
|
if partition == nil {
|
|
|
|
return fn(err), nil
|
|
|
|
}
|
|
|
|
|
2021-01-26 15:13:20 +08:00
|
|
|
showSegmentRequest := &milvuspb.ShowSegmentRequest{
|
|
|
|
Base: &commonpb.MsgBase{
|
|
|
|
MsgType: commonpb.MsgType_kShowSegment,
|
|
|
|
},
|
|
|
|
CollectionID: collectionID,
|
|
|
|
PartitionID: partitionID,
|
|
|
|
}
|
|
|
|
showSegmentResponse, err := qs.masterServiceClient.ShowSegments(showSegmentRequest)
|
|
|
|
if err != nil {
|
|
|
|
return fn(err), err
|
|
|
|
}
|
2021-02-04 17:47:19 +08:00
|
|
|
|
2021-01-26 15:13:20 +08:00
|
|
|
segmentIDs := showSegmentResponse.SegmentIDs
|
2021-02-02 10:58:39 +08:00
|
|
|
segmentStates := make(map[UniqueID]*datapb.SegmentStateInfo)
|
2021-02-04 17:47:19 +08:00
|
|
|
channel2segs := make(map[string][]UniqueID)
|
2021-01-26 15:13:20 +08:00
|
|
|
|
2021-02-02 10:58:39 +08:00
|
|
|
resp, err := qs.dataServiceClient.GetSegmentStates(&datapb.SegmentStatesRequest{
|
|
|
|
SegmentIDs: segmentIDs,
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
2021-02-04 17:47:19 +08:00
|
|
|
return fn(err), err
|
2021-02-02 10:58:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, state := range resp.States {
|
|
|
|
segmentID := state.SegmentID
|
2021-01-26 15:13:20 +08:00
|
|
|
segmentStates[segmentID] = state
|
2021-02-04 17:47:19 +08:00
|
|
|
|
|
|
|
channelName := state.StartPosition.ChannelName
|
|
|
|
|
|
|
|
if _, ok := channel2segs[channelName]; !ok {
|
|
|
|
segments := make([]UniqueID, 0)
|
|
|
|
segments = append(segments, segmentID)
|
|
|
|
channel2segs[channelName] = segments
|
2021-01-26 15:13:20 +08:00
|
|
|
} else {
|
2021-02-04 17:47:19 +08:00
|
|
|
channel2segs[channelName] = append(channel2segs[channelName], segmentID)
|
2021-01-26 15:13:20 +08:00
|
|
|
}
|
|
|
|
}
|
2021-02-04 17:47:19 +08:00
|
|
|
|
|
|
|
qs.replica.updatePartitionState(dbID, collectionID, partitionID, querypb.PartitionState_PartialInMemory)
|
|
|
|
for channel, segmentIDs := range channel2segs {
|
|
|
|
sort.Slice(segmentIDs, func(i, j int) bool {
|
|
|
|
return segmentStates[segmentIDs[i]].StartPosition.Timestamp < segmentStates[segmentIDs[j]].StartPosition.Timestamp
|
|
|
|
})
|
|
|
|
var channelLoadDone = false
|
|
|
|
for _, node := range qs.queryNodes {
|
|
|
|
channels2node := node.dmChannelNames
|
|
|
|
for _, ch := range channels2node {
|
|
|
|
if channel == ch {
|
|
|
|
channelLoadDone = true
|
2021-01-26 15:13:20 +08:00
|
|
|
break
|
|
|
|
}
|
2021-02-04 17:47:19 +08:00
|
|
|
}
|
|
|
|
if channelLoadDone {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !channelLoadDone {
|
|
|
|
states := make([]*datapb.SegmentStateInfo, 0)
|
|
|
|
for _, id := range segmentIDs {
|
|
|
|
states = append(states, segmentStates[id])
|
|
|
|
}
|
|
|
|
loadSegmentRequest := &querypb.LoadSegmentRequest{
|
|
|
|
CollectionID: collectionID,
|
|
|
|
PartitionID: partitionID,
|
|
|
|
SegmentIDs: segmentIDs,
|
|
|
|
SegmentStates: states,
|
|
|
|
}
|
|
|
|
dmChannels := []string{channel}
|
|
|
|
nodeIDs := qs.shuffleChannelsToQueryNode(dmChannels)
|
|
|
|
err = qs.watchDmChannels(dmChannels, nodeIDs, collection)
|
|
|
|
if err != nil {
|
|
|
|
return fn(err), err
|
|
|
|
}
|
|
|
|
queryNode := qs.queryNodes[nodeIDs[0]]
|
|
|
|
//TODO:: seek when loadSegment may cause more msgs consumed
|
|
|
|
status, err := queryNode.LoadSegments(loadSegmentRequest)
|
|
|
|
if err != nil {
|
|
|
|
return status, err
|
2021-01-26 15:13:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-04 17:47:19 +08:00
|
|
|
qs.replica.updatePartitionState(dbID, collectionID, partitionID, querypb.PartitionState_InMemory)
|
|
|
|
}
|
2021-02-04 17:09:18 +08:00
|
|
|
|
2021-02-04 17:47:19 +08:00
|
|
|
if len(collection.dmChannelNames) == 0 {
|
|
|
|
channelRequest := datapb.InsertChannelRequest{
|
|
|
|
DbID: dbID,
|
|
|
|
CollectionID: collectionID,
|
|
|
|
}
|
|
|
|
|
2021-02-04 19:34:35 +08:00
|
|
|
resp, err := qs.dataServiceClient.GetInsertChannels(&channelRequest)
|
|
|
|
if resp == nil {
|
|
|
|
err = errors.New("get insert channels resp is nil")
|
|
|
|
return fn(err), err
|
|
|
|
}
|
|
|
|
if resp.Status.ErrorCode != commonpb.ErrorCode_SUCCESS {
|
|
|
|
err = errors.New(resp.Status.Reason)
|
2021-02-04 17:47:19 +08:00
|
|
|
return fn(err), err
|
|
|
|
}
|
2021-02-04 19:34:35 +08:00
|
|
|
dmChannels := resp.Values
|
2021-02-04 17:47:19 +08:00
|
|
|
for _, partitionID := range partitionIDs {
|
|
|
|
loadSegmentRequest := &querypb.LoadSegmentRequest{
|
|
|
|
CollectionID: collectionID,
|
|
|
|
PartitionID: partitionID,
|
|
|
|
}
|
|
|
|
for _, node := range qs.queryNodes {
|
|
|
|
_, err := node.LoadSegments(loadSegmentRequest)
|
|
|
|
if err != nil {
|
|
|
|
return fn(err), nil
|
2021-01-26 15:13:20 +08:00
|
|
|
}
|
|
|
|
}
|
2021-02-04 17:47:19 +08:00
|
|
|
nodeIDs := qs.shuffleChannelsToQueryNode(dmChannels)
|
|
|
|
err = qs.watchDmChannels(dmChannels, nodeIDs, collection)
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return fn(err), err
|
2021-01-26 15:13:20 +08:00
|
|
|
}
|
|
|
|
}
|
2021-02-04 17:47:19 +08:00
|
|
|
|
2021-01-26 15:13:20 +08:00
|
|
|
return &commonpb.Status{
|
|
|
|
ErrorCode: commonpb.ErrorCode_SUCCESS,
|
|
|
|
}, nil
|
2021-01-15 15:28:54 +08:00
|
|
|
}
|
|
|
|
|
2021-01-22 14:28:06 +08:00
|
|
|
func (qs *QueryService) ReleasePartitions(req *querypb.ReleasePartitionRequest) (*commonpb.Status, error) {
|
2021-01-26 15:13:20 +08:00
|
|
|
dbID := req.DbID
|
|
|
|
collectionID := req.CollectionID
|
|
|
|
partitionIDs := req.PartitionIDs
|
|
|
|
segmentIDs := make([]UniqueID, 0)
|
|
|
|
for _, partitionID := range partitionIDs {
|
2021-02-02 11:52:41 +08:00
|
|
|
segments, err := qs.replica.getSegments(dbID, collectionID, partitionID)
|
2021-01-26 15:13:20 +08:00
|
|
|
if err != nil {
|
2021-02-02 11:52:41 +08:00
|
|
|
return &commonpb.Status{
|
|
|
|
ErrorCode: commonpb.ErrorCode_UNEXPECTED_ERROR,
|
|
|
|
Reason: err.Error(),
|
|
|
|
}, err
|
2021-01-26 15:13:20 +08:00
|
|
|
}
|
2021-02-02 11:52:41 +08:00
|
|
|
res := make([]UniqueID, 0)
|
|
|
|
for _, segment := range segments {
|
|
|
|
res = append(res, segment.id)
|
|
|
|
}
|
|
|
|
|
2021-01-26 15:13:20 +08:00
|
|
|
segmentIDs = append(segmentIDs, res...)
|
2021-02-04 17:47:19 +08:00
|
|
|
err = qs.replica.releasePartition(dbID, collectionID, partitionID)
|
|
|
|
if err != nil {
|
|
|
|
return &commonpb.Status{
|
|
|
|
ErrorCode: commonpb.ErrorCode_UNEXPECTED_ERROR,
|
|
|
|
Reason: err.Error(),
|
|
|
|
}, err
|
|
|
|
}
|
2021-01-26 15:13:20 +08:00
|
|
|
}
|
|
|
|
releaseSegmentRequest := &querypb.ReleaseSegmentRequest{
|
|
|
|
Base: req.Base,
|
|
|
|
DbID: dbID,
|
|
|
|
CollectionID: collectionID,
|
|
|
|
PartitionIDs: partitionIDs,
|
|
|
|
SegmentIDs: segmentIDs,
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, node := range qs.queryNodes {
|
|
|
|
status, err := node.client.ReleaseSegments(releaseSegmentRequest)
|
|
|
|
if err != nil {
|
|
|
|
return status, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-04 17:47:19 +08:00
|
|
|
//TODO:: queryNode cancel subscribe dmChannels
|
2021-01-26 15:13:20 +08:00
|
|
|
return &commonpb.Status{
|
|
|
|
ErrorCode: commonpb.ErrorCode_SUCCESS,
|
|
|
|
}, nil
|
2021-01-15 15:28:54 +08:00
|
|
|
}
|
|
|
|
|
2021-01-22 14:28:06 +08:00
|
|
|
func (qs *QueryService) CreateQueryChannel() (*querypb.CreateQueryChannelResponse, error) {
|
|
|
|
channelID := qs.numQueryChannel
|
|
|
|
qs.numQueryChannel++
|
|
|
|
allocatedQueryChannel := "query-" + strconv.FormatInt(int64(channelID), 10)
|
|
|
|
allocatedQueryResultChannel := "queryResult-" + strconv.FormatInt(int64(channelID), 10)
|
2021-01-15 15:28:54 +08:00
|
|
|
|
2021-01-26 15:13:20 +08:00
|
|
|
//TODO:: query node watch query channels
|
2021-01-22 14:28:06 +08:00
|
|
|
return &querypb.CreateQueryChannelResponse{
|
|
|
|
Status: &commonpb.Status{
|
|
|
|
ErrorCode: commonpb.ErrorCode_SUCCESS,
|
|
|
|
},
|
|
|
|
RequestChannel: allocatedQueryChannel,
|
|
|
|
ResultChannel: allocatedQueryResultChannel,
|
|
|
|
}, nil
|
2021-01-15 15:28:54 +08:00
|
|
|
}
|
|
|
|
|
2021-01-22 14:28:06 +08:00
|
|
|
func (qs *QueryService) GetPartitionStates(req *querypb.PartitionStatesRequest) (*querypb.PartitionStatesResponse, error) {
|
2021-01-26 15:13:20 +08:00
|
|
|
states, err := qs.replica.getPartitionStates(req.DbID, req.CollectionID, req.PartitionIDs)
|
|
|
|
if err != nil {
|
|
|
|
return &querypb.PartitionStatesResponse{
|
|
|
|
Status: &commonpb.Status{
|
|
|
|
ErrorCode: commonpb.ErrorCode_UNEXPECTED_ERROR,
|
|
|
|
Reason: err.Error(),
|
|
|
|
},
|
|
|
|
PartitionDescriptions: states,
|
|
|
|
}, err
|
|
|
|
}
|
|
|
|
return &querypb.PartitionStatesResponse{
|
|
|
|
Status: &commonpb.Status{
|
|
|
|
ErrorCode: commonpb.ErrorCode_SUCCESS,
|
|
|
|
},
|
|
|
|
PartitionDescriptions: states,
|
|
|
|
}, nil
|
2021-01-16 15:31:10 +08:00
|
|
|
}
|
|
|
|
|
2021-02-04 11:40:14 +08:00
|
|
|
func (qs *QueryService) GetSegmentInfo(req *querypb.SegmentInfoRequest) (*querypb.SegmentInfoResponse, error) {
|
|
|
|
segmentInfos := make([]*querypb.SegmentInfo, 0)
|
|
|
|
for _, node := range qs.queryNodes {
|
|
|
|
segmentInfo, err := node.client.GetSegmentInfo(req)
|
|
|
|
if err != nil {
|
|
|
|
return &querypb.SegmentInfoResponse{
|
|
|
|
Status: &commonpb.Status{
|
|
|
|
ErrorCode: commonpb.ErrorCode_UNEXPECTED_ERROR,
|
|
|
|
Reason: err.Error(),
|
|
|
|
},
|
|
|
|
}, err
|
|
|
|
}
|
|
|
|
segmentInfos = append(segmentInfos, segmentInfo.Infos...)
|
|
|
|
}
|
|
|
|
return &querypb.SegmentInfoResponse{
|
|
|
|
Status: &commonpb.Status{
|
|
|
|
ErrorCode: commonpb.ErrorCode_SUCCESS,
|
|
|
|
},
|
|
|
|
Infos: segmentInfos,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2021-01-26 15:13:20 +08:00
|
|
|
func NewQueryService(ctx context.Context) (*QueryService, error) {
|
2021-02-04 17:47:19 +08:00
|
|
|
nodes := make(map[UniqueID]*queryNodeInfo)
|
2021-01-22 14:28:06 +08:00
|
|
|
ctx1, cancel := context.WithCancel(ctx)
|
2021-01-26 15:13:20 +08:00
|
|
|
replica := newMetaReplica()
|
2021-01-22 14:28:06 +08:00
|
|
|
service := &QueryService{
|
|
|
|
loopCtx: ctx1,
|
|
|
|
loopCancel: cancel,
|
2021-02-04 17:31:02 +08:00
|
|
|
replica: replica,
|
2021-02-04 17:47:19 +08:00
|
|
|
queryNodes: nodes,
|
2021-01-26 15:13:20 +08:00
|
|
|
numRegisterNode: 0,
|
2021-01-22 14:28:06 +08:00
|
|
|
numQueryChannel: 0,
|
2021-01-26 15:13:20 +08:00
|
|
|
enableGrpc: false,
|
2021-01-22 14:28:06 +08:00
|
|
|
}
|
|
|
|
service.stateCode.Store(internalpb2.StateCode_INITIALIZING)
|
|
|
|
service.isInit.Store(false)
|
|
|
|
return service, nil
|
2021-01-15 15:28:54 +08:00
|
|
|
}
|
2021-01-26 15:13:20 +08:00
|
|
|
|
|
|
|
func (qs *QueryService) SetMasterService(masterService MasterServiceInterface) {
|
|
|
|
qs.masterServiceClient = masterService
|
|
|
|
}
|
|
|
|
|
|
|
|
func (qs *QueryService) SetDataService(dataService DataServiceInterface) {
|
|
|
|
qs.dataServiceClient = dataService
|
|
|
|
}
|
|
|
|
|
|
|
|
func (qs *QueryService) SetEnableGrpc(en bool) {
|
|
|
|
qs.enableGrpc = en
|
|
|
|
}
|
2021-02-04 17:47:19 +08:00
|
|
|
|
|
|
|
func (qs *QueryService) watchDmChannels(dmChannels []string, assignedNodeIDs []UniqueID, collection *collection) error {
|
|
|
|
err := qs.replica.addDmChannels(collection.id, dmChannels)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
node2channels := make(map[UniqueID][]string)
|
|
|
|
for i, channel := range dmChannels {
|
|
|
|
nodeID := assignedNodeIDs[i]
|
|
|
|
findChannel := false
|
|
|
|
for _, ch := range collection.dmChannelNames {
|
|
|
|
if channel == ch {
|
|
|
|
findChannel = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !findChannel {
|
|
|
|
if _, ok := node2channels[nodeID]; ok {
|
|
|
|
node2channels[nodeID] = append(node2channels[nodeID], channel)
|
|
|
|
} else {
|
|
|
|
channels := make([]string, 0)
|
|
|
|
channels = append(channels, channel)
|
|
|
|
node2channels[nodeID] = channels
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for nodeID, channels := range node2channels {
|
|
|
|
node := qs.queryNodes[nodeID]
|
|
|
|
request := &querypb.WatchDmChannelsRequest{
|
|
|
|
ChannelIDs: channels,
|
|
|
|
}
|
|
|
|
_, err := node.WatchDmChannels(request)
|
|
|
|
node.AddDmChannels(channels)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (qs *QueryService) shuffleChannelsToQueryNode(dmChannels []string) []UniqueID {
|
|
|
|
maxNumDMChannel := 0
|
|
|
|
res := make([]UniqueID, 0)
|
|
|
|
node2lens := make(map[UniqueID]int)
|
|
|
|
for id, node := range qs.queryNodes {
|
|
|
|
node2lens[id] = len(node.dmChannelNames)
|
|
|
|
}
|
|
|
|
offset := 0
|
|
|
|
for {
|
|
|
|
lastOffset := offset
|
|
|
|
for id, len := range node2lens {
|
|
|
|
if len >= maxNumDMChannel {
|
|
|
|
maxNumDMChannel = len
|
|
|
|
} else {
|
|
|
|
res = append(res, id)
|
|
|
|
node2lens[id]++
|
|
|
|
offset++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if lastOffset == offset {
|
|
|
|
for id := range node2lens {
|
|
|
|
res = append(res, id)
|
|
|
|
node2lens[id]++
|
|
|
|
offset++
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if offset == len(dmChannels) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res
|
|
|
|
}
|