mirror of
https://gitee.com/milvus-io/milvus.git
synced 2024-12-01 11:29:48 +08:00
bcffb3c389
Signed-off-by: cai.zhang <cai.zhang@zilliz.com> Signed-off-by: cai.zhang <cai.zhang@zilliz.com>
1286 lines
37 KiB
Go
1286 lines
37 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"
|
|
"fmt"
|
|
"math/rand"
|
|
"path"
|
|
"strconv"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/golang/protobuf/proto"
|
|
|
|
"github.com/milvus-io/milvus-proto/go-api/commonpb"
|
|
"github.com/milvus-io/milvus-proto/go-api/milvuspb"
|
|
"github.com/milvus-io/milvus/internal/common"
|
|
"github.com/milvus-io/milvus/internal/indexnode"
|
|
etcdkv "github.com/milvus-io/milvus/internal/kv/etcd"
|
|
"github.com/milvus-io/milvus/internal/metastore/kv/indexcoord"
|
|
"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/internalpb"
|
|
"github.com/milvus-io/milvus/internal/util"
|
|
"github.com/milvus-io/milvus/internal/util/dependency"
|
|
"github.com/milvus-io/milvus/internal/util/etcd"
|
|
"github.com/milvus-io/milvus/internal/util/metricsinfo"
|
|
"github.com/milvus-io/milvus/internal/util/sessionutil"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestMockEtcd(t *testing.T) {
|
|
Params.InitOnce()
|
|
Params.EtcdCfg.MetaRootPath = "indexcoord-mock"
|
|
|
|
etcdCli, err := etcd.GetEtcdClient(&Params.EtcdCfg)
|
|
assert.NoError(t, err)
|
|
etcdKV := etcdkv.NewEtcdKV(etcdCli, Params.EtcdCfg.MetaRootPath)
|
|
|
|
mockEtcd := NewMockEtcdKVWithReal(etcdKV)
|
|
key := "foo"
|
|
value := "foo-val"
|
|
err = mockEtcd.Save(key, value)
|
|
assert.NoError(t, err)
|
|
|
|
fmt.Println(mockEtcd == nil)
|
|
loadVal, err := mockEtcd.Load(key)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, value, loadVal)
|
|
|
|
_, _, err = mockEtcd.LoadWithPrefix(key)
|
|
assert.NoError(t, err)
|
|
|
|
_, _, _, err = mockEtcd.LoadWithPrefix2(key)
|
|
assert.NoError(t, err)
|
|
|
|
_, _, _, err = mockEtcd.LoadWithRevision(key)
|
|
assert.NoError(t, err)
|
|
|
|
_, _, _, _, err = mockEtcd.LoadWithRevisionAndVersions(key)
|
|
assert.NoError(t, err)
|
|
|
|
err = mockEtcd.MultiSave(map[string]string{
|
|
"TestMockEtcd-1": "mock-val",
|
|
"TestMockEtcd-2": "mock-val",
|
|
})
|
|
assert.NoError(t, err)
|
|
|
|
err = mockEtcd.RemoveWithPrefix("TestMockEtcd-")
|
|
assert.NoError(t, err)
|
|
|
|
err = mockEtcd.Remove(key)
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
func testIndexCoord(t *testing.T) {
|
|
ctx := context.Background()
|
|
Params.EtcdCfg.MetaRootPath = "indexcoord-ut"
|
|
|
|
// first start an IndexNode
|
|
inm0 := indexnode.NewIndexNodeMock()
|
|
etcdCli, err := etcd.GetEtcdClient(&Params.EtcdCfg)
|
|
assert.NoError(t, err)
|
|
|
|
// start IndexCoord
|
|
factory := dependency.NewDefaultFactory(true)
|
|
ic, err := NewIndexCoord(ctx, factory)
|
|
assert.NoError(t, err)
|
|
|
|
rcm := NewRootCoordMock()
|
|
err = ic.SetRootCoord(rcm)
|
|
assert.NoError(t, err)
|
|
|
|
dcm := &DataCoordMock{
|
|
CallGetSegmentInfo: func(ctx context.Context, req *datapb.GetSegmentInfoRequest) (*datapb.GetSegmentInfoResponse, error) {
|
|
segmentInfos := make([]*datapb.SegmentInfo, 0)
|
|
for _, segID := range req.SegmentIDs {
|
|
segmentInfos = append(segmentInfos, &datapb.SegmentInfo{
|
|
ID: segID,
|
|
CollectionID: collID,
|
|
PartitionID: partID,
|
|
NumOfRows: 10240,
|
|
State: commonpb.SegmentState_Flushed,
|
|
StartPosition: &internalpb.MsgPosition{
|
|
Timestamp: createTs,
|
|
},
|
|
Binlogs: []*datapb.FieldBinlog{
|
|
{
|
|
FieldID: fieldID,
|
|
Binlogs: []*datapb.Binlog{
|
|
{
|
|
LogPath: "file1",
|
|
},
|
|
{
|
|
LogPath: "file2",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
return &datapb.GetSegmentInfoResponse{
|
|
Status: &commonpb.Status{
|
|
ErrorCode: commonpb.ErrorCode_Success,
|
|
},
|
|
Infos: segmentInfos,
|
|
}, nil
|
|
},
|
|
CallGetFlushedSegment: func(ctx context.Context, req *datapb.GetFlushedSegmentsRequest) (*datapb.GetFlushedSegmentsResponse, error) {
|
|
return &datapb.GetFlushedSegmentsResponse{
|
|
Status: &commonpb.Status{
|
|
ErrorCode: commonpb.ErrorCode_Success,
|
|
},
|
|
Segments: []int64{segID},
|
|
}, nil
|
|
},
|
|
CallAcquireSegmentLock: func(ctx context.Context, req *datapb.AcquireSegmentLockRequest) (*commonpb.Status, error) {
|
|
return &commonpb.Status{
|
|
ErrorCode: commonpb.ErrorCode_Success,
|
|
}, nil
|
|
},
|
|
CallReleaseSegmentLock: func(ctx context.Context, req *datapb.ReleaseSegmentLockRequest) (*commonpb.Status, error) {
|
|
return &commonpb.Status{
|
|
ErrorCode: commonpb.ErrorCode_Success,
|
|
}, nil
|
|
},
|
|
}
|
|
err = ic.SetDataCoord(dcm)
|
|
assert.Nil(t, err)
|
|
|
|
ic.SetEtcdClient(etcdCli)
|
|
|
|
err = ic.Init()
|
|
assert.NoError(t, err)
|
|
|
|
mockKv := NewMockEtcdKVWithReal(ic.etcdKV)
|
|
ic.metaTable.catalog = &indexcoord.Catalog{
|
|
Txn: mockKv,
|
|
}
|
|
assert.NoError(t, err)
|
|
|
|
err = ic.Register()
|
|
assert.NoError(t, err)
|
|
|
|
err = ic.Start()
|
|
assert.NoError(t, err)
|
|
|
|
ic.UpdateStateCode(commonpb.StateCode_Healthy)
|
|
|
|
ic.nodeManager.setClient(1, inm0)
|
|
|
|
// Test IndexCoord function
|
|
t.Run("GetComponentStates", func(t *testing.T) {
|
|
states, err := ic.GetComponentStates(ctx)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.StateCode_Healthy, states.State.StateCode)
|
|
})
|
|
|
|
t.Run("GetStatisticsChannel", func(t *testing.T) {
|
|
resp, err := ic.GetStatisticsChannel(ctx)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_Success, resp.Status.ErrorCode)
|
|
})
|
|
|
|
t.Run("CreateIndex", func(t *testing.T) {
|
|
req := &indexpb.CreateIndexRequest{
|
|
CollectionID: collID,
|
|
FieldID: fieldID,
|
|
IndexName: indexName,
|
|
Timestamp: createTs,
|
|
}
|
|
resp, err := ic.CreateIndex(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_Success, resp.ErrorCode)
|
|
})
|
|
|
|
t.Run("GetIndexState", func(t *testing.T) {
|
|
req := &indexpb.GetIndexStateRequest{
|
|
CollectionID: collID,
|
|
IndexName: indexName,
|
|
}
|
|
resp, err := ic.GetIndexState(ctx, req)
|
|
assert.NoError(t, err)
|
|
for resp.State != commonpb.IndexState_Finished {
|
|
resp, err = ic.GetIndexState(ctx, req)
|
|
assert.NoError(t, err)
|
|
time.Sleep(time.Second)
|
|
}
|
|
})
|
|
|
|
t.Run("GetSegmentIndexState", func(t *testing.T) {
|
|
req := &indexpb.GetSegmentIndexStateRequest{
|
|
CollectionID: collID,
|
|
IndexName: indexName,
|
|
SegmentIDs: []UniqueID{segID},
|
|
}
|
|
resp, err := ic.GetSegmentIndexState(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, len(req.SegmentIDs), len(resp.States))
|
|
})
|
|
|
|
t.Run("GetIndexInfos", func(t *testing.T) {
|
|
req := &indexpb.GetIndexInfoRequest{
|
|
CollectionID: collID,
|
|
SegmentIDs: []UniqueID{segID},
|
|
IndexName: indexName,
|
|
}
|
|
resp, err := ic.GetIndexInfos(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, len(req.SegmentIDs), len(resp.SegmentInfo))
|
|
})
|
|
|
|
getReq := func() *indexpb.DescribeIndexRequest {
|
|
return &indexpb.DescribeIndexRequest{
|
|
CollectionID: collID,
|
|
IndexName: indexName,
|
|
}
|
|
}
|
|
|
|
t.Run("DescribeIndex NotExist", func(t *testing.T) {
|
|
indexs := ic.metaTable.collectionIndexes
|
|
ic.metaTable.collectionIndexes = make(map[UniqueID]map[UniqueID]*model.Index)
|
|
defer func() {
|
|
fmt.Println("simfg fubang")
|
|
ic.metaTable.collectionIndexes = indexs
|
|
}()
|
|
|
|
resp, err := ic.DescribeIndex(ctx, getReq())
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, resp.Status.ErrorCode, commonpb.ErrorCode_IndexNotExist)
|
|
})
|
|
|
|
t.Run("DescribeIndex State", func(t *testing.T) {
|
|
req := getReq()
|
|
res := ic.metaTable.GetIndexIDByName(collID, indexName)
|
|
var indexIDTest int64
|
|
for k := range res {
|
|
indexIDTest = k
|
|
break
|
|
}
|
|
|
|
indexs := ic.metaTable.segmentIndexes
|
|
mockIndexs := make(map[UniqueID]map[UniqueID]*model.SegmentIndex)
|
|
progressIndex := &model.SegmentIndex{
|
|
IndexState: commonpb.IndexState_InProgress,
|
|
}
|
|
failedIndex := &model.SegmentIndex{
|
|
IndexState: commonpb.IndexState_Failed,
|
|
SegmentID: 333,
|
|
FailReason: "mock fail",
|
|
}
|
|
finishedIndex := &model.SegmentIndex{
|
|
IndexState: commonpb.IndexState_Finished,
|
|
NumRows: 2048,
|
|
}
|
|
ic.metaTable.segmentIndexes = mockIndexs
|
|
defer func() {
|
|
ic.metaTable.segmentIndexes = indexs
|
|
}()
|
|
|
|
mockIndexs[111] = make(map[UniqueID]*model.SegmentIndex)
|
|
mockIndexs[111][indexIDTest] = finishedIndex
|
|
|
|
resp, err := ic.DescribeIndex(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_Success, resp.Status.ErrorCode)
|
|
assert.Equal(t, commonpb.IndexState_Finished, resp.IndexInfos[0].State)
|
|
|
|
originFunc1 := dcm.CallGetFlushedSegment
|
|
originFunc2 := dcm.CallGetSegmentInfo
|
|
defer func() {
|
|
dcm.CallGetFlushedSegment = originFunc1
|
|
dcm.SetFunc(func() {
|
|
dcm.CallGetSegmentInfo = originFunc2
|
|
})
|
|
}()
|
|
dcm.CallGetFlushedSegment = func(ctx context.Context, req *datapb.GetFlushedSegmentsRequest) (*datapb.GetFlushedSegmentsResponse, error) {
|
|
return nil, errors.New("mock error")
|
|
}
|
|
|
|
mockIndexs[222] = make(map[UniqueID]*model.SegmentIndex)
|
|
mockIndexs[222][indexIDTest] = progressIndex
|
|
resp, err = ic.DescribeIndex(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.Status.ErrorCode)
|
|
|
|
dcm.CallGetFlushedSegment = func(ctx context.Context, req *datapb.GetFlushedSegmentsRequest) (*datapb.GetFlushedSegmentsResponse, error) {
|
|
return &datapb.GetFlushedSegmentsResponse{
|
|
Segments: []int64{111, 222, 333},
|
|
}, nil
|
|
}
|
|
dcm.SetFunc(func() {
|
|
dcm.CallGetSegmentInfo = func(ctx context.Context, req *datapb.GetSegmentInfoRequest) (*datapb.GetSegmentInfoResponse, error) {
|
|
return nil, errors.New("mock error")
|
|
}
|
|
})
|
|
resp, err = ic.DescribeIndex(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.Status.ErrorCode)
|
|
|
|
dcm.SetFunc(func() {
|
|
dcm.CallGetSegmentInfo = func(ctx context.Context, req *datapb.GetSegmentInfoRequest) (*datapb.GetSegmentInfoResponse, error) {
|
|
return &datapb.GetSegmentInfoResponse{
|
|
Infos: []*datapb.SegmentInfo{
|
|
{State: commonpb.SegmentState_Flushed, NumOfRows: 2048},
|
|
{State: commonpb.SegmentState_Flushed, NumOfRows: 2048},
|
|
{State: commonpb.SegmentState_Flushed, NumOfRows: 2048},
|
|
},
|
|
}, nil
|
|
}
|
|
})
|
|
resp, err = ic.DescribeIndex(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_Success, resp.Status.ErrorCode)
|
|
assert.Equal(t, commonpb.IndexState_InProgress, resp.IndexInfos[0].State)
|
|
assert.Equal(t, int64(2048), resp.IndexInfos[0].IndexedRows)
|
|
assert.Equal(t, int64(2048*3), resp.IndexInfos[0].TotalRows)
|
|
|
|
mockIndexs[333] = make(map[UniqueID]*model.SegmentIndex)
|
|
mockIndexs[333][indexIDTest] = failedIndex
|
|
resp, err = ic.DescribeIndex(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_Success, resp.Status.ErrorCode)
|
|
assert.Equal(t, commonpb.IndexState_Failed, resp.IndexInfos[0].State)
|
|
})
|
|
|
|
t.Run("DescribeIndex", func(t *testing.T) {
|
|
req := &indexpb.DescribeIndexRequest{
|
|
CollectionID: collID,
|
|
IndexName: indexName,
|
|
}
|
|
resp, err := ic.DescribeIndex(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 1, len(resp.IndexInfos))
|
|
})
|
|
|
|
t.Run("FlushedSegmentWatcher", func(t *testing.T) {
|
|
segmentID := segID + 1
|
|
|
|
segment := &datapb.SegmentInfo{ID: segID}
|
|
segBytes, err := proto.Marshal(segment)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
err = ic.etcdKV.Save(path.Join(util.FlushedSegmentPrefix, strconv.FormatInt(collID, 10), strconv.FormatInt(partID, 10), strconv.FormatInt(segmentID, 10)), string(segBytes))
|
|
assert.NoError(t, err)
|
|
|
|
req := &indexpb.GetSegmentIndexStateRequest{
|
|
CollectionID: collID,
|
|
IndexName: indexName,
|
|
SegmentIDs: []UniqueID{segmentID},
|
|
}
|
|
resp, err := ic.GetSegmentIndexState(ctx, req)
|
|
assert.NoError(t, err)
|
|
for len(resp.States) != 1 || resp.States[0].State != commonpb.IndexState_Finished {
|
|
resp, err = ic.GetSegmentIndexState(ctx, req)
|
|
assert.NoError(t, err)
|
|
time.Sleep(time.Second)
|
|
}
|
|
})
|
|
|
|
t.Run("FlushedSegmentWatcher backward compatibility testing", func(t *testing.T) {
|
|
segmentID := segID + 2
|
|
err = ic.etcdKV.Save(path.Join(util.FlushedSegmentPrefix, strconv.FormatInt(collID, 10), strconv.FormatInt(partID, 10), strconv.FormatInt(segmentID, 10)), strconv.FormatInt(segmentID, 10))
|
|
assert.NoError(t, err)
|
|
|
|
req := &indexpb.GetSegmentIndexStateRequest{
|
|
CollectionID: collID,
|
|
IndexName: indexName,
|
|
SegmentIDs: []UniqueID{segmentID},
|
|
}
|
|
resp, err := ic.GetSegmentIndexState(ctx, req)
|
|
assert.NoError(t, err)
|
|
for len(resp.States) != 1 || resp.States[0].State != commonpb.IndexState_Finished {
|
|
resp, err = ic.GetSegmentIndexState(ctx, req)
|
|
assert.NoError(t, err)
|
|
time.Sleep(time.Second)
|
|
}
|
|
})
|
|
|
|
t.Run("Showconfigurations, port", func(t *testing.T) {
|
|
pattern := "Port"
|
|
req := &internalpb.ShowConfigurationsRequest{
|
|
Base: &commonpb.MsgBase{
|
|
MsgType: commonpb.MsgType_WatchQueryChannels,
|
|
MsgID: rand.Int63(),
|
|
},
|
|
Pattern: pattern,
|
|
}
|
|
|
|
resp, err := ic.ShowConfigurations(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_Success, resp.Status.ErrorCode)
|
|
assert.Equal(t, 1, len(resp.Configuations))
|
|
assert.Equal(t, "indexcoord.port", resp.Configuations[0].Key)
|
|
})
|
|
|
|
t.Run("GetIndexBuildProgress", func(t *testing.T) {
|
|
req := &indexpb.GetIndexBuildProgressRequest{
|
|
CollectionID: collID,
|
|
IndexName: indexName,
|
|
}
|
|
resp, err := ic.GetIndexBuildProgress(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_Success, resp.Status.ErrorCode)
|
|
})
|
|
|
|
t.Run("DropIndex", func(t *testing.T) {
|
|
req := &indexpb.DropIndexRequest{
|
|
CollectionID: collID,
|
|
PartitionIDs: nil,
|
|
IndexName: indexName,
|
|
DropAll: false,
|
|
}
|
|
resp, err := ic.DropIndex(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_Success, resp.ErrorCode)
|
|
})
|
|
|
|
t.Run("GetMetrics", func(t *testing.T) {
|
|
req, err := metricsinfo.ConstructRequestByMetricType(metricsinfo.SystemInfoMetrics)
|
|
assert.NoError(t, err)
|
|
resp, err := ic.GetMetrics(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_Success, resp.Status.ErrorCode)
|
|
})
|
|
|
|
// Stop IndexCoord
|
|
err = ic.Stop()
|
|
assert.NoError(t, err)
|
|
|
|
etcdKV := etcdkv.NewEtcdKV(etcdCli, Params.EtcdCfg.MetaRootPath)
|
|
err = etcdKV.RemoveWithPrefix("")
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestIndexCoord_DisableActiveStandby(t *testing.T) {
|
|
Params.InitOnce()
|
|
Params.IndexCoordCfg.EnableActiveStandby = false
|
|
testIndexCoord(t)
|
|
}
|
|
|
|
// make sure the main functions work well when EnableActiveStandby=true
|
|
func TestIndexCoord_EnableActiveStandby(t *testing.T) {
|
|
Params.InitOnce()
|
|
Params.IndexCoordCfg.EnableActiveStandby = true
|
|
testIndexCoord(t)
|
|
}
|
|
|
|
func TestIndexCoord_GetComponentStates(t *testing.T) {
|
|
ic := &IndexCoord{}
|
|
ic.stateCode.Store(commonpb.StateCode_Healthy)
|
|
resp, err := ic.GetComponentStates(context.Background())
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_Success, resp.Status.ErrorCode)
|
|
assert.Equal(t, common.NotRegisteredID, resp.State.NodeID)
|
|
|
|
ic.session = &sessionutil.Session{}
|
|
ic.session.UpdateRegistered(true)
|
|
resp, err = ic.GetComponentStates(context.Background())
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_Success, resp.Status.ErrorCode)
|
|
}
|
|
|
|
func TestIndexCoord_UnHealthy(t *testing.T) {
|
|
ctx := context.Background()
|
|
ic := &IndexCoord{
|
|
serverID: 1,
|
|
}
|
|
ic.stateCode.Store(commonpb.StateCode_Abnormal)
|
|
|
|
// Test IndexCoord function
|
|
t.Run("CreateIndex", func(t *testing.T) {
|
|
req := &indexpb.CreateIndexRequest{
|
|
CollectionID: collID,
|
|
FieldID: fieldID,
|
|
IndexName: indexName,
|
|
}
|
|
resp, err := ic.CreateIndex(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_UnexpectedError, resp.ErrorCode)
|
|
})
|
|
|
|
t.Run("GetIndexState", func(t *testing.T) {
|
|
req := &indexpb.GetIndexStateRequest{
|
|
CollectionID: collID,
|
|
IndexName: indexName,
|
|
}
|
|
resp, err := ic.GetIndexState(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_UnexpectedError, resp.Status.ErrorCode)
|
|
})
|
|
|
|
t.Run("GetSegmentIndexState", func(t *testing.T) {
|
|
req := &indexpb.GetSegmentIndexStateRequest{
|
|
CollectionID: collID,
|
|
IndexName: indexName,
|
|
SegmentIDs: []UniqueID{segID},
|
|
}
|
|
resp, err := ic.GetSegmentIndexState(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_UnexpectedError, resp.Status.ErrorCode)
|
|
})
|
|
|
|
t.Run("GetIndexInfos", func(t *testing.T) {
|
|
req := &indexpb.GetIndexInfoRequest{
|
|
CollectionID: collID,
|
|
SegmentIDs: []UniqueID{segID},
|
|
IndexName: indexName,
|
|
}
|
|
resp, err := ic.GetIndexInfos(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_UnexpectedError, resp.Status.ErrorCode)
|
|
})
|
|
|
|
t.Run("DescribeIndex", func(t *testing.T) {
|
|
req := &indexpb.DescribeIndexRequest{
|
|
CollectionID: collID,
|
|
IndexName: indexName,
|
|
}
|
|
resp, err := ic.DescribeIndex(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_UnexpectedError, resp.Status.ErrorCode)
|
|
})
|
|
|
|
t.Run("GetIndexBuildProgress", func(t *testing.T) {
|
|
req := &indexpb.GetIndexBuildProgressRequest{
|
|
CollectionID: collID,
|
|
IndexName: indexName,
|
|
}
|
|
resp, err := ic.GetIndexBuildProgress(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_UnexpectedError, resp.Status.ErrorCode)
|
|
})
|
|
|
|
t.Run("DropIndex", func(t *testing.T) {
|
|
req := &indexpb.DropIndexRequest{
|
|
CollectionID: collID,
|
|
IndexName: indexName,
|
|
}
|
|
resp, err := ic.DropIndex(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_UnexpectedError, resp.ErrorCode)
|
|
})
|
|
|
|
t.Run("ShowConfigurations when indexcoord is not healthy", func(t *testing.T) {
|
|
pattern := ""
|
|
req := &internalpb.ShowConfigurationsRequest{
|
|
Base: &commonpb.MsgBase{
|
|
MsgType: commonpb.MsgType_WatchQueryChannels,
|
|
MsgID: rand.Int63(),
|
|
},
|
|
Pattern: pattern,
|
|
}
|
|
|
|
resp, err := ic.ShowConfigurations(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_UnexpectedError, resp.Status.ErrorCode)
|
|
})
|
|
|
|
t.Run("GetMetrics", func(t *testing.T) {
|
|
req, err := metricsinfo.ConstructRequestByMetricType(metricsinfo.SystemInfoMetrics)
|
|
assert.NoError(t, err)
|
|
resp, err := ic.GetMetrics(ctx, req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_UnexpectedError, resp.Status.ErrorCode)
|
|
})
|
|
|
|
}
|
|
|
|
func TestIndexCoord_DropIndex(t *testing.T) {
|
|
t.Run("success", func(t *testing.T) {
|
|
ic := &IndexCoord{
|
|
metaTable: constructMetaTable(&indexcoord.Catalog{
|
|
Txn: &mockETCDKV{
|
|
multiSave: func(m map[string]string) error {
|
|
return nil
|
|
},
|
|
},
|
|
}),
|
|
}
|
|
ic.UpdateStateCode(commonpb.StateCode_Healthy)
|
|
resp, err := ic.DropIndex(context.Background(), &indexpb.DropIndexRequest{
|
|
CollectionID: collID,
|
|
PartitionIDs: []int64{partID},
|
|
IndexName: indexName,
|
|
DropAll: false,
|
|
})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_Success, resp.GetErrorCode())
|
|
|
|
resp, err = ic.DropIndex(context.Background(), &indexpb.DropIndexRequest{
|
|
CollectionID: collID,
|
|
PartitionIDs: []int64{partID},
|
|
IndexName: indexName,
|
|
DropAll: false,
|
|
})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_Success, resp.GetErrorCode())
|
|
|
|
resp, err = ic.DropIndex(context.Background(), &indexpb.DropIndexRequest{
|
|
CollectionID: collID,
|
|
PartitionIDs: nil,
|
|
IndexName: indexName,
|
|
DropAll: false,
|
|
})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_Success, resp.GetErrorCode())
|
|
|
|
resp, err = ic.DropIndex(context.Background(), &indexpb.DropIndexRequest{
|
|
CollectionID: collID,
|
|
PartitionIDs: nil,
|
|
IndexName: indexName,
|
|
DropAll: false,
|
|
})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_Success, resp.GetErrorCode())
|
|
})
|
|
|
|
t.Run("fail", func(t *testing.T) {
|
|
ic := &IndexCoord{
|
|
metaTable: constructMetaTable(&indexcoord.Catalog{
|
|
Txn: &mockETCDKV{
|
|
multiSave: func(m map[string]string) error {
|
|
return errors.New("error")
|
|
},
|
|
},
|
|
}),
|
|
}
|
|
ic.UpdateStateCode(commonpb.StateCode_Healthy)
|
|
|
|
resp, err := ic.DropIndex(context.Background(), &indexpb.DropIndexRequest{
|
|
CollectionID: collID,
|
|
PartitionIDs: []int64{partID},
|
|
IndexName: indexName,
|
|
DropAll: false,
|
|
})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_UnexpectedError, resp.GetErrorCode())
|
|
|
|
resp, err = ic.DropIndex(context.Background(), &indexpb.DropIndexRequest{
|
|
CollectionID: collID,
|
|
PartitionIDs: nil,
|
|
IndexName: indexName,
|
|
DropAll: false,
|
|
})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_UnexpectedError, resp.GetErrorCode())
|
|
})
|
|
|
|
t.Run("multiple index but no index name", func(t *testing.T) {
|
|
ic := &IndexCoord{
|
|
metaTable: &metaTable{
|
|
catalog: &indexcoord.Catalog{Txn: NewMockEtcdKV()},
|
|
indexLock: sync.RWMutex{},
|
|
segmentIndexLock: sync.RWMutex{},
|
|
collectionIndexes: map[UniqueID]map[UniqueID]*model.Index{
|
|
collID: {
|
|
indexID: {
|
|
TenantID: "",
|
|
CollectionID: collID,
|
|
FieldID: fieldID,
|
|
IndexID: indexID,
|
|
IndexName: indexName,
|
|
IsDeleted: false,
|
|
CreateTime: 10,
|
|
TypeParams: nil,
|
|
IndexParams: nil,
|
|
IsAutoIndex: false,
|
|
UserIndexParams: nil,
|
|
},
|
|
indexID + 1: {
|
|
TenantID: "",
|
|
CollectionID: collID,
|
|
FieldID: fieldID + 1,
|
|
IndexID: indexID + 1,
|
|
IndexName: indexName + "1",
|
|
IsDeleted: false,
|
|
CreateTime: 20,
|
|
TypeParams: nil,
|
|
IndexParams: nil,
|
|
IsAutoIndex: false,
|
|
UserIndexParams: nil,
|
|
},
|
|
},
|
|
},
|
|
segmentIndexes: nil,
|
|
buildID2SegmentIndex: nil,
|
|
},
|
|
}
|
|
ic.UpdateStateCode(commonpb.StateCode_Healthy)
|
|
resp, err := ic.DropIndex(context.Background(), &indexpb.DropIndexRequest{
|
|
CollectionID: collID,
|
|
PartitionIDs: []int64{partID},
|
|
IndexName: "",
|
|
DropAll: false,
|
|
})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_UnexpectedError, resp.GetErrorCode())
|
|
})
|
|
}
|
|
|
|
// TODO @xiaocai2333: add ut for error occurred.
|
|
|
|
//func TestIndexCoord_watchNodeLoop(t *testing.T) {
|
|
// ech := make(chan *sessionutil.SessionEvent)
|
|
// in := &IndexCoord{
|
|
// loopWg: sync.WaitGroup{},
|
|
// loopCtx: context.Background(),
|
|
// eventChan: ech,
|
|
// session: &sessionutil.Session{
|
|
// TriggerKill: true,
|
|
// ServerID: 0,
|
|
// },
|
|
// }
|
|
// in.loopWg.Add(1)
|
|
//
|
|
// flag := false
|
|
// closed := false
|
|
// sigDone := make(chan struct{}, 1)
|
|
// sigQuit := make(chan struct{}, 1)
|
|
// sc := make(chan os.Signal, 1)
|
|
// signal.Notify(sc, syscall.SIGINT)
|
|
// defer signal.Reset(syscall.SIGINT)
|
|
//
|
|
// go func() {
|
|
// in.watchNodeLoop()
|
|
// flag = true
|
|
// sigDone <- struct{}{}
|
|
// }()
|
|
// go func() {
|
|
// <-sc
|
|
// closed = true
|
|
// sigQuit <- struct{}{}
|
|
// }()
|
|
//
|
|
// close(ech)
|
|
// <-sigDone
|
|
// <-sigQuit
|
|
// assert.True(t, flag)
|
|
// assert.True(t, closed)
|
|
//}
|
|
//
|
|
//func TestIndexCoord_watchMetaLoop(t *testing.T) {
|
|
// ctx, cancel := context.WithCancel(context.Background())
|
|
// ic := &IndexCoord{
|
|
// loopCtx: ctx,
|
|
// loopWg: sync.WaitGroup{},
|
|
// }
|
|
//
|
|
// watchChan := make(chan clientv3.WatchResponse, 1024)
|
|
//
|
|
// client := &mockETCDKV{
|
|
// watchWithRevision: func(s string, i int64) clientv3.WatchChan {
|
|
// return watchChan
|
|
// },
|
|
// }
|
|
// mt := &metaTable{
|
|
// client: client,
|
|
// indexBuildID2Meta: map[UniqueID]*Meta{},
|
|
// etcdRevision: 0,
|
|
// lock: sync.RWMutex{},
|
|
// }
|
|
// ic.metaTable = mt
|
|
//
|
|
// t.Run("watch chan panic", func(t *testing.T) {
|
|
// ic.loopWg.Add(1)
|
|
// watchChan <- clientv3.WatchResponse{Canceled: true}
|
|
//
|
|
// assert.Panics(t, func() {
|
|
// ic.watchMetaLoop()
|
|
// })
|
|
// ic.loopWg.Wait()
|
|
// })
|
|
//
|
|
// t.Run("watch chan new meta table panic", func(t *testing.T) {
|
|
// client = &mockETCDKV{
|
|
// watchWithRevision: func(s string, i int64) clientv3.WatchChan {
|
|
// return watchChan
|
|
// },
|
|
// loadWithRevisionAndVersions: func(s string) ([]string, []string, []int64, int64, error) {
|
|
// return []string{}, []string{}, []int64{}, 0, fmt.Errorf("error occurred")
|
|
// },
|
|
// }
|
|
// mt = &metaTable{
|
|
// client: client,
|
|
// indexBuildID2Meta: map[UniqueID]*Meta{},
|
|
// etcdRevision: 0,
|
|
// lock: sync.RWMutex{},
|
|
// }
|
|
// ic.metaTable = mt
|
|
// ic.loopWg.Add(1)
|
|
// watchChan <- clientv3.WatchResponse{CompactRevision: 10}
|
|
// assert.Panics(t, func() {
|
|
// ic.watchMetaLoop()
|
|
// })
|
|
// ic.loopWg.Wait()
|
|
// })
|
|
//
|
|
// t.Run("watch chan new meta success", func(t *testing.T) {
|
|
// ic.loopWg = sync.WaitGroup{}
|
|
// client = &mockETCDKV{
|
|
// watchWithRevision: func(s string, i int64) clientv3.WatchChan {
|
|
// return watchChan
|
|
// },
|
|
// loadWithRevisionAndVersions: func(s string) ([]string, []string, []int64, int64, error) {
|
|
// return []string{}, []string{}, []int64{}, 0, nil
|
|
// },
|
|
// }
|
|
// mt = &metaTable{
|
|
// client: client,
|
|
// indexBuildID2Meta: map[UniqueID]*Meta{},
|
|
// etcdRevision: 0,
|
|
// lock: sync.RWMutex{},
|
|
// }
|
|
// ic.metaTable = mt
|
|
// ic.loopWg.Add(1)
|
|
// watchChan <- clientv3.WatchResponse{CompactRevision: 10}
|
|
// go ic.watchMetaLoop()
|
|
// cancel()
|
|
// ic.loopWg.Wait()
|
|
// })
|
|
//}
|
|
//
|
|
//func TestIndexCoord_GetComponentStates(t *testing.T) {
|
|
// n := &IndexCoord{}
|
|
// n.stateCode.Store(commonpb.StateCode_Healthy)
|
|
// resp, err := n.GetComponentStates(context.Background())
|
|
// assert.NoError(t, err)
|
|
// assert.Equal(t, commonpb.ErrorCode_Success, resp.Status.ErrorCode)
|
|
// assert.Equal(t, common.NotRegisteredID, resp.State.NodeID)
|
|
// n.session = &sessionutil.Session{}
|
|
// n.session.UpdateRegistered(true)
|
|
// resp, err = n.GetComponentStates(context.Background())
|
|
// assert.NoError(t, err)
|
|
// assert.Equal(t, commonpb.ErrorCode_Success, resp.Status.ErrorCode)
|
|
//}
|
|
//
|
|
//func TestIndexCoord_NotHealthy(t *testing.T) {
|
|
// ic := &IndexCoord{}
|
|
// ic.stateCode.Store(commonpb.StateCode_Abnormal)
|
|
// req := &indexpb.BuildIndexRequest{}
|
|
// resp, err := ic.BuildIndex(context.Background(), req)
|
|
// assert.Error(t, err)
|
|
// assert.Equal(t, commonpb.ErrorCode_UnexpectedError, resp.Status.ErrorCode)
|
|
//
|
|
// req2 := &indexpb.DropIndexRequest{}
|
|
// status, err := ic.DropIndex(context.Background(), req2)
|
|
// assert.Nil(t, err)
|
|
// assert.Equal(t, commonpb.ErrorCode_UnexpectedError, status.ErrorCode)
|
|
//
|
|
// req3 := &indexpb.GetIndexStatesRequest{}
|
|
// resp2, err := ic.GetIndexStates(context.Background(), req3)
|
|
// assert.Nil(t, err)
|
|
// assert.Equal(t, commonpb.ErrorCode_UnexpectedError, resp2.Status.ErrorCode)
|
|
//
|
|
// req4 := &indexpb.GetIndexFilePathsRequest{
|
|
// IndexBuildIDs: []UniqueID{1, 2},
|
|
// }
|
|
// resp4, err := ic.GetIndexFilePaths(context.Background(), req4)
|
|
// assert.Nil(t, err)
|
|
// assert.Equal(t, commonpb.ErrorCode_UnexpectedError, resp4.Status.ErrorCode)
|
|
//
|
|
// req5 := &indexpb.RemoveIndexRequest{}
|
|
// resp5, err := ic.RemoveIndex(context.Background(), req5)
|
|
// assert.Nil(t, err)
|
|
// assert.Equal(t, commonpb.ErrorCode_UnexpectedError, resp5.GetErrorCode())
|
|
//}
|
|
//
|
|
//func TestIndexCoord_GetIndexFilePaths(t *testing.T) {
|
|
// ic := &IndexCoord{
|
|
// metaTable: &metaTable{
|
|
// indexBuildID2Meta: map[UniqueID]*Meta{
|
|
// 1: {
|
|
// indexMeta: &indexpb.IndexMeta{
|
|
// IndexBuildID: 1,
|
|
// State: commonpb.IndexState_Finished,
|
|
// IndexFileKeys: []string{"indexFiles-1", "indexFiles-2"},
|
|
// },
|
|
// },
|
|
// 2: {
|
|
// indexMeta: &indexpb.IndexMeta{
|
|
// IndexBuildID: 2,
|
|
// State: commonpb.IndexState_Failed,
|
|
// },
|
|
// },
|
|
// },
|
|
// },
|
|
// }
|
|
//
|
|
// ic.stateCode.Store(commonpb.StateCode_Healthy)
|
|
//
|
|
// t.Run("GetIndexFilePaths success", func(t *testing.T) {
|
|
// resp, err := ic.GetIndexFilePaths(context.Background(), &indexpb.GetIndexFilePathsRequest{IndexBuildIDs: []UniqueID{1}})
|
|
// assert.NoError(t, err)
|
|
// assert.Equal(t, commonpb.ErrorCode_Success, resp.Status.ErrorCode)
|
|
// assert.Equal(t, 1, len(resp.FilePaths))
|
|
// assert.ElementsMatch(t, resp.FilePaths[0].IndexFileKeys, []string{"indexFiles-1", "indexFiles-2"})
|
|
// })
|
|
//
|
|
// t.Run("GetIndexFilePaths failed", func(t *testing.T) {
|
|
// resp, err := ic.GetIndexFilePaths(context.Background(), &indexpb.GetIndexFilePathsRequest{IndexBuildIDs: []UniqueID{2}})
|
|
// assert.NoError(t, err)
|
|
// assert.Equal(t, commonpb.ErrorCode_Success, resp.Status.ErrorCode)
|
|
// assert.Equal(t, 0, len(resp.FilePaths[0].IndexFileKeys))
|
|
// })
|
|
//
|
|
// t.Run("set DataCoord with nil", func(t *testing.T) {
|
|
// err := ic.SetDataCoord(nil)
|
|
// assert.Error(t, err)
|
|
// })
|
|
//}
|
|
//
|
|
//func Test_tryAcquireSegmentReferLock(t *testing.T) {
|
|
// ic := &IndexCoord{
|
|
// session: &sessionutil.Session{
|
|
// ServerID: 1,
|
|
// },
|
|
// }
|
|
// dcm := &DataCoordMock{
|
|
// Err: false,
|
|
// Fail: false,
|
|
// }
|
|
// cmm := &ChunkManagerMock{
|
|
// Err: false,
|
|
// Fail: false,
|
|
// }
|
|
//
|
|
// ic.dataCoordClient = dcm
|
|
// ic.chunkManager = cmm
|
|
//
|
|
// t.Run("success", func(t *testing.T) {
|
|
// err := ic.tryAcquireSegmentReferLock(context.Background(), 1, 1, []UniqueID{1})
|
|
// assert.Nil(t, err)
|
|
// })
|
|
//
|
|
// t.Run("error", func(t *testing.T) {
|
|
// dcmE := &DataCoordMock{
|
|
// Err: true,
|
|
// Fail: false,
|
|
// }
|
|
// ic.dataCoordClient = dcmE
|
|
// err := ic.tryAcquireSegmentReferLock(context.Background(), 1, 1, []UniqueID{1})
|
|
// assert.Error(t, err)
|
|
// })
|
|
//
|
|
// t.Run("Fail", func(t *testing.T) {
|
|
// dcmF := &DataCoordMock{
|
|
// Err: false,
|
|
// Fail: true,
|
|
// }
|
|
// ic.dataCoordClient = dcmF
|
|
// err := ic.tryAcquireSegmentReferLock(context.Background(), 1, 1, []UniqueID{1})
|
|
// assert.Error(t, err)
|
|
// })
|
|
//}
|
|
//
|
|
//func Test_tryReleaseSegmentReferLock(t *testing.T) {
|
|
// ic := &IndexCoord{
|
|
// session: &sessionutil.Session{
|
|
// ServerID: 1,
|
|
// },
|
|
// }
|
|
// dcm := &DataCoordMock{
|
|
// Err: false,
|
|
// Fail: false,
|
|
// }
|
|
//
|
|
// ic.dataCoordClient = dcm
|
|
//
|
|
// t.Run("success", func(t *testing.T) {
|
|
// err := ic.tryReleaseSegmentReferLock(context.Background(), 1, 1)
|
|
// assert.NoError(t, err)
|
|
// })
|
|
//}
|
|
//
|
|
//func TestIndexCoord_RemoveIndex(t *testing.T) {
|
|
// ic := &IndexCoord{
|
|
// metaTable: &metaTable{},
|
|
// indexBuilder: &indexBuilder{
|
|
// notify: make(chan struct{}, 10),
|
|
// },
|
|
// }
|
|
// ic.stateCode.Store(commonpb.StateCode_Healthy)
|
|
// status, err := ic.RemoveIndex(context.Background(), &indexpb.RemoveIndexRequest{BuildIDs: []UniqueID{0}})
|
|
// assert.Nil(t, err)
|
|
// assert.Equal(t, commonpb.ErrorCode_Success, status.GetErrorCode())
|
|
//}
|
|
|
|
func TestIndexCoord_pullSegmentInfo(t *testing.T) {
|
|
t.Run("success", func(t *testing.T) {
|
|
ic := &IndexCoord{
|
|
dataCoordClient: NewDataCoordMock(),
|
|
}
|
|
info, err := ic.pullSegmentInfo(context.Background(), segID)
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, info)
|
|
})
|
|
|
|
t.Run("fail", func(t *testing.T) {
|
|
ic := &IndexCoord{
|
|
dataCoordClient: &DataCoordMock{
|
|
CallGetSegmentInfo: func(ctx context.Context, req *datapb.GetSegmentInfoRequest) (*datapb.GetSegmentInfoResponse, error) {
|
|
return nil, errors.New("error")
|
|
},
|
|
},
|
|
}
|
|
info, err := ic.pullSegmentInfo(context.Background(), segID)
|
|
assert.Error(t, err)
|
|
assert.Nil(t, info)
|
|
})
|
|
|
|
t.Run("not success", func(t *testing.T) {
|
|
ic := &IndexCoord{
|
|
dataCoordClient: &DataCoordMock{
|
|
CallGetSegmentInfo: func(ctx context.Context, req *datapb.GetSegmentInfoRequest) (*datapb.GetSegmentInfoResponse, error) {
|
|
return &datapb.GetSegmentInfoResponse{
|
|
Status: &commonpb.Status{
|
|
ErrorCode: commonpb.ErrorCode_UnexpectedError,
|
|
Reason: "fail reason",
|
|
},
|
|
}, nil
|
|
},
|
|
},
|
|
}
|
|
info, err := ic.pullSegmentInfo(context.Background(), segID)
|
|
assert.Error(t, err)
|
|
assert.Nil(t, info)
|
|
})
|
|
|
|
t.Run("failed to get segment", func(t *testing.T) {
|
|
ic := &IndexCoord{
|
|
dataCoordClient: &DataCoordMock{
|
|
CallGetSegmentInfo: func(ctx context.Context, req *datapb.GetSegmentInfoRequest) (*datapb.GetSegmentInfoResponse, error) {
|
|
return &datapb.GetSegmentInfoResponse{
|
|
Status: &commonpb.Status{
|
|
ErrorCode: commonpb.ErrorCode_UnexpectedError,
|
|
Reason: msgSegmentNotFound(segID),
|
|
},
|
|
}, nil
|
|
},
|
|
},
|
|
}
|
|
info, err := ic.pullSegmentInfo(context.Background(), segID)
|
|
assert.Error(t, err)
|
|
assert.Nil(t, info)
|
|
})
|
|
|
|
t.Run("seg not exist", func(t *testing.T) {
|
|
ic := &IndexCoord{
|
|
dataCoordClient: &DataCoordMock{
|
|
CallGetSegmentInfo: func(ctx context.Context, req *datapb.GetSegmentInfoRequest) (*datapb.GetSegmentInfoResponse, error) {
|
|
return &datapb.GetSegmentInfoResponse{
|
|
Status: &commonpb.Status{
|
|
ErrorCode: commonpb.ErrorCode_Success,
|
|
Reason: "",
|
|
},
|
|
Infos: []*datapb.SegmentInfo{},
|
|
}, nil
|
|
},
|
|
},
|
|
}
|
|
info, err := ic.pullSegmentInfo(context.Background(), segID)
|
|
assert.ErrorIs(t, err, ErrSegmentNotFound)
|
|
assert.Nil(t, info)
|
|
})
|
|
}
|
|
|
|
func TestIndexCoord_CheckHealth(t *testing.T) {
|
|
t.Run("not healthy", func(t *testing.T) {
|
|
ctx := context.Background()
|
|
ic := &IndexCoord{session: &sessionutil.Session{ServerID: 1}}
|
|
ic.stateCode.Store(commonpb.StateCode_Abnormal)
|
|
resp, err := ic.CheckHealth(ctx, &milvuspb.CheckHealthRequest{})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, false, resp.IsHealthy)
|
|
assert.NotEmpty(t, resp.Reasons)
|
|
})
|
|
|
|
t.Run("index node health check is ok", func(t *testing.T) {
|
|
ctx := context.Background()
|
|
indexNode := indexnode.NewIndexNodeMock()
|
|
nm := NewNodeManager(ctx)
|
|
nm.nodeClients[1] = indexNode
|
|
ic := &IndexCoord{
|
|
session: &sessionutil.Session{ServerID: 1},
|
|
nodeManager: nm,
|
|
}
|
|
ic.stateCode.Store(commonpb.StateCode_Healthy)
|
|
resp, err := ic.CheckHealth(ctx, &milvuspb.CheckHealthRequest{})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, true, resp.IsHealthy)
|
|
assert.Empty(t, resp.Reasons)
|
|
})
|
|
|
|
t.Run("index node health check is fail", func(t *testing.T) {
|
|
ctx := context.Background()
|
|
indexNode := indexnode.NewIndexNodeMock()
|
|
indexNode.CallGetComponentStates = func(ctx context.Context) (*milvuspb.ComponentStates, error) {
|
|
return &milvuspb.ComponentStates{
|
|
State: &milvuspb.ComponentInfo{
|
|
NodeID: 1,
|
|
StateCode: commonpb.StateCode_Abnormal,
|
|
},
|
|
SubcomponentStates: nil,
|
|
Status: &commonpb.Status{
|
|
ErrorCode: commonpb.ErrorCode_Success,
|
|
},
|
|
}, nil
|
|
}
|
|
nm := NewNodeManager(ctx)
|
|
nm.nodeClients[1] = indexNode
|
|
ic := &IndexCoord{
|
|
nodeManager: nm,
|
|
session: &sessionutil.Session{ServerID: 1},
|
|
}
|
|
ic.stateCode.Store(commonpb.StateCode_Healthy)
|
|
|
|
resp, err := ic.CheckHealth(ctx, &milvuspb.CheckHealthRequest{})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, false, resp.IsHealthy)
|
|
assert.NotEmpty(t, resp.Reasons)
|
|
})
|
|
}
|
|
|
|
func TestIndexCoord_CreateIndex(t *testing.T) {
|
|
ic := &IndexCoord{
|
|
metaTable: &metaTable{
|
|
catalog: nil,
|
|
indexLock: sync.RWMutex{},
|
|
segmentIndexLock: sync.RWMutex{},
|
|
collectionIndexes: map[UniqueID]map[UniqueID]*model.Index{
|
|
collID: {
|
|
indexID: {
|
|
TenantID: "",
|
|
CollectionID: collID,
|
|
FieldID: fieldID,
|
|
IndexID: indexID,
|
|
IndexName: indexName,
|
|
IsDeleted: false,
|
|
CreateTime: 10,
|
|
TypeParams: []*commonpb.KeyValuePair{
|
|
{
|
|
Key: "dim",
|
|
Value: "128",
|
|
},
|
|
},
|
|
IndexParams: []*commonpb.KeyValuePair{
|
|
{
|
|
Key: "index_type",
|
|
Value: "IVF_FLAT",
|
|
},
|
|
{
|
|
Key: "metrics_type",
|
|
Value: "HAMMING",
|
|
},
|
|
{
|
|
Key: "nlist",
|
|
Value: "128",
|
|
},
|
|
},
|
|
IsAutoIndex: false,
|
|
UserIndexParams: nil,
|
|
},
|
|
},
|
|
},
|
|
segmentIndexes: map[UniqueID]map[UniqueID]*model.SegmentIndex{
|
|
segID: {
|
|
indexID: {
|
|
SegmentID: segID,
|
|
CollectionID: collID,
|
|
PartitionID: partID,
|
|
NumRows: 1025,
|
|
IndexID: indexID,
|
|
BuildID: buildID,
|
|
NodeID: nodeID,
|
|
IndexVersion: 1,
|
|
IndexState: commonpb.IndexState_Unissued,
|
|
FailReason: "",
|
|
IsDeleted: false,
|
|
CreateTime: 10,
|
|
IndexFileKeys: nil,
|
|
IndexSize: 0,
|
|
WriteHandoff: false,
|
|
},
|
|
},
|
|
},
|
|
buildID2SegmentIndex: map[UniqueID]*model.SegmentIndex{
|
|
buildID: {
|
|
SegmentID: segID,
|
|
CollectionID: collID,
|
|
PartitionID: partID,
|
|
NumRows: 1025,
|
|
IndexID: indexID,
|
|
BuildID: buildID,
|
|
NodeID: nodeID,
|
|
IndexVersion: 1,
|
|
IndexState: commonpb.IndexState_Unissued,
|
|
FailReason: "",
|
|
IsDeleted: false,
|
|
CreateTime: 10,
|
|
IndexFileKeys: nil,
|
|
IndexSize: 0,
|
|
WriteHandoff: false,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ic.UpdateStateCode(commonpb.StateCode_Healthy)
|
|
|
|
t.Run("index already exist, but params are inconsistent", func(t *testing.T) {
|
|
req := &indexpb.CreateIndexRequest{
|
|
CollectionID: collID,
|
|
FieldID: fieldID,
|
|
IndexName: indexName,
|
|
TypeParams: []*commonpb.KeyValuePair{
|
|
{
|
|
Key: "dim",
|
|
Value: "128",
|
|
},
|
|
},
|
|
IndexParams: []*commonpb.KeyValuePair{
|
|
{
|
|
Key: "index_type",
|
|
Value: "IVF_FLAT",
|
|
},
|
|
{
|
|
Key: "metrics_type",
|
|
Value: "HAMMING",
|
|
},
|
|
{
|
|
Key: "params",
|
|
Value: "{nlist: 128}",
|
|
},
|
|
},
|
|
Timestamp: 0,
|
|
IsAutoIndex: false,
|
|
UserIndexParams: nil,
|
|
}
|
|
|
|
resp, err := ic.CreateIndex(context.Background(), req)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, commonpb.ErrorCode_UnexpectedError, resp.GetErrorCode())
|
|
})
|
|
}
|