2022-07-18 09:58:28 +08:00
|
|
|
package proxy
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"strconv"
|
|
|
|
|
2023-02-26 11:31:49 +08:00
|
|
|
"github.com/cockroachdb/errors"
|
2023-03-27 00:42:00 +08:00
|
|
|
"github.com/golang/protobuf/proto"
|
2023-01-12 16:09:39 +08:00
|
|
|
"go.opentelemetry.io/otel"
|
2023-04-06 19:14:32 +08:00
|
|
|
"go.uber.org/zap"
|
2022-07-18 09:58:28 +08:00
|
|
|
|
2023-06-09 01:28:37 +08:00
|
|
|
"github.com/milvus-io/milvus-proto/go-api/v2/commonpb"
|
|
|
|
"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
|
2023-04-06 19:14:32 +08:00
|
|
|
"github.com/milvus-io/milvus/internal/proto/datapb"
|
2022-07-18 09:58:28 +08:00
|
|
|
"github.com/milvus-io/milvus/internal/proto/internalpb"
|
|
|
|
"github.com/milvus-io/milvus/internal/proto/querypb"
|
|
|
|
"github.com/milvus-io/milvus/internal/types"
|
2023-04-06 19:14:32 +08:00
|
|
|
"github.com/milvus-io/milvus/pkg/log"
|
|
|
|
"github.com/milvus-io/milvus/pkg/util/commonpbutil"
|
|
|
|
"github.com/milvus-io/milvus/pkg/util/funcutil"
|
2023-06-13 10:20:37 +08:00
|
|
|
"github.com/milvus-io/milvus/pkg/util/merr"
|
2023-04-06 19:14:32 +08:00
|
|
|
"github.com/milvus-io/milvus/pkg/util/paramtable"
|
|
|
|
"github.com/milvus-io/milvus/pkg/util/timerecord"
|
|
|
|
"github.com/milvus-io/milvus/pkg/util/tsoutil"
|
|
|
|
"github.com/milvus-io/milvus/pkg/util/typeutil"
|
2022-07-18 09:58:28 +08:00
|
|
|
)
|
|
|
|
|
2022-10-08 15:38:58 +08:00
|
|
|
const (
|
|
|
|
GetCollectionStatisticsTaskName = "GetCollectionStatisticsTask"
|
|
|
|
GetPartitionStatisticsTaskName = "GetPartitionStatisticsTask"
|
|
|
|
)
|
|
|
|
|
2022-07-18 09:58:28 +08:00
|
|
|
type getStatisticsTask struct {
|
|
|
|
request *milvuspb.GetStatisticsRequest
|
|
|
|
result *milvuspb.GetStatisticsResponse
|
|
|
|
Condition
|
|
|
|
collectionName string
|
|
|
|
partitionNames []string
|
|
|
|
// partition ids that are loaded into query node, require get statistics from QueryNode
|
|
|
|
loadedPartitionIDs []UniqueID
|
|
|
|
// partition ids that are not loaded into query node, require get statistics from DataCoord
|
|
|
|
unloadedPartitionIDs []UniqueID
|
|
|
|
|
2023-06-13 10:20:37 +08:00
|
|
|
ctx context.Context
|
2023-09-26 09:57:25 +08:00
|
|
|
dc types.DataCoordClient
|
2023-06-13 10:20:37 +08:00
|
|
|
tr *timerecord.TimeRecorder
|
2022-07-18 09:58:28 +08:00
|
|
|
|
|
|
|
fromDataCoord bool
|
|
|
|
fromQueryNode bool
|
|
|
|
|
|
|
|
// if query from shard
|
|
|
|
*internalpb.GetStatisticsRequest
|
2023-09-26 09:57:25 +08:00
|
|
|
qc types.QueryCoordClient
|
2023-06-13 10:20:37 +08:00
|
|
|
resultBuf *typeutil.ConcurrentSet[*internalpb.GetStatisticsResponse]
|
|
|
|
|
|
|
|
lb LBPolicy
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getStatisticsTask) TraceCtx() context.Context {
|
|
|
|
return g.ctx
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getStatisticsTask) ID() UniqueID {
|
|
|
|
return g.Base.MsgID
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getStatisticsTask) SetID(uid UniqueID) {
|
|
|
|
g.Base.MsgID = uid
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getStatisticsTask) Name() string {
|
|
|
|
return GetPartitionStatisticsTaskName
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getStatisticsTask) Type() commonpb.MsgType {
|
|
|
|
return g.Base.MsgType
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getStatisticsTask) BeginTs() Timestamp {
|
|
|
|
return g.Base.Timestamp
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getStatisticsTask) EndTs() Timestamp {
|
|
|
|
return g.Base.Timestamp
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getStatisticsTask) SetTs(ts Timestamp) {
|
|
|
|
g.Base.Timestamp = ts
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getStatisticsTask) OnEnqueue() error {
|
|
|
|
g.GetStatisticsRequest = &internalpb.GetStatisticsRequest{
|
2022-10-19 10:01:26 +08:00
|
|
|
Base: commonpbutil.NewMsgBase(),
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getStatisticsTask) PreExecute(ctx context.Context) error {
|
|
|
|
g.DbID = 0
|
|
|
|
g.collectionName = g.request.GetCollectionName()
|
|
|
|
g.partitionNames = g.request.GetPartitionNames()
|
|
|
|
// g.TravelTimestamp = g.request.GetTravelTimestamp()
|
|
|
|
g.GuaranteeTimestamp = g.request.GetGuaranteeTimestamp()
|
|
|
|
|
2023-01-12 16:09:39 +08:00
|
|
|
ctx, sp := otel.Tracer(typeutil.ProxyRole).Start(ctx, "Proxy-GetStatistics-PreExecute")
|
|
|
|
defer sp.End()
|
2022-07-18 09:58:28 +08:00
|
|
|
|
|
|
|
// TODO: Maybe we should create a new MsgType: GetStatistics?
|
|
|
|
g.Base.MsgType = commonpb.MsgType_GetPartitionStatistics
|
2022-11-04 14:25:38 +08:00
|
|
|
g.Base.SourceID = paramtable.GetNodeID()
|
2022-07-18 09:58:28 +08:00
|
|
|
|
2023-06-25 17:20:43 +08:00
|
|
|
collID, err := globalMetaCache.GetCollectionID(ctx, g.request.GetDbName(), g.collectionName)
|
2022-07-18 09:58:28 +08:00
|
|
|
if err != nil { // err is not nil if collection not exists
|
|
|
|
return err
|
|
|
|
}
|
2023-08-22 17:06:22 +08:00
|
|
|
partIDs, err := getPartitionIDs(ctx, g.request.GetDbName(), g.collectionName, g.partitionNames)
|
2022-07-18 09:58:28 +08:00
|
|
|
if err != nil { // err is not nil if partition not exists
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
g.GetStatisticsRequest.DbID = 0 // todo
|
|
|
|
g.GetStatisticsRequest.CollectionID = collID
|
|
|
|
|
2023-08-10 18:53:17 +08:00
|
|
|
g.TravelTimestamp = g.BeginTs()
|
2022-07-18 09:58:28 +08:00
|
|
|
g.GuaranteeTimestamp = parseGuaranteeTs(g.GuaranteeTimestamp, g.BeginTs())
|
|
|
|
|
|
|
|
deadline, ok := g.TraceCtx().Deadline()
|
|
|
|
if ok {
|
|
|
|
g.TimeoutTimestamp = tsoutil.ComposeTSByTime(deadline, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if collection/partitions are loaded into query node
|
2023-08-22 17:06:22 +08:00
|
|
|
loaded, unloaded, err := checkFullLoaded(ctx, g.qc, g.request.GetDbName(), g.collectionName, g.GetStatisticsRequest.CollectionID, partIDs)
|
2023-08-01 17:33:06 +08:00
|
|
|
log := log.Ctx(ctx).With(
|
|
|
|
zap.String("collectionName", g.collectionName),
|
|
|
|
zap.Int64("collectionID", g.CollectionID),
|
|
|
|
)
|
2022-07-18 09:58:28 +08:00
|
|
|
if err != nil {
|
|
|
|
g.fromDataCoord = true
|
|
|
|
g.unloadedPartitionIDs = partIDs
|
2023-08-01 17:33:06 +08:00
|
|
|
log.Info("checkFullLoaded failed, try get statistics from DataCoord",
|
|
|
|
zap.Error(err))
|
2022-07-18 09:58:28 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if len(unloaded) > 0 {
|
|
|
|
g.fromDataCoord = true
|
|
|
|
g.unloadedPartitionIDs = unloaded
|
2023-06-19 13:28:41 +08:00
|
|
|
log.Info("some partitions has not been loaded, try get statistics from DataCoord",
|
|
|
|
zap.Int64s("unloaded partitions", unloaded))
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
|
|
|
if len(loaded) > 0 {
|
|
|
|
g.fromQueryNode = true
|
|
|
|
g.loadedPartitionIDs = loaded
|
2023-06-19 13:28:41 +08:00
|
|
|
log.Info("some partitions has been loaded, try get statistics from QueryNode",
|
|
|
|
zap.Int64s("loaded partitions", loaded))
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getStatisticsTask) Execute(ctx context.Context) error {
|
2023-01-12 16:09:39 +08:00
|
|
|
ctx, sp := otel.Tracer(typeutil.ProxyRole).Start(ctx, "Proxy-GetStatistics-Execute")
|
|
|
|
defer sp.End()
|
2022-07-18 09:58:28 +08:00
|
|
|
if g.fromQueryNode {
|
|
|
|
// if request get statistics of collection which is full loaded into query node
|
|
|
|
// then we need not pass partition ids params
|
|
|
|
if len(g.request.GetPartitionNames()) == 0 && len(g.unloadedPartitionIDs) == 0 {
|
|
|
|
g.loadedPartitionIDs = []UniqueID{}
|
|
|
|
}
|
|
|
|
err := g.getStatisticsFromQueryNode(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-11-14 15:29:06 +08:00
|
|
|
log.Ctx(ctx).Debug("get collection statistics from QueryNode execute done")
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
|
|
|
if g.fromDataCoord {
|
|
|
|
err := g.getStatisticsFromDataCoord(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-11-14 15:29:06 +08:00
|
|
|
log.Debug("get collection statistics from DataCoord execute done")
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getStatisticsTask) PostExecute(ctx context.Context) error {
|
2023-01-12 16:09:39 +08:00
|
|
|
_, sp := otel.Tracer(typeutil.ProxyRole).Start(ctx, "Proxy-GetStatistic-PostExecute")
|
|
|
|
defer sp.End()
|
2022-07-18 09:58:28 +08:00
|
|
|
tr := timerecord.NewTimeRecorder("getStatisticTask PostExecute")
|
|
|
|
defer func() {
|
|
|
|
tr.Elapse("done")
|
|
|
|
}()
|
|
|
|
|
2023-06-13 10:20:37 +08:00
|
|
|
toReduceResults := make([]*internalpb.GetStatisticsResponse, 0)
|
|
|
|
select {
|
|
|
|
case <-g.TraceCtx().Done():
|
|
|
|
log.Debug("wait to finish timeout!")
|
|
|
|
return nil
|
|
|
|
default:
|
|
|
|
log.Debug("all get statistics are finished or canceled")
|
|
|
|
g.resultBuf.Range(func(res *internalpb.GetStatisticsResponse) bool {
|
|
|
|
toReduceResults = append(toReduceResults, res)
|
|
|
|
log.Debug("proxy receives one get statistic response",
|
|
|
|
zap.Int64("sourceID", res.GetBase().GetSourceID()))
|
|
|
|
return true
|
|
|
|
})
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
|
|
|
|
2023-06-13 10:20:37 +08:00
|
|
|
validResults, err := decodeGetStatisticsResults(toReduceResults)
|
2022-07-18 09:58:28 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
result, err := reduceStatisticResponse(validResults)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
g.result = &milvuspb.GetStatisticsResponse{
|
2023-10-11 21:01:35 +08:00
|
|
|
Status: merr.Success(),
|
2022-07-18 09:58:28 +08:00
|
|
|
Stats: result,
|
|
|
|
}
|
|
|
|
|
2023-06-19 13:28:41 +08:00
|
|
|
log.Debug("get statistics post execute done", zap.Any("result", result))
|
2022-07-18 09:58:28 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getStatisticsTask) getStatisticsFromDataCoord(ctx context.Context) error {
|
|
|
|
collID := g.CollectionID
|
|
|
|
partIDs := g.unloadedPartitionIDs
|
|
|
|
|
|
|
|
req := &datapb.GetPartitionStatisticsRequest{
|
2022-10-21 15:57:28 +08:00
|
|
|
Base: commonpbutil.UpdateMsgBase(
|
2022-10-19 10:01:26 +08:00
|
|
|
g.Base,
|
|
|
|
commonpbutil.WithMsgType(commonpb.MsgType_GetPartitionStatistics),
|
|
|
|
),
|
2022-07-18 09:58:28 +08:00
|
|
|
CollectionID: collID,
|
|
|
|
PartitionIDs: partIDs,
|
|
|
|
}
|
|
|
|
|
|
|
|
result, err := g.dc.GetPartitionStatistics(ctx, req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-09-12 16:07:18 +08:00
|
|
|
if result.GetStatus().GetErrorCode() != commonpb.ErrorCode_Success {
|
2023-09-15 10:09:21 +08:00
|
|
|
return merr.Error(result.GetStatus())
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
2023-06-13 10:20:37 +08:00
|
|
|
if g.resultBuf == nil {
|
|
|
|
g.resultBuf = typeutil.NewConcurrentSet[*internalpb.GetStatisticsResponse]()
|
|
|
|
}
|
|
|
|
g.resultBuf.Insert(&internalpb.GetStatisticsResponse{
|
2023-10-11 21:01:35 +08:00
|
|
|
Status: merr.Success(),
|
2022-07-18 09:58:28 +08:00
|
|
|
Stats: result.Stats,
|
|
|
|
})
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getStatisticsTask) getStatisticsFromQueryNode(ctx context.Context) error {
|
|
|
|
g.GetStatisticsRequest.PartitionIDs = g.loadedPartitionIDs
|
2023-06-13 10:20:37 +08:00
|
|
|
if g.resultBuf == nil {
|
|
|
|
g.resultBuf = typeutil.NewConcurrentSet[*internalpb.GetStatisticsResponse]()
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
2023-06-13 10:20:37 +08:00
|
|
|
err := g.lb.Execute(ctx, CollectionWorkLoad{
|
2023-08-01 17:33:06 +08:00
|
|
|
db: g.request.GetDbName(),
|
|
|
|
collectionID: g.GetStatisticsRequest.CollectionID,
|
|
|
|
collectionName: g.collectionName,
|
|
|
|
nq: 1,
|
|
|
|
exec: g.getStatisticsShard,
|
2023-06-13 10:20:37 +08:00
|
|
|
})
|
2022-07-18 09:58:28 +08:00
|
|
|
if err != nil {
|
2023-09-04 09:57:09 +08:00
|
|
|
return errors.Wrap(err, "failed to statistic")
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-01-09 11:38:48 +08:00
|
|
|
func (g *getStatisticsTask) getStatisticsShard(ctx context.Context, nodeID int64, qn types.QueryNodeClient, channel string) error {
|
2023-03-27 00:42:00 +08:00
|
|
|
nodeReq := proto.Clone(g.GetStatisticsRequest).(*internalpb.GetStatisticsRequest)
|
|
|
|
nodeReq.Base.TargetID = nodeID
|
2022-07-18 09:58:28 +08:00
|
|
|
req := &querypb.GetStatisticsRequest{
|
2023-03-27 00:42:00 +08:00
|
|
|
Req: nodeReq,
|
2024-01-09 11:38:48 +08:00
|
|
|
DmlChannels: []string{channel},
|
2022-07-18 09:58:28 +08:00
|
|
|
Scope: querypb.DataScope_All,
|
|
|
|
}
|
|
|
|
result, err := qn.GetStatistics(ctx, req)
|
|
|
|
if err != nil {
|
2022-11-14 15:29:06 +08:00
|
|
|
log.Warn("QueryNode statistic return error",
|
|
|
|
zap.Int64("nodeID", nodeID),
|
2024-01-09 11:38:48 +08:00
|
|
|
zap.String("channel", channel),
|
2022-11-14 15:29:06 +08:00
|
|
|
zap.Error(err))
|
2023-06-25 17:20:43 +08:00
|
|
|
globalMetaCache.DeprecateShardCache(g.request.GetDbName(), g.collectionName)
|
2022-07-18 09:58:28 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
if result.GetStatus().GetErrorCode() == commonpb.ErrorCode_NotShardLeader {
|
2022-11-14 15:29:06 +08:00
|
|
|
log.Warn("QueryNode is not shardLeader",
|
|
|
|
zap.Int64("nodeID", nodeID),
|
2024-01-09 11:38:48 +08:00
|
|
|
zap.String("channel", channel))
|
2023-06-25 17:20:43 +08:00
|
|
|
globalMetaCache.DeprecateShardCache(g.request.GetDbName(), g.collectionName)
|
2022-07-18 09:58:28 +08:00
|
|
|
return errInvalidShardLeaders
|
|
|
|
}
|
|
|
|
if result.GetStatus().GetErrorCode() != commonpb.ErrorCode_Success {
|
2022-11-14 15:29:06 +08:00
|
|
|
log.Warn("QueryNode statistic result error",
|
|
|
|
zap.Int64("nodeID", nodeID),
|
|
|
|
zap.String("reason", result.GetStatus().GetReason()))
|
2023-06-25 17:20:43 +08:00
|
|
|
globalMetaCache.DeprecateShardCache(g.request.GetDbName(), g.collectionName)
|
2023-11-30 18:34:32 +08:00
|
|
|
return errors.Wrapf(merr.Error(result.GetStatus()), "fail to get statistic on QueryNode ID=%d", nodeID)
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
2023-06-13 10:20:37 +08:00
|
|
|
g.resultBuf.Insert(result)
|
2022-07-18 09:58:28 +08:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// checkFullLoaded check if collection / partition was fully loaded into QueryNode
|
|
|
|
// return loaded partitions, unloaded partitions and error
|
2023-09-26 09:57:25 +08:00
|
|
|
func checkFullLoaded(ctx context.Context, qc types.QueryCoordClient, dbName string, collectionName string, collectionID int64, searchPartitionIDs []UniqueID) ([]UniqueID, []UniqueID, error) {
|
2022-07-18 09:58:28 +08:00
|
|
|
var loadedPartitionIDs []UniqueID
|
|
|
|
var unloadPartitionIDs []UniqueID
|
|
|
|
|
|
|
|
// TODO: Consider to check if partition loaded from cache to save rpc.
|
2023-08-22 17:06:22 +08:00
|
|
|
info, err := globalMetaCache.GetCollectionInfo(ctx, dbName, collectionName, collectionID)
|
2022-07-18 09:58:28 +08:00
|
|
|
if err != nil {
|
2023-08-22 17:06:22 +08:00
|
|
|
return nil, nil, fmt.Errorf("GetCollectionInfo failed, dbName = %s, collectionName = %s,collectionID = %d, err = %s", dbName, collectionName, collectionID, err)
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
2023-12-20 10:02:43 +08:00
|
|
|
partitionInfos, err := globalMetaCache.GetPartitions(ctx, dbName, collectionName)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, fmt.Errorf("GetPartitions failed, dbName = %s, collectionName = %s,collectionID = %d, err = %s", dbName, collectionName, collectionID, err)
|
|
|
|
}
|
2022-07-18 09:58:28 +08:00
|
|
|
|
|
|
|
// If request to search partitions
|
|
|
|
if len(searchPartitionIDs) > 0 {
|
|
|
|
resp, err := qc.ShowPartitions(ctx, &querypb.ShowPartitionsRequest{
|
2022-10-19 10:01:26 +08:00
|
|
|
Base: commonpbutil.NewMsgBase(
|
|
|
|
commonpbutil.WithMsgType(commonpb.MsgType_ShowPartitions),
|
2022-11-04 14:25:38 +08:00
|
|
|
commonpbutil.WithSourceID(paramtable.GetNodeID()),
|
2022-10-19 10:01:26 +08:00
|
|
|
),
|
2022-07-18 09:58:28 +08:00
|
|
|
CollectionID: info.collID,
|
|
|
|
PartitionIDs: searchPartitionIDs,
|
|
|
|
})
|
|
|
|
if err != nil {
|
2023-08-01 17:33:06 +08:00
|
|
|
return nil, nil, fmt.Errorf("showPartitions failed, collection = %d, partitionIDs = %v, err = %s", collectionID, searchPartitionIDs, err)
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
2023-09-12 16:07:18 +08:00
|
|
|
if resp.GetStatus().GetErrorCode() != commonpb.ErrorCode_Success {
|
2023-08-01 17:33:06 +08:00
|
|
|
return nil, nil, fmt.Errorf("showPartitions failed, collection = %d, partitionIDs = %v, reason = %s", collectionID, searchPartitionIDs, resp.GetStatus().GetReason())
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for i, percentage := range resp.GetInMemoryPercentages() {
|
|
|
|
if percentage >= 100 {
|
|
|
|
loadedPartitionIDs = append(loadedPartitionIDs, resp.GetPartitionIDs()[i])
|
2022-11-11 16:17:04 +08:00
|
|
|
} else {
|
|
|
|
unloadPartitionIDs = append(unloadPartitionIDs, resp.GetPartitionIDs()[i])
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return loadedPartitionIDs, unloadPartitionIDs, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// If request to search collection
|
|
|
|
resp, err := qc.ShowPartitions(ctx, &querypb.ShowPartitionsRequest{
|
2022-10-19 10:01:26 +08:00
|
|
|
Base: commonpbutil.NewMsgBase(
|
|
|
|
commonpbutil.WithMsgType(commonpb.MsgType_ShowPartitions),
|
2022-11-04 14:25:38 +08:00
|
|
|
commonpbutil.WithSourceID(paramtable.GetNodeID()),
|
2022-10-19 10:01:26 +08:00
|
|
|
),
|
2022-07-18 09:58:28 +08:00
|
|
|
CollectionID: info.collID,
|
|
|
|
})
|
|
|
|
if err != nil {
|
2023-08-01 17:33:06 +08:00
|
|
|
return nil, nil, fmt.Errorf("showPartitions failed, collection = %d, partitionIDs = %v, err = %s", collectionID, searchPartitionIDs, err)
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
2023-09-12 16:07:18 +08:00
|
|
|
if resp.GetStatus().GetErrorCode() != commonpb.ErrorCode_Success {
|
2023-08-01 17:33:06 +08:00
|
|
|
return nil, nil, fmt.Errorf("showPartitions failed, collection = %d, partitionIDs = %v, reason = %s", collectionID, searchPartitionIDs, resp.GetStatus().GetReason())
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
loadedMap := make(map[UniqueID]bool)
|
|
|
|
|
|
|
|
for i, percentage := range resp.GetInMemoryPercentages() {
|
|
|
|
if percentage >= 100 {
|
|
|
|
loadedMap[resp.GetPartitionIDs()[i]] = true
|
|
|
|
loadedPartitionIDs = append(loadedPartitionIDs, resp.GetPartitionIDs()[i])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-20 10:02:43 +08:00
|
|
|
for _, partitionID := range partitionInfos {
|
|
|
|
if _, ok := loadedMap[partitionID]; !ok {
|
|
|
|
unloadPartitionIDs = append(unloadPartitionIDs, partitionID)
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
|
|
|
}
|
2023-12-20 10:02:43 +08:00
|
|
|
|
2022-07-18 09:58:28 +08:00
|
|
|
return loadedPartitionIDs, unloadPartitionIDs, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func decodeGetStatisticsResults(results []*internalpb.GetStatisticsResponse) ([]map[string]string, error) {
|
|
|
|
ret := make([]map[string]string, len(results))
|
|
|
|
for i, result := range results {
|
|
|
|
if result.GetStatus().GetErrorCode() != commonpb.ErrorCode_Success {
|
|
|
|
return nil, fmt.Errorf("fail to decode result, reason=%s", result.GetStatus().GetReason())
|
|
|
|
}
|
|
|
|
ret[i] = funcutil.KeyValuePair2Map(result.GetStats())
|
|
|
|
}
|
|
|
|
return ret, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func reduceStatisticResponse(results []map[string]string) ([]*commonpb.KeyValuePair, error) {
|
|
|
|
mergedResults := map[string]interface{}{
|
|
|
|
"row_count": int64(0),
|
|
|
|
}
|
|
|
|
fieldMethod := map[string]func(string) error{
|
|
|
|
"row_count": func(str string) error {
|
|
|
|
count, err := strconv.ParseInt(str, 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
mergedResults["row_count"] = mergedResults["row_count"].(int64) + count
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
err := funcutil.MapReduce(results, fieldMethod)
|
|
|
|
|
|
|
|
stringMap := make(map[string]string)
|
|
|
|
for k, v := range mergedResults {
|
|
|
|
stringMap[k] = fmt.Sprint(v)
|
|
|
|
}
|
|
|
|
|
|
|
|
return funcutil.Map2KeyValuePair(stringMap), err
|
|
|
|
}
|
|
|
|
|
|
|
|
// implement Task
|
|
|
|
// try to compatible with old API (getCollectionStatistics & getPartitionStatistics)
|
|
|
|
|
|
|
|
//type getPartitionStatisticsTask struct {
|
|
|
|
// getStatisticsTask
|
|
|
|
// request *milvuspb.GetPartitionStatisticsRequest
|
|
|
|
// result *milvuspb.GetPartitionStatisticsResponse
|
|
|
|
//}
|
|
|
|
//
|
|
|
|
//func (g *getPartitionStatisticsTask) PreExecute(ctx context.Context) error {
|
|
|
|
// g.getStatisticsTask.DbID = 0
|
|
|
|
// g.getStatisticsTask.collectionName = g.request.GetCollectionName()
|
|
|
|
// g.getStatisticsTask.partitionNames = []string{g.request.GetPartitionName()}
|
|
|
|
// // g.TravelTimestamp = g.request.GetTravelTimestamp()
|
|
|
|
// // g.GuaranteeTimestamp = g.request.GetGuaranteeTimestamp()
|
|
|
|
// return g.getStatisticsTask.PreExecute(ctx)
|
|
|
|
//}
|
|
|
|
//
|
|
|
|
//func (g *getPartitionStatisticsTask) Execute(ctx context.Context) error {
|
|
|
|
// if g.fromQueryNode {
|
|
|
|
// err := g.getStatisticsTask.Execute(ctx)
|
|
|
|
// if err != nil {
|
|
|
|
// return err
|
|
|
|
// }
|
|
|
|
// log.Debug("get partition statistics from QueryNode execute done", zap.Int64("msgID", g.ID()))
|
|
|
|
// }
|
|
|
|
// if g.fromDataCoord {
|
|
|
|
// collID := g.CollectionID
|
|
|
|
// partIDs := g.unloadedPartitionIDs
|
|
|
|
//
|
|
|
|
// req := &datapb.GetPartitionStatisticsRequest{
|
|
|
|
// Base: &commonpb.MsgBase{
|
|
|
|
// MsgType: commonpb.MsgType_GetPartitionStatistics,
|
|
|
|
// MsgID: g.Base.MsgID,
|
|
|
|
// Timestamp: g.Base.Timestamp,
|
|
|
|
// SourceID: g.Base.SourceID,
|
|
|
|
// },
|
|
|
|
// CollectionID: collID,
|
|
|
|
// PartitionIDs: partIDs,
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// result, err := g.dc.GetPartitionStatistics(ctx, req)
|
|
|
|
// if err != nil {
|
|
|
|
// return err
|
|
|
|
// }
|
2023-09-12 16:07:18 +08:00
|
|
|
// if result.GetStatus().GetErrorCode() != commonpb.ErrorCode_Success {
|
2023-09-15 10:09:21 +08:00
|
|
|
// return merr.Error(result.GetStatus())
|
2022-07-18 09:58:28 +08:00
|
|
|
// }
|
|
|
|
// g.toReduceResults = append(g.toReduceResults, &internalpb.GetStatisticsResponse{
|
2023-10-11 21:01:35 +08:00
|
|
|
// Status: merr.Success(),
|
2022-07-18 09:58:28 +08:00
|
|
|
// Stats: result.Stats,
|
|
|
|
// })
|
|
|
|
// log.Debug("get partition statistics from DataCoord execute done", zap.Int64("msgID", g.ID()))
|
|
|
|
// return nil
|
|
|
|
// }
|
|
|
|
// return nil
|
|
|
|
//}
|
|
|
|
//
|
|
|
|
//func (g *getPartitionStatisticsTask) PostExecute(ctx context.Context) error {
|
|
|
|
// err := g.getStatisticsTask.PostExecute(ctx)
|
|
|
|
// if err != nil {
|
|
|
|
// return err
|
|
|
|
// }
|
|
|
|
// g.result = &milvuspb.GetPartitionStatisticsResponse{
|
2023-10-11 21:01:35 +08:00
|
|
|
// Status: merr.Success(),
|
2022-07-18 09:58:28 +08:00
|
|
|
// Stats: g.innerResult,
|
|
|
|
// }
|
|
|
|
// return nil
|
|
|
|
//}
|
|
|
|
//
|
|
|
|
//type getCollectionStatisticsTask struct {
|
|
|
|
// getStatisticsTask
|
|
|
|
// request *milvuspb.GetCollectionStatisticsRequest
|
|
|
|
// result *milvuspb.GetCollectionStatisticsResponse
|
|
|
|
//}
|
|
|
|
//
|
|
|
|
//func (g *getCollectionStatisticsTask) PreExecute(ctx context.Context) error {
|
|
|
|
// g.getStatisticsTask.DbID = 0
|
|
|
|
// g.getStatisticsTask.collectionName = g.request.GetCollectionName()
|
|
|
|
// g.getStatisticsTask.partitionNames = []string{}
|
|
|
|
// // g.TravelTimestamp = g.request.GetTravelTimestamp()
|
|
|
|
// // g.GuaranteeTimestamp = g.request.GetGuaranteeTimestamp()
|
|
|
|
// return g.getStatisticsTask.PreExecute(ctx)
|
|
|
|
//}
|
|
|
|
//
|
|
|
|
//func (g *getCollectionStatisticsTask) Execute(ctx context.Context) error {
|
|
|
|
// if g.fromQueryNode {
|
|
|
|
// // if you get entire collection, we need to pass partition ids param.
|
|
|
|
// if len(g.unloadedPartitionIDs) == 0 {
|
|
|
|
// g.GetStatisticsRequest.PartitionIDs = nil
|
|
|
|
// }
|
|
|
|
// err := g.getStatisticsTask.Execute(ctx)
|
|
|
|
// if err != nil {
|
|
|
|
// return err
|
|
|
|
// }
|
|
|
|
// log.Debug("get collection statistics from QueryNode execute done", zap.Int64("msgID", g.ID()))
|
|
|
|
// }
|
|
|
|
// if g.fromDataCoord {
|
|
|
|
// collID := g.CollectionID
|
|
|
|
// partIDs := g.unloadedPartitionIDs
|
|
|
|
//
|
|
|
|
// // all collection has not been loaded, get statistics from datacoord
|
|
|
|
// if len(g.GetStatisticsRequest.PartitionIDs) == 0 {
|
|
|
|
// req := &datapb.GetCollectionStatisticsRequest{
|
|
|
|
// Base: &commonpb.MsgBase{
|
|
|
|
// MsgType: commonpb.MsgType_GetCollectionStatistics,
|
|
|
|
// MsgID: g.Base.MsgID,
|
|
|
|
// Timestamp: g.Base.Timestamp,
|
|
|
|
// SourceID: g.Base.SourceID,
|
|
|
|
// },
|
|
|
|
// CollectionID: collID,
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// result, err := g.dc.GetCollectionStatistics(ctx, req)
|
|
|
|
// if err != nil {
|
|
|
|
// return err
|
|
|
|
// }
|
2023-09-12 16:07:18 +08:00
|
|
|
// if result.GetStatus().GetErrorCode() != commonpb.ErrorCode_Success {
|
2023-09-15 10:09:21 +08:00
|
|
|
// return merr.Error(result.GetStatus())
|
2022-07-18 09:58:28 +08:00
|
|
|
// }
|
|
|
|
// g.toReduceResults = append(g.toReduceResults, &internalpb.GetStatisticsResponse{
|
2023-10-11 21:01:35 +08:00
|
|
|
// Status: merr.Success(),
|
2022-07-18 09:58:28 +08:00
|
|
|
// Stats: result.Stats,
|
|
|
|
// })
|
|
|
|
// } else { // some partitions have been loaded, get some partition statistics from datacoord
|
|
|
|
// req := &datapb.GetPartitionStatisticsRequest{
|
|
|
|
// Base: &commonpb.MsgBase{
|
|
|
|
// MsgType: commonpb.MsgType_GetPartitionStatistics,
|
|
|
|
// MsgID: g.Base.MsgID,
|
|
|
|
// Timestamp: g.Base.Timestamp,
|
|
|
|
// SourceID: g.Base.SourceID,
|
|
|
|
// },
|
|
|
|
// CollectionID: collID,
|
|
|
|
// PartitionIDs: partIDs,
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// result, err := g.dc.GetPartitionStatistics(ctx, req)
|
|
|
|
// if err != nil {
|
|
|
|
// return err
|
|
|
|
// }
|
2023-09-12 16:07:18 +08:00
|
|
|
// if result.GetStatus().GetErrorCode() != commonpb.ErrorCode_Success {
|
2023-09-15 10:09:21 +08:00
|
|
|
// return merr.Error(result.GetStatus())
|
2022-07-18 09:58:28 +08:00
|
|
|
// }
|
|
|
|
// g.toReduceResults = append(g.toReduceResults, &internalpb.GetStatisticsResponse{
|
2023-10-11 21:01:35 +08:00
|
|
|
// Status: merr.Success(),
|
2022-07-18 09:58:28 +08:00
|
|
|
// Stats: result.Stats,
|
|
|
|
// })
|
|
|
|
// }
|
|
|
|
// log.Debug("get collection statistics from DataCoord execute done", zap.Int64("msgID", g.ID()))
|
|
|
|
// return nil
|
|
|
|
// }
|
|
|
|
// return nil
|
|
|
|
//}
|
|
|
|
//
|
|
|
|
//func (g *getCollectionStatisticsTask) PostExecute(ctx context.Context) error {
|
|
|
|
// err := g.getStatisticsTask.PostExecute(ctx)
|
|
|
|
// if err != nil {
|
|
|
|
// return err
|
|
|
|
// }
|
|
|
|
// g.result = &milvuspb.GetCollectionStatisticsResponse{
|
2023-10-11 21:01:35 +08:00
|
|
|
// Status: merr.Success(),
|
2022-07-18 09:58:28 +08:00
|
|
|
// Stats: g.innerResult,
|
|
|
|
// }
|
|
|
|
// return nil
|
|
|
|
//}
|
|
|
|
|
|
|
|
// old version of get statistics
|
|
|
|
// please remove it after getStatisticsTask below is stable
|
|
|
|
type getCollectionStatisticsTask struct {
|
|
|
|
Condition
|
|
|
|
*milvuspb.GetCollectionStatisticsRequest
|
|
|
|
ctx context.Context
|
2023-09-26 09:57:25 +08:00
|
|
|
dataCoord types.DataCoordClient
|
2022-07-18 09:58:28 +08:00
|
|
|
result *milvuspb.GetCollectionStatisticsResponse
|
|
|
|
|
|
|
|
collectionID UniqueID
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getCollectionStatisticsTask) TraceCtx() context.Context {
|
|
|
|
return g.ctx
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getCollectionStatisticsTask) ID() UniqueID {
|
|
|
|
return g.Base.MsgID
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getCollectionStatisticsTask) SetID(uid UniqueID) {
|
|
|
|
g.Base.MsgID = uid
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getCollectionStatisticsTask) Name() string {
|
|
|
|
return GetCollectionStatisticsTaskName
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getCollectionStatisticsTask) Type() commonpb.MsgType {
|
|
|
|
return g.Base.MsgType
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getCollectionStatisticsTask) BeginTs() Timestamp {
|
|
|
|
return g.Base.Timestamp
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getCollectionStatisticsTask) EndTs() Timestamp {
|
|
|
|
return g.Base.Timestamp
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getCollectionStatisticsTask) SetTs(ts Timestamp) {
|
|
|
|
g.Base.Timestamp = ts
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getCollectionStatisticsTask) OnEnqueue() error {
|
2022-10-19 10:01:26 +08:00
|
|
|
g.Base = commonpbutil.NewMsgBase()
|
2022-07-18 09:58:28 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getCollectionStatisticsTask) PreExecute(ctx context.Context) error {
|
|
|
|
g.Base.MsgType = commonpb.MsgType_GetCollectionStatistics
|
2022-11-04 14:25:38 +08:00
|
|
|
g.Base.SourceID = paramtable.GetNodeID()
|
2022-07-18 09:58:28 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getCollectionStatisticsTask) Execute(ctx context.Context) error {
|
2023-06-25 17:20:43 +08:00
|
|
|
collID, err := globalMetaCache.GetCollectionID(ctx, g.GetDbName(), g.CollectionName)
|
2022-07-18 09:58:28 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
g.collectionID = collID
|
|
|
|
req := &datapb.GetCollectionStatisticsRequest{
|
2022-10-21 15:57:28 +08:00
|
|
|
Base: commonpbutil.UpdateMsgBase(
|
2022-10-19 10:01:26 +08:00
|
|
|
g.Base,
|
|
|
|
commonpbutil.WithMsgType(commonpb.MsgType_GetCollectionStatistics),
|
|
|
|
),
|
2022-07-18 09:58:28 +08:00
|
|
|
CollectionID: collID,
|
|
|
|
}
|
|
|
|
|
2022-09-16 11:12:47 +08:00
|
|
|
result, err := g.dataCoord.GetCollectionStatistics(ctx, req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
2023-09-12 16:07:18 +08:00
|
|
|
if result.GetStatus().GetErrorCode() != commonpb.ErrorCode_Success {
|
2023-09-15 10:09:21 +08:00
|
|
|
return merr.Error(result.GetStatus())
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
|
|
|
g.result = &milvuspb.GetCollectionStatisticsResponse{
|
2023-10-11 21:01:35 +08:00
|
|
|
Status: merr.Success(),
|
2023-09-04 09:57:09 +08:00
|
|
|
Stats: result.Stats,
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getCollectionStatisticsTask) PostExecute(ctx context.Context) error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type getPartitionStatisticsTask struct {
|
|
|
|
Condition
|
|
|
|
*milvuspb.GetPartitionStatisticsRequest
|
|
|
|
ctx context.Context
|
2023-09-26 09:57:25 +08:00
|
|
|
dataCoord types.DataCoordClient
|
2022-07-18 09:58:28 +08:00
|
|
|
result *milvuspb.GetPartitionStatisticsResponse
|
|
|
|
|
|
|
|
collectionID UniqueID
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getPartitionStatisticsTask) TraceCtx() context.Context {
|
|
|
|
return g.ctx
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getPartitionStatisticsTask) ID() UniqueID {
|
|
|
|
return g.Base.MsgID
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getPartitionStatisticsTask) SetID(uid UniqueID) {
|
|
|
|
g.Base.MsgID = uid
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getPartitionStatisticsTask) Name() string {
|
|
|
|
return GetPartitionStatisticsTaskName
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getPartitionStatisticsTask) Type() commonpb.MsgType {
|
|
|
|
return g.Base.MsgType
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getPartitionStatisticsTask) BeginTs() Timestamp {
|
|
|
|
return g.Base.Timestamp
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getPartitionStatisticsTask) EndTs() Timestamp {
|
|
|
|
return g.Base.Timestamp
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getPartitionStatisticsTask) SetTs(ts Timestamp) {
|
|
|
|
g.Base.Timestamp = ts
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getPartitionStatisticsTask) OnEnqueue() error {
|
2022-10-19 10:01:26 +08:00
|
|
|
g.Base = commonpbutil.NewMsgBase()
|
2022-07-18 09:58:28 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getPartitionStatisticsTask) PreExecute(ctx context.Context) error {
|
|
|
|
g.Base.MsgType = commonpb.MsgType_GetPartitionStatistics
|
2022-11-04 14:25:38 +08:00
|
|
|
g.Base.SourceID = paramtable.GetNodeID()
|
2022-07-18 09:58:28 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getPartitionStatisticsTask) Execute(ctx context.Context) error {
|
2023-06-25 17:20:43 +08:00
|
|
|
collID, err := globalMetaCache.GetCollectionID(ctx, g.GetDbName(), g.CollectionName)
|
2022-07-18 09:58:28 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
g.collectionID = collID
|
2023-06-25 17:20:43 +08:00
|
|
|
partitionID, err := globalMetaCache.GetPartitionID(ctx, g.GetDbName(), g.CollectionName, g.PartitionName)
|
2022-07-18 09:58:28 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
req := &datapb.GetPartitionStatisticsRequest{
|
2022-10-21 15:57:28 +08:00
|
|
|
Base: commonpbutil.UpdateMsgBase(
|
2022-10-19 10:01:26 +08:00
|
|
|
g.Base,
|
|
|
|
commonpbutil.WithMsgType(commonpb.MsgType_GetCollectionStatistics),
|
|
|
|
),
|
2022-07-18 09:58:28 +08:00
|
|
|
CollectionID: collID,
|
|
|
|
PartitionIDs: []int64{partitionID},
|
|
|
|
}
|
|
|
|
|
|
|
|
result, _ := g.dataCoord.GetPartitionStatistics(ctx, req)
|
|
|
|
if result == nil {
|
|
|
|
return errors.New("get partition statistics resp is nil")
|
|
|
|
}
|
2023-09-12 16:07:18 +08:00
|
|
|
if result.GetStatus().GetErrorCode() != commonpb.ErrorCode_Success {
|
2023-09-15 10:09:21 +08:00
|
|
|
return merr.Error(result.GetStatus())
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
|
|
|
g.result = &milvuspb.GetPartitionStatisticsResponse{
|
2023-10-11 21:01:35 +08:00
|
|
|
Status: merr.Success(),
|
2023-09-04 09:57:09 +08:00
|
|
|
Stats: result.Stats,
|
2022-07-18 09:58:28 +08:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getPartitionStatisticsTask) PostExecute(ctx context.Context) error {
|
|
|
|
return nil
|
|
|
|
}
|