mirror of
https://gitee.com/milvus-io/milvus.git
synced 2024-12-01 11:29:48 +08:00
b3f6b67977
Signed-off-by: cai.zhang <cai.zhang@zilliz.com> Signed-off-by: cai.zhang <cai.zhang@zilliz.com>
303 lines
9.2 KiB
Go
303 lines
9.2 KiB
Go
// Licensed to the LF AI & Data foundation under one
|
|
// or more contributor license agreements. See the NOTICE file
|
|
// distributed with this work for additional information
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
// to you under the Apache License, Version 2.0 (the
|
|
// "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package indexcoord
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/milvus-io/milvus-proto/go-api/commonpb"
|
|
"github.com/milvus-io/milvus/internal/log"
|
|
"github.com/milvus-io/milvus/internal/metastore/model"
|
|
"github.com/milvus-io/milvus/internal/proto/datapb"
|
|
"github.com/milvus-io/milvus/internal/proto/indexpb"
|
|
"github.com/milvus-io/milvus/internal/proto/rootcoordpb"
|
|
"github.com/milvus-io/milvus/internal/types"
|
|
)
|
|
|
|
type task interface {
|
|
Ctx() context.Context
|
|
ID() UniqueID // return ReqID
|
|
SetID(uid UniqueID) // set ReqID
|
|
Name() string // set task name
|
|
PreExecute(ctx context.Context) error
|
|
Execute(ctx context.Context) error
|
|
PostExecute(ctx context.Context) error
|
|
WaitToFinish() error
|
|
Notify(err error) // notify if task is terminated
|
|
OnEnqueue() error
|
|
}
|
|
|
|
// BaseTask is an basic instance of task.
|
|
type BaseTask struct {
|
|
done chan error
|
|
ctx context.Context
|
|
id UniqueID
|
|
table *metaTable
|
|
}
|
|
|
|
// ID returns the id of index task.
|
|
func (bt *BaseTask) ID() UniqueID {
|
|
return bt.id
|
|
}
|
|
|
|
func (bt *BaseTask) setID(id UniqueID) {
|
|
bt.id = id
|
|
}
|
|
|
|
// WaitToFinish will wait for the task to complete, if the context is done,
|
|
// it means that the execution of the task has timed out.
|
|
func (bt *BaseTask) WaitToFinish() error {
|
|
select {
|
|
case <-bt.ctx.Done():
|
|
return errors.New("Task wait to finished timeout")
|
|
case err := <-bt.done:
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Notify will notify WaitToFinish that the task is completed or failed.
|
|
func (bt *BaseTask) Notify(err error) {
|
|
bt.done <- err
|
|
}
|
|
|
|
// CreateIndexTask is used to create an index on field.
|
|
type CreateIndexTask struct {
|
|
BaseTask
|
|
dataCoordClient types.DataCoord
|
|
rootCoordClient types.RootCoord
|
|
indexCoordClient *IndexCoord
|
|
req *indexpb.CreateIndexRequest
|
|
indexID UniqueID
|
|
}
|
|
|
|
// Ctx returns the context of the index task.
|
|
func (cit *CreateIndexTask) Ctx() context.Context {
|
|
return cit.ctx
|
|
}
|
|
|
|
// ID returns the id of the index task.
|
|
func (cit *CreateIndexTask) ID() UniqueID {
|
|
return cit.id
|
|
}
|
|
|
|
// SetID sets the id for index tasks.
|
|
func (cit *CreateIndexTask) SetID(ID UniqueID) {
|
|
cit.BaseTask.setID(ID)
|
|
}
|
|
|
|
// Name returns the task name.
|
|
func (cit *CreateIndexTask) Name() string {
|
|
return CreateIndexTaskName
|
|
}
|
|
|
|
// OnEnqueue assigns the indexBuildID to index task.
|
|
func (cit *CreateIndexTask) OnEnqueue() error {
|
|
resp, err := cit.rootCoordClient.AllocID(cit.Ctx(), &rootcoordpb.AllocIDRequest{
|
|
Count: 1,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if resp.Status.ErrorCode != commonpb.ErrorCode_Success {
|
|
return errors.New(resp.Status.Reason)
|
|
}
|
|
cit.indexID = resp.ID
|
|
return nil
|
|
}
|
|
|
|
// PreExecute do nothing.
|
|
func (cit *CreateIndexTask) PreExecute(ctx context.Context) error {
|
|
log.Info("IndexCoord CreateIndexTask PreExecute", zap.Int64("collectionID", cit.req.CollectionID),
|
|
zap.Int64("fieldID", cit.req.FieldID), zap.String("indexName", cit.req.IndexName))
|
|
// TODO: check index type is disk index.
|
|
if getIndexType(cit.req.GetIndexParams()) == diskAnnIndex && !cit.indexCoordClient.nodeManager.ClientSupportDisk() {
|
|
return errors.New("all IndexNodes do not support disk indexes, please verify")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Execute adds the index task to meta table.
|
|
func (cit *CreateIndexTask) Execute(ctx context.Context) error {
|
|
log.Info("IndexCoord CreateIndexTask Execute", zap.Int64("collectionID", cit.req.CollectionID),
|
|
zap.Int64("fieldID", cit.req.FieldID), zap.String("indexName", cit.req.IndexName))
|
|
hasIndex, indexID := cit.table.HasSameReq(cit.req)
|
|
if hasIndex {
|
|
cit.indexID = indexID
|
|
}
|
|
index := &model.Index{
|
|
CollectionID: cit.req.GetCollectionID(),
|
|
FieldID: cit.req.GetFieldID(),
|
|
IndexID: cit.indexID,
|
|
IndexName: cit.req.GetIndexName(),
|
|
TypeParams: cit.req.GetTypeParams(),
|
|
IndexParams: cit.req.GetIndexParams(),
|
|
CreateTime: cit.req.GetTimestamp(),
|
|
IsAutoIndex: cit.req.GetIsAutoIndex(),
|
|
UserIndexParams: cit.req.GetUserIndexParams(),
|
|
}
|
|
|
|
// Get flushed segments
|
|
flushedSegments, err := cit.dataCoordClient.GetFlushedSegments(cit.ctx, &datapb.GetFlushedSegmentsRequest{
|
|
Base: &commonpb.MsgBase{
|
|
MsgType: 0,
|
|
MsgID: cit.indexID,
|
|
Timestamp: cit.req.Timestamp,
|
|
SourceID: cit.indexCoordClient.serverID,
|
|
},
|
|
CollectionID: cit.req.CollectionID,
|
|
PartitionID: -1,
|
|
})
|
|
if err != nil {
|
|
log.Error("IndexCoord get flushed segments from datacoord fail", zap.Int64("collectionID", cit.req.CollectionID),
|
|
zap.Int64("fieldID", cit.req.FieldID), zap.String("indexName", cit.req.IndexName), zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
log.Debug("IndexCoord get flushed segment from DataCoord success", zap.Int64("collectionID", cit.req.CollectionID),
|
|
zap.Int64s("flushed segments", flushedSegments.Segments))
|
|
segmentsInfo, err := cit.dataCoordClient.GetSegmentInfo(cit.ctx, &datapb.GetSegmentInfoRequest{
|
|
SegmentIDs: flushedSegments.Segments,
|
|
IncludeUnHealthy: true,
|
|
})
|
|
|
|
if err != nil {
|
|
log.Error("IndexCoord get segment info from DataCoord fail", zap.Int64s("segIDs", flushedSegments.Segments),
|
|
zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
buildIDs := make([]UniqueID, 0)
|
|
segIDs := make([]UniqueID, 0)
|
|
for _, segmentInfo := range segmentsInfo.Infos {
|
|
if segmentInfo.State != commonpb.SegmentState_Flushed {
|
|
continue
|
|
}
|
|
|
|
segIdx := &model.SegmentIndex{
|
|
SegmentID: segmentInfo.ID,
|
|
CollectionID: segmentInfo.CollectionID,
|
|
PartitionID: segmentInfo.PartitionID,
|
|
NumRows: segmentInfo.NumOfRows,
|
|
IndexID: cit.indexID,
|
|
CreateTime: cit.req.GetTimestamp(),
|
|
}
|
|
have, buildID, err := cit.indexCoordClient.createIndexForSegment(segIdx)
|
|
if err != nil {
|
|
log.Error("IndexCoord create index on segment fail", zap.Int64("collectionID", cit.req.CollectionID),
|
|
zap.Int64("fieldID", cit.req.FieldID), zap.String("indexName", cit.req.IndexName),
|
|
zap.Int64("segmentID", segIdx.SegmentID), zap.Error(err))
|
|
return err
|
|
}
|
|
if have || buildID == 0 {
|
|
continue
|
|
}
|
|
segIDs = append(segIDs, segmentInfo.ID)
|
|
buildIDs = append(buildIDs, buildID)
|
|
}
|
|
|
|
err = cit.table.CreateIndex(index)
|
|
if err != nil {
|
|
log.Error("IndexCoord create index fail", zap.Int64("collectionID", cit.req.CollectionID),
|
|
zap.Int64("fieldID", cit.req.FieldID), zap.String("indexName", cit.req.IndexName), zap.Error(err))
|
|
return err
|
|
}
|
|
for _, buildID := range buildIDs {
|
|
cit.indexCoordClient.indexBuilder.enqueue(buildID)
|
|
}
|
|
for _, segID := range segIDs {
|
|
cit.indexCoordClient.handoff.enqueue(segID)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// PostExecute does nothing here.
|
|
func (cit *CreateIndexTask) PostExecute(ctx context.Context) error {
|
|
log.Info("IndexCoord CreateIndexTask PostExecute", zap.Int64("collectionID", cit.req.CollectionID),
|
|
zap.Int64("fieldID", cit.req.FieldID), zap.String("indexName", cit.req.IndexName))
|
|
return nil
|
|
}
|
|
|
|
// IndexAddTask is used to record index task on segment.
|
|
type IndexAddTask struct {
|
|
BaseTask
|
|
segmentIndex *model.SegmentIndex
|
|
rootcoordClient types.RootCoord
|
|
}
|
|
|
|
// Ctx returns the context of the index task.
|
|
func (it *IndexAddTask) Ctx() context.Context {
|
|
return it.ctx
|
|
}
|
|
|
|
// ID returns the id of the index task.
|
|
func (it *IndexAddTask) ID() UniqueID {
|
|
return it.id
|
|
}
|
|
|
|
// SetID sets the id for index tasks.
|
|
func (it *IndexAddTask) SetID(ID UniqueID) {
|
|
it.BaseTask.setID(ID)
|
|
}
|
|
|
|
// Name returns the task name.
|
|
func (it *IndexAddTask) Name() string {
|
|
return IndexAddTaskName
|
|
}
|
|
|
|
// OnEnqueue assigns the indexBuildID to index task.
|
|
func (it *IndexAddTask) OnEnqueue() error {
|
|
resp, err := it.rootcoordClient.AllocID(it.Ctx(), &rootcoordpb.AllocIDRequest{
|
|
Count: 1,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if resp.Status.ErrorCode != commonpb.ErrorCode_Success {
|
|
return errors.New(resp.Status.Reason)
|
|
}
|
|
it.segmentIndex.BuildID = resp.ID
|
|
return nil
|
|
}
|
|
|
|
// PreExecute sets the indexBuildID to index task request.
|
|
func (it *IndexAddTask) PreExecute(ctx context.Context) error {
|
|
log.Info("IndexCoord IndexAddTask PreExecute", zap.Int64("segID", it.segmentIndex.SegmentID),
|
|
zap.Int64("IndexBuildID", it.segmentIndex.BuildID))
|
|
return nil
|
|
}
|
|
|
|
// Execute adds the index task to meta table.
|
|
func (it *IndexAddTask) Execute(ctx context.Context) error {
|
|
log.Info("IndexCoord IndexAddTask Execute", zap.Int64("segID", it.segmentIndex.SegmentID),
|
|
zap.Int64("IndexBuildID", it.segmentIndex.BuildID))
|
|
err := it.table.AddIndex(it.segmentIndex)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// PostExecute does nothing here.
|
|
func (it *IndexAddTask) PostExecute(ctx context.Context) error {
|
|
log.Info("IndexCoord IndexAddTask PostExecute", zap.Int64("segID", it.segmentIndex.SegmentID),
|
|
zap.Int64("IndexBuildID", it.segmentIndex.BuildID))
|
|
return nil
|
|
}
|