2021-10-27 18:04:47 +08:00
// 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
2021-01-19 18:32:57 +08:00
// with the License. You may obtain a copy of the License at
//
2021-10-27 18:04:47 +08:00
// http://www.apache.org/licenses/LICENSE-2.0
2021-01-19 18:32:57 +08:00
//
2021-10-27 18:04:47 +08:00
// 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.
2021-01-19 18:32:57 +08:00
2021-06-21 17:28:03 +08:00
package indexcoord
2021-01-19 18:32:57 +08:00
import (
2021-06-23 09:24:10 +08:00
"context"
2021-09-08 14:23:59 +08:00
"errors"
2021-01-19 18:32:57 +08:00
"fmt"
"sync"
2022-08-25 15:48:54 +08:00
"time"
2021-05-27 22:24:29 +08:00
2022-08-25 15:48:54 +08:00
"github.com/golang/protobuf/proto"
2021-03-10 09:56:09 +08:00
"go.uber.org/zap"
2022-08-25 15:48:54 +08:00
"github.com/milvus-io/milvus/internal/kv"
2021-04-22 14:45:57 +08:00
"github.com/milvus-io/milvus/internal/log"
2022-08-25 15:48:54 +08:00
"github.com/milvus-io/milvus/internal/metastore"
"github.com/milvus-io/milvus/internal/metastore/kv/indexcoord"
"github.com/milvus-io/milvus/internal/metastore/model"
"github.com/milvus-io/milvus/internal/metrics"
2021-04-22 14:45:57 +08:00
"github.com/milvus-io/milvus/internal/proto/commonpb"
"github.com/milvus-io/milvus/internal/proto/indexpb"
2022-08-25 15:48:54 +08:00
"github.com/milvus-io/milvus/internal/util/tsoutil"
2021-01-19 18:32:57 +08:00
)
2022-08-25 15:48:54 +08:00
// metaTable maintains index-related information
2021-01-19 18:32:57 +08:00
type metaTable struct {
2022-08-25 15:48:54 +08:00
catalog metastore . IndexCoordCatalog
indexLock sync . RWMutex
segmentIndexLock sync . RWMutex
// collectionIndexes records which indexes are on the collection
// collID -> indexID -> index
collectionIndexes map [ UniqueID ] map [ UniqueID ] * model . Index
// segmentIndexes records which indexes are on the segment
// segID -> indexID -> segmentIndex
segmentIndexes map [ UniqueID ] map [ UniqueID ] * model . SegmentIndex
// buildID2Meta records the meta information of the segment
// buildID -> segmentIndex
buildID2SegmentIndex map [ UniqueID ] * model . SegmentIndex
2021-01-19 18:32:57 +08:00
}
2021-09-23 21:37:55 +08:00
// NewMetaTable is used to create a new meta table.
2022-06-27 21:52:17 +08:00
func NewMetaTable ( kv kv . MetaKv ) ( * metaTable , error ) {
2021-01-19 18:32:57 +08:00
mt := & metaTable {
2022-08-25 15:48:54 +08:00
catalog : & indexcoord . Catalog {
Txn : kv ,
} ,
indexLock : sync . RWMutex { } ,
segmentIndexLock : sync . RWMutex { } ,
2021-01-19 18:32:57 +08:00
}
err := mt . reloadFromKV ( )
if err != nil {
return nil , err
}
return mt , nil
}
2022-08-25 15:48:54 +08:00
func ( mt * metaTable ) updateCollectionIndex ( index * model . Index ) {
if _ , ok := mt . collectionIndexes [ index . CollectionID ] ; ! ok {
mt . collectionIndexes [ index . CollectionID ] = make ( map [ UniqueID ] * model . Index )
}
mt . collectionIndexes [ index . CollectionID ] [ index . IndexID ] = index
}
func ( mt * metaTable ) updateSegmentIndex ( segIdx * model . SegmentIndex ) {
if _ , ok := mt . segmentIndexes [ segIdx . SegmentID ] ; ! ok {
mt . segmentIndexes [ segIdx . SegmentID ] = make ( map [ UniqueID ] * model . SegmentIndex )
}
mt . segmentIndexes [ segIdx . SegmentID ] [ segIdx . IndexID ] = segIdx
mt . buildID2SegmentIndex [ segIdx . BuildID ] = segIdx
}
2021-12-08 09:33:41 +08:00
// reloadFromKV reloads the index meta from ETCD.
2021-01-19 18:32:57 +08:00
func ( mt * metaTable ) reloadFromKV ( ) error {
2022-08-25 15:48:54 +08:00
mt . collectionIndexes = make ( map [ UniqueID ] map [ UniqueID ] * model . Index )
mt . segmentIndexes = make ( map [ UniqueID ] map [ UniqueID ] * model . SegmentIndex )
mt . buildID2SegmentIndex = make ( map [ UniqueID ] * model . SegmentIndex )
2021-01-19 18:32:57 +08:00
2022-08-25 15:48:54 +08:00
// load field indexes
log . Info ( "IndexCoord metaTable reloadFromKV load indexes" )
fieldIndexes , err := mt . catalog . ListIndexes ( context . Background ( ) )
2021-01-19 18:32:57 +08:00
if err != nil {
2022-08-25 15:48:54 +08:00
log . Error ( "IndexCoord metaTable reloadFromKV load field indexes fail" , zap . Error ( err ) )
return err
}
segmentIndxes , err := mt . catalog . ListSegmentIndexes ( context . Background ( ) )
if err != nil {
log . Error ( "IndexCoord metaTable reloadFromKV load segment indexes fail" , zap . Error ( err ) )
2021-01-19 18:32:57 +08:00
return err
}
2022-08-25 15:48:54 +08:00
for _ , fieldIndex := range fieldIndexes {
mt . updateCollectionIndex ( fieldIndex )
}
for _ , segIdx := range segmentIndxes {
mt . updateSegmentIndex ( segIdx )
2021-01-19 18:32:57 +08:00
}
2022-08-25 15:48:54 +08:00
log . Info ( "IndexCoord metaTable reloadFromKV success" )
2021-01-19 18:32:57 +08:00
return nil
}
2022-08-25 15:48:54 +08:00
func ( mt * metaTable ) saveFieldIndexMeta ( index * model . Index ) error {
err := mt . catalog . CreateIndex ( context . Background ( ) , index )
2021-09-29 20:26:00 +08:00
if err != nil {
2022-08-25 15:48:54 +08:00
log . Error ( "failed to save index meta in etcd" , zap . Int64 ( "buildID" , index . CollectionID ) ,
zap . Int64 ( "fieldID" , index . FieldID ) , zap . Int64 ( "indexID" , index . IndexID ) , zap . Error ( err ) )
2021-09-29 20:26:00 +08:00
return err
}
2022-08-25 15:48:54 +08:00
mt . updateCollectionIndex ( index )
return nil
}
func ( mt * metaTable ) alterIndexes ( indexes [ ] * model . Index ) error {
err := mt . catalog . AlterIndexes ( context . Background ( ) , indexes )
2021-05-27 22:24:29 +08:00
if err != nil {
2022-08-25 15:48:54 +08:00
log . Error ( "failed to alter index meta in meta store" , zap . Int ( "indexes num" , len ( indexes ) ) , zap . Error ( err ) )
2021-05-27 22:24:29 +08:00
return err
}
2022-08-25 15:48:54 +08:00
for _ , index := range indexes {
mt . updateCollectionIndex ( index )
2022-07-06 13:54:21 +08:00
}
2021-05-27 22:24:29 +08:00
return nil
}
2022-08-25 15:48:54 +08:00
func ( mt * metaTable ) alterSegmentIndexes ( segIdxes [ ] * model . SegmentIndex ) error {
err := mt . catalog . AlterSegmentIndexes ( context . Background ( ) , segIdxes )
2021-05-27 22:24:29 +08:00
if err != nil {
2022-08-25 15:48:54 +08:00
log . Error ( "failed to alter segments index in meta store" , zap . Int ( "segment indexes num" , len ( segIdxes ) ) ,
zap . Error ( err ) )
return err
2021-05-27 22:24:29 +08:00
}
2022-08-25 15:48:54 +08:00
for _ , segIdx := range segIdxes {
mt . updateSegmentIndex ( segIdx )
2021-09-08 14:23:59 +08:00
}
2022-08-25 15:48:54 +08:00
return nil
}
// saveSegmentIndexMeta saves the index meta to ETCD.
// metaTable.lock.Lock() before call this function
func ( mt * metaTable ) saveSegmentIndexMeta ( segIdx * model . SegmentIndex ) error {
err := mt . catalog . CreateSegmentIndex ( context . Background ( ) , segIdx )
2021-05-27 22:24:29 +08:00
if err != nil {
2022-08-25 15:48:54 +08:00
log . Error ( "failed to save index meta in etcd" , zap . Int64 ( "buildID" , segIdx . BuildID ) , zap . Error ( err ) )
return err
2021-05-27 22:24:29 +08:00
}
2021-01-19 18:32:57 +08:00
2022-08-25 15:48:54 +08:00
mt . updateSegmentIndex ( segIdx )
log . Info ( "IndexCoord metaTable saveIndexMeta success" , zap . Int64 ( "buildID" , segIdx . BuildID ) )
return nil
}
func ( mt * metaTable ) updateIndexMeta ( index * model . Index , updateFunc func ( clonedIndex * model . Index ) error ) error {
return updateFunc ( model . CloneIndex ( index ) )
}
func ( mt * metaTable ) updateSegIndexMeta ( segIdx * model . SegmentIndex , updateFunc func ( clonedSegIdx * model . SegmentIndex ) error ) error {
return updateFunc ( model . CloneSegmentIndex ( segIdx ) )
2021-01-19 18:32:57 +08:00
}
2022-08-25 15:48:54 +08:00
func ( mt * metaTable ) GetAllIndexMeta ( ) map [ int64 ] * model . SegmentIndex {
mt . segmentIndexLock . RLock ( )
defer mt . segmentIndexLock . RUnlock ( )
2022-07-07 14:44:21 +08:00
2022-08-25 15:48:54 +08:00
metas := map [ int64 ] * model . SegmentIndex { }
for buildID , segIdx := range mt . buildID2SegmentIndex {
metas [ buildID ] = model . CloneSegmentIndex ( segIdx )
2022-07-07 14:44:21 +08:00
}
return metas
}
2022-08-25 15:48:54 +08:00
func ( mt * metaTable ) GetMeta ( buildID UniqueID ) ( * model . SegmentIndex , bool ) {
mt . segmentIndexLock . RLock ( )
defer mt . segmentIndexLock . RUnlock ( )
segIdx , ok := mt . buildID2SegmentIndex [ buildID ]
2021-01-19 18:32:57 +08:00
if ok {
2022-08-25 15:48:54 +08:00
return model . CloneSegmentIndex ( segIdx ) , true
2021-01-19 18:32:57 +08:00
}
2022-08-25 15:48:54 +08:00
return nil , false
2021-01-19 18:32:57 +08:00
}
2022-08-25 15:48:54 +08:00
func ( mt * metaTable ) GetTypeParams ( collID , indexID UniqueID ) ( [ ] * commonpb . KeyValuePair , error ) {
mt . indexLock . RLock ( )
defer mt . indexLock . RUnlock ( )
fieldIndexes , ok := mt . collectionIndexes [ collID ]
2021-04-16 15:37:13 +08:00
if ! ok {
2022-08-25 15:48:54 +08:00
return nil , fmt . Errorf ( "there is no index on collection: %d" , collID )
2021-04-16 15:37:13 +08:00
}
2022-08-25 15:48:54 +08:00
index , ok := fieldIndexes [ indexID ]
if ! ok {
return nil , fmt . Errorf ( "there is no index on collection: %d with indexID: %d" , collID , indexID )
2021-10-28 18:20:27 +08:00
}
2022-08-25 15:48:54 +08:00
typeParams := make ( [ ] * commonpb . KeyValuePair , len ( index . TypeParams ) )
for i , param := range index . TypeParams {
typeParams [ i ] = proto . Clone ( param ) . ( * commonpb . KeyValuePair )
2021-05-27 22:24:29 +08:00
}
2022-08-25 15:48:54 +08:00
return typeParams , nil
2022-07-07 14:44:21 +08:00
}
2021-05-27 22:24:29 +08:00
2022-08-25 15:48:54 +08:00
func ( mt * metaTable ) GetIndexParams ( collID , indexID UniqueID ) [ ] * commonpb . KeyValuePair {
mt . indexLock . RLock ( )
defer mt . indexLock . RUnlock ( )
2022-07-07 14:44:21 +08:00
2022-08-25 15:48:54 +08:00
fieldIndexes , ok := mt . collectionIndexes [ collID ]
if ! ok {
return nil
2022-07-07 14:44:21 +08:00
}
2022-08-25 15:48:54 +08:00
index , ok := fieldIndexes [ indexID ]
if ! ok {
return nil
}
indexParams := make ( [ ] * commonpb . KeyValuePair , len ( index . IndexParams ) )
for i , param := range index . IndexParams {
indexParams [ i ] = proto . Clone ( param ) . ( * commonpb . KeyValuePair )
}
return indexParams
}
2022-07-07 14:44:21 +08:00
2022-08-25 15:48:54 +08:00
func ( mt * metaTable ) CreateIndex ( index * model . Index ) error {
mt . indexLock . Lock ( )
defer mt . indexLock . Unlock ( )
log . Info ( "IndexCoord metaTable CreateIndex" , zap . Int64 ( "collectionID" , index . CollectionID ) ,
zap . Int64 ( "fieldID" , index . FieldID ) , zap . Int64 ( "indexID" , index . IndexID ) , zap . String ( "indexName" , index . IndexName ) )
if err := mt . saveFieldIndexMeta ( index ) ; err != nil {
log . Error ( "IndexCoord metaTable CreateIndex save meta fail" , zap . Int64 ( "collectionID" , index . CollectionID ) ,
zap . Int64 ( "fieldID" , index . FieldID ) , zap . Int64 ( "indexID" , index . IndexID ) ,
zap . String ( "indexName" , index . IndexName ) , zap . Error ( err ) )
2022-07-07 14:44:21 +08:00
return err
}
2022-08-25 15:48:54 +08:00
log . Info ( "IndexCoord metaTable CreateIndex success" , zap . Int64 ( "collectionID" , index . CollectionID ) ,
zap . Int64 ( "fieldID" , index . FieldID ) , zap . Int64 ( "indexID" , index . IndexID ) , zap . String ( "indexName" , index . IndexName ) )
2021-05-27 22:24:29 +08:00
return nil
2021-04-16 15:37:13 +08:00
}
2022-08-25 15:48:54 +08:00
// AddIndex adds the index meta corresponding the indexBuildID to meta table.
func ( mt * metaTable ) AddIndex ( segIndex * model . SegmentIndex ) error {
mt . segmentIndexLock . Lock ( )
defer mt . segmentIndexLock . Unlock ( )
buildID := segIndex . BuildID
log . Info ( "IndexCoord metaTable AddIndex" , zap . Int64 ( "collID" , segIndex . CollectionID ) ,
zap . Int64 ( "segID" , segIndex . SegmentID ) , zap . Int64 ( "indexID" , segIndex . IndexID ) ,
zap . Int64 ( "buildID" , buildID ) )
_ , ok := mt . buildID2SegmentIndex [ buildID ]
if ok {
log . Info ( "index already exists" , zap . Int64 ( "buildID" , buildID ) , zap . Int64 ( "indexID" , segIndex . IndexID ) )
return nil
2021-05-27 22:24:29 +08:00
}
2022-08-25 15:48:54 +08:00
segIndex . IndexState = commonpb . IndexState_Unissued
2021-02-23 11:57:18 +08:00
2022-08-25 15:48:54 +08:00
metrics . IndexCoordIndexTaskCounter . WithLabelValues ( metrics . UnissuedIndexTaskLabel ) . Inc ( )
if err := mt . saveSegmentIndexMeta ( segIndex ) ; err != nil {
// no need to reload, no reason to compare version fail
log . Error ( "IndexCoord metaTable save index meta failed" , zap . Int64 ( "buildID" , buildID ) ,
zap . Int64 ( "indexID" , segIndex . IndexID ) , zap . Error ( err ) )
2022-07-07 14:44:21 +08:00
return err
}
2022-08-25 15:48:54 +08:00
log . Info ( "IndexCoord metaTable AddIndex success" , zap . Int64 ( "collID" , segIndex . CollectionID ) ,
zap . Int64 ( "segID" , segIndex . SegmentID ) , zap . Int64 ( "indexID" , segIndex . IndexID ) ,
zap . Int64 ( "buildID" , buildID ) )
2022-07-07 14:44:21 +08:00
return nil
}
2021-03-26 10:01:08 +08:00
2022-08-25 15:48:54 +08:00
func ( mt * metaTable ) NeedIndex ( collID , indexID UniqueID ) bool {
mt . indexLock . RLock ( )
defer mt . indexLock . RUnlock ( )
2021-05-27 22:24:29 +08:00
2022-08-25 15:48:54 +08:00
fieldIndexes , ok := mt . collectionIndexes [ collID ]
if ! ok {
return false
}
if index , ok := fieldIndexes [ indexID ] ; ! ok || index . IsDeleted {
return false
2022-07-07 14:44:21 +08:00
}
2021-05-27 22:24:29 +08:00
2022-08-25 15:48:54 +08:00
return true
2022-07-07 14:44:21 +08:00
}
2022-08-25 15:48:54 +08:00
func ( mt * metaTable ) canIndex ( segIdx * model . SegmentIndex ) bool {
if segIdx . IsDeleted {
log . Debug ( "Index has been deleted" , zap . Int64 ( "buildID" , segIdx . BuildID ) )
2022-07-07 14:44:21 +08:00
return false
2021-02-23 11:57:18 +08:00
}
2022-08-25 15:48:54 +08:00
if segIdx . NodeID != 0 {
2022-08-11 10:00:38 +08:00
log . Debug ( "IndexCoord metaTable BuildIndex, but indexMeta's NodeID is not zero" ,
2022-08-25 15:48:54 +08:00
zap . Int64 ( "buildID" , segIdx . BuildID ) , zap . Int64 ( "nodeID" , segIdx . NodeID ) )
2022-07-07 14:44:21 +08:00
return false
}
2022-08-25 15:48:54 +08:00
if segIdx . IndexState != commonpb . IndexState_Unissued {
2022-08-11 10:00:38 +08:00
log . Debug ( "IndexCoord metaTable BuildIndex, but indexMeta's state is not unissued" ,
2022-08-25 15:48:54 +08:00
zap . Int64 ( "buildID" , segIdx . BuildID ) , zap . String ( "state" , segIdx . IndexState . String ( ) ) )
2022-07-07 14:44:21 +08:00
return false
}
return true
}
// UpdateVersion updates the version and nodeID of the index meta, whenever the task is built once, the version will be updated once.
2022-08-25 15:48:54 +08:00
func ( mt * metaTable ) UpdateVersion ( buildID UniqueID , nodeID UniqueID ) error {
mt . segmentIndexLock . Lock ( )
defer mt . segmentIndexLock . Unlock ( )
log . Debug ( "IndexCoord metaTable UpdateVersion receive" , zap . Int64 ( "buildID" , buildID ) , zap . Int64 ( "nodeID" , nodeID ) )
segIdx , ok := mt . buildID2SegmentIndex [ buildID ]
if ! ok {
return fmt . Errorf ( "there is no index with buildID: %d" , buildID )
2022-07-07 14:44:21 +08:00
}
2022-08-25 15:48:54 +08:00
if ! mt . canIndex ( segIdx ) {
return fmt . Errorf ( "it's no necessary to build index with buildID = %d" , buildID )
}
updateFunc := func ( segIdx * model . SegmentIndex ) error {
segIdx . NodeID = nodeID
segIdx . IndexVersion ++
return mt . saveSegmentIndexMeta ( segIdx )
}
return mt . updateSegIndexMeta ( segIdx , updateFunc )
2021-02-23 11:57:18 +08:00
}
2022-07-07 14:44:21 +08:00
// BuildIndex set the index state to be InProgress. It means IndexNode is building the index.
2022-08-25 15:48:54 +08:00
func ( mt * metaTable ) BuildIndex ( buildID UniqueID ) error {
mt . segmentIndexLock . Lock ( )
defer mt . segmentIndexLock . Unlock ( )
segIdx , ok := mt . buildID2SegmentIndex [ buildID ]
if ! ok {
return fmt . Errorf ( "there is no index with buildID: %d" , buildID )
}
2022-07-07 14:44:21 +08:00
2022-08-25 15:48:54 +08:00
updateFunc := func ( segIdx * model . SegmentIndex ) error {
if segIdx . IsDeleted {
errMsg := fmt . Sprintf ( "index has been marked deleted, no need to build index with ID: %d" , segIdx . BuildID )
log . Warn ( errMsg , zap . Int64 ( "BuildID" , segIdx . BuildID ) )
return errors . New ( errMsg )
2022-07-07 14:44:21 +08:00
}
2022-08-25 15:48:54 +08:00
if segIdx . IndexState == commonpb . IndexState_Finished || segIdx . IndexState == commonpb . IndexState_Failed {
errMsg := fmt . Sprintf ( "index has been finished, no need to build index with ID: %d" , segIdx . BuildID )
log . Warn ( errMsg , zap . Int64 ( "BuildID" , segIdx . BuildID ) , zap . String ( "state" , segIdx . IndexState . String ( ) ) )
return errors . New ( errMsg )
2022-07-07 14:44:21 +08:00
}
2022-08-25 15:48:54 +08:00
segIdx . IndexState = commonpb . IndexState_InProgress
2022-07-07 14:44:21 +08:00
2022-08-25 15:48:54 +08:00
err := mt . saveSegmentIndexMeta ( segIdx )
2022-07-07 14:44:21 +08:00
if err != nil {
2022-08-25 15:48:54 +08:00
log . Error ( "IndexCoord metaTable BuildIndex fail" , zap . Int64 ( "buildID" , segIdx . BuildID ) , zap . Error ( err ) )
2022-07-07 14:44:21 +08:00
return err
}
metrics . IndexCoordIndexTaskCounter . WithLabelValues ( metrics . UnissuedIndexTaskLabel ) . Dec ( )
metrics . IndexCoordIndexTaskCounter . WithLabelValues ( metrics . InProgressIndexTaskLabel ) . Inc ( )
return nil
}
2022-08-25 15:48:54 +08:00
return mt . updateSegIndexMeta ( segIdx , updateFunc )
2022-07-07 14:44:21 +08:00
}
2022-08-25 15:48:54 +08:00
// GetIndexesForCollection gets all indexes info with the specified collection.
func ( mt * metaTable ) GetIndexesForCollection ( collID UniqueID , indexName string ) [ ] * model . Index {
mt . indexLock . RLock ( )
defer mt . indexLock . RUnlock ( )
2022-07-07 14:44:21 +08:00
2022-08-25 15:48:54 +08:00
indexInfos := make ( [ ] * model . Index , 0 )
for _ , index := range mt . collectionIndexes [ collID ] {
if index . IsDeleted {
2022-07-07 14:44:21 +08:00
continue
}
2022-08-25 15:48:54 +08:00
if indexName == "" || indexName == index . IndexName {
indexInfos = append ( indexInfos , model . CloneIndex ( index ) )
2022-07-07 14:44:21 +08:00
}
}
2022-08-25 15:48:54 +08:00
return indexInfos
2022-07-07 14:44:21 +08:00
}
2022-08-25 15:48:54 +08:00
func ( mt * metaTable ) CanCreateIndex ( req * indexpb . CreateIndexRequest ) bool {
mt . indexLock . RLock ( )
defer mt . indexLock . RUnlock ( )
2022-07-07 14:44:21 +08:00
2022-08-25 15:48:54 +08:00
indexes , ok := mt . collectionIndexes [ req . CollectionID ]
if ! ok {
return true
2022-07-07 14:44:21 +08:00
}
2022-08-25 15:48:54 +08:00
for _ , index := range indexes {
if index . IsDeleted {
continue
}
if req . IndexName == index . IndexName {
return mt . checkParams ( index , req )
}
if req . FieldID == index . FieldID {
// creating multiple indexes on same field is not supported
return false
2021-05-27 22:24:29 +08:00
}
2021-01-19 18:32:57 +08:00
}
2022-08-25 15:48:54 +08:00
return true
2021-01-19 18:32:57 +08:00
}
2022-08-25 15:48:54 +08:00
func ( mt * metaTable ) IsExpire ( buildID UniqueID ) bool {
mt . segmentIndexLock . RLock ( )
defer mt . segmentIndexLock . RUnlock ( )
2022-06-17 18:08:12 +08:00
2022-08-25 15:48:54 +08:00
segIdx , ok := mt . buildID2SegmentIndex [ buildID ]
if ! ok {
return true
2022-07-07 14:44:21 +08:00
}
2022-06-17 18:08:12 +08:00
2022-08-25 15:48:54 +08:00
pTs , _ := tsoutil . ParseTS ( segIdx . CreateTime )
return time . Since ( pTs ) > time . Minute * 10
}
func ( mt * metaTable ) checkParams ( fieldIndex * model . Index , req * indexpb . CreateIndexRequest ) bool {
if fieldIndex . IsDeleted {
return false
}
if fieldIndex . IndexName != req . IndexName {
return false
}
if fieldIndex . FieldID != req . FieldID {
return false
}
if len ( fieldIndex . TypeParams ) != len ( req . TypeParams ) {
return false
}
notEq := false
for _ , param1 := range fieldIndex . TypeParams {
exist := false
for _ , param2 := range req . TypeParams {
if param2 . Key == param1 . Key && param2 . Value == param1 . Value {
exist = true
}
2022-07-07 14:44:21 +08:00
}
2022-08-25 15:48:54 +08:00
if ! exist {
notEq = true
break
}
}
if notEq {
return false
}
if len ( fieldIndex . IndexParams ) != len ( req . IndexParams ) {
return false
}
for _ , param1 := range fieldIndex . IndexParams {
exist := false
for _ , param2 := range req . IndexParams {
if param2 . Key == param1 . Key && param2 . Value == param1 . Value {
exist = true
}
}
if ! exist {
notEq = true
break
2022-06-17 18:08:12 +08:00
}
}
2022-06-28 12:08:17 +08:00
2022-08-25 15:48:54 +08:00
return ! notEq
2022-06-17 18:08:12 +08:00
}
2022-08-25 15:48:54 +08:00
// HasSameReq determine whether there are same indexing tasks.
func ( mt * metaTable ) HasSameReq ( req * indexpb . CreateIndexRequest ) ( bool , UniqueID ) {
mt . indexLock . RLock ( )
defer mt . indexLock . RUnlock ( )
for _ , fieldIndex := range mt . collectionIndexes [ req . CollectionID ] {
if ! mt . checkParams ( fieldIndex , req ) {
continue
2021-06-30 14:32:19 +08:00
}
2022-08-25 15:48:54 +08:00
log . Debug ( "IndexCoord has same index" , zap . Int64 ( "collectionID" , req . CollectionID ) ,
zap . Int64 ( "fieldID" , req . FieldID ) , zap . String ( "indexName" , req . IndexName ) ,
zap . Int64 ( "indexID" , fieldIndex . IndexID ) )
return true , fieldIndex . IndexID
2021-02-23 11:57:18 +08:00
}
2022-08-25 15:48:54 +08:00
return false , 0
2021-01-19 18:32:57 +08:00
}
2022-08-25 15:48:54 +08:00
func ( mt * metaTable ) HasSameIndex ( segmentID , indexID UniqueID ) ( bool , UniqueID ) {
mt . segmentIndexLock . RLock ( )
defer mt . segmentIndexLock . RUnlock ( )
if _ , ok := mt . segmentIndexes [ segmentID ] ; ! ok {
return false , 0
2021-01-19 18:32:57 +08:00
}
2022-08-25 15:48:54 +08:00
if index , ok := mt . segmentIndexes [ segmentID ] [ indexID ] ; ok {
return true , index . BuildID
2022-05-17 20:41:56 +08:00
}
2022-08-25 15:48:54 +08:00
return false , 0
}
func ( mt * metaTable ) GetIndexIDByName ( collID int64 , indexName string ) map [ int64 ] uint64 {
mt . indexLock . RLock ( )
defer mt . indexLock . RUnlock ( )
indexID2CreateTs := make ( map [ int64 ] uint64 )
fieldIndexes , ok := mt . collectionIndexes [ collID ]
if ! ok {
return indexID2CreateTs
2021-02-23 11:57:18 +08:00
}
2021-12-23 21:38:34 +08:00
2022-08-25 15:48:54 +08:00
for _ , index := range fieldIndexes {
if ! index . IsDeleted && ( indexName == "" || index . IndexName == indexName ) {
indexID2CreateTs [ index . IndexID ] = index . CreateTime
}
}
return indexID2CreateTs
2021-01-19 18:32:57 +08:00
}
2022-08-25 15:48:54 +08:00
func ( mt * metaTable ) GetFieldIDByIndexID ( collID , indexID UniqueID ) UniqueID {
mt . indexLock . RLock ( )
defer mt . indexLock . RUnlock ( )
2021-02-23 11:57:18 +08:00
2022-08-25 15:48:54 +08:00
if fieldIndexes , ok := mt . collectionIndexes [ collID ] ; ok {
if index , ok := fieldIndexes [ indexID ] ; ok {
return index . FieldID
}
2021-12-23 21:40:25 +08:00
}
2022-08-25 15:48:54 +08:00
return 0
2021-02-23 11:57:18 +08:00
}
2022-08-25 15:48:54 +08:00
func ( mt * metaTable ) GetIndexNameByID ( collID , indexID UniqueID ) string {
mt . indexLock . RLock ( )
defer mt . indexLock . RUnlock ( )
if fieldIndexes , ok := mt . collectionIndexes [ collID ] ; ok {
if index , ok := fieldIndexes [ indexID ] ; ok {
return index . IndexName
}
}
return ""
}
2021-05-27 22:24:29 +08:00
2022-08-25 15:48:54 +08:00
type IndexState struct {
state commonpb . IndexState
failReason string
}
2021-05-27 22:24:29 +08:00
2022-08-25 15:48:54 +08:00
// GetIndexStates gets the index states for indexID from meta table.
func ( mt * metaTable ) GetIndexStates ( indexID int64 , createTs uint64 ) [ ] * IndexState {
mt . segmentIndexLock . RLock ( )
defer mt . segmentIndexLock . RUnlock ( )
segIndexStates := make ( [ ] * IndexState , 0 )
var (
cntNone = 0
cntUnissued = 0
cntInProgress = 0
cntFinished = 0
cntFailed = 0
)
for _ , indexID2SegIdx := range mt . segmentIndexes {
segIdx , ok := indexID2SegIdx [ indexID ]
if ! ok {
continue
}
if segIdx . CreateTime > createTs {
continue
}
if segIdx . IsDeleted {
// skip deleted index, deleted by compaction
continue
}
switch segIdx . IndexState {
case commonpb . IndexState_IndexStateNone :
cntNone ++
case commonpb . IndexState_Unissued :
cntUnissued ++
case commonpb . IndexState_InProgress :
cntInProgress ++
case commonpb . IndexState_Finished :
cntFinished ++
case commonpb . IndexState_Failed :
cntFailed ++
}
segIndexStates = append ( segIndexStates , & IndexState {
state : segIdx . IndexState ,
failReason : segIdx . FailReason ,
} )
2021-05-27 22:24:29 +08:00
}
2022-08-25 15:48:54 +08:00
log . Debug ( "IndexCoord get index states success" , zap . Int64 ( "indexID" , indexID ) ,
zap . Int ( "total" , len ( segIndexStates ) ) , zap . Int ( "None" , cntNone ) , zap . Int ( "Unissued" , cntUnissued ) ,
zap . Int ( "InProgress" , cntInProgress ) , zap . Int ( "Finished" , cntFinished ) , zap . Int ( "Failed" , cntFailed ) )
return segIndexStates
2022-06-23 10:40:13 +08:00
}
2022-08-25 15:48:54 +08:00
func ( mt * metaTable ) GetSegmentIndexes ( segID UniqueID ) [ ] * model . SegmentIndex {
mt . segmentIndexLock . RLock ( )
defer mt . segmentIndexLock . RUnlock ( )
2021-07-14 14:15:55 +08:00
2022-08-25 15:48:54 +08:00
segIndexInfos := make ( [ ] * model . SegmentIndex , 0 )
if segIndexes , ok := mt . segmentIndexes [ segID ] ; ok {
for _ , segIdx := range segIndexes {
segIndexInfos = append ( segIndexInfos , model . CloneSegmentIndex ( segIdx ) )
2021-05-27 22:24:29 +08:00
}
}
2022-08-25 15:48:54 +08:00
return segIndexInfos
2021-05-27 22:24:29 +08:00
}
2022-08-25 15:48:54 +08:00
func ( mt * metaTable ) GetSegmentIndexState ( segmentID UniqueID , indexID UniqueID ) IndexState {
mt . segmentIndexLock . RLock ( )
defer mt . segmentIndexLock . RUnlock ( )
2021-05-27 22:24:29 +08:00
2022-08-25 15:48:54 +08:00
if segIdxes , ok := mt . segmentIndexes [ segmentID ] ; ok {
if segIdx , ok := segIdxes [ indexID ] ; ok && ! segIdx . IsDeleted {
return IndexState {
state : segIdx . IndexState ,
failReason : segIdx . FailReason ,
}
2022-05-31 16:36:03 +08:00
}
2022-08-25 15:48:54 +08:00
}
return IndexState {
state : commonpb . IndexState_IndexStateNone ,
failReason : "there is no index" ,
}
}
// GetIndexBuildProgress gets the index progress for indexID from meta table.
func ( mt * metaTable ) GetIndexBuildProgress ( indexID int64 , createTs uint64 ) int64 {
mt . segmentIndexLock . RLock ( )
defer mt . segmentIndexLock . RUnlock ( )
indexRows := int64 ( 0 )
for _ , indexID2SegIdx := range mt . segmentIndexes {
segIdx , ok := indexID2SegIdx [ indexID ]
if ! ok {
2021-06-24 14:36:08 +08:00
continue
}
2022-08-25 15:48:54 +08:00
if segIdx . CreateTime > createTs {
2021-06-24 14:36:08 +08:00
continue
}
2022-08-25 15:48:54 +08:00
if segIdx . IsDeleted {
// skip deleted index, deleted by compaction
2021-06-24 14:36:08 +08:00
continue
}
2022-08-25 15:48:54 +08:00
if segIdx . IndexState == commonpb . IndexState_Finished {
indexRows += segIdx . NumRows
2021-06-24 14:36:08 +08:00
}
2022-08-25 15:48:54 +08:00
}
log . Debug ( "IndexCoord get index states success" , zap . Int64 ( "indexID" , indexID ) ,
zap . Int64 ( "indexRows" , indexRows ) )
return indexRows
}
// MarkIndexAsDeleted will mark the corresponding index as deleted, and recycleUnusedIndexFiles will recycle these tasks.
func ( mt * metaTable ) MarkIndexAsDeleted ( collID UniqueID , indexIDs [ ] UniqueID ) error {
log . Info ( "IndexCoord metaTable MarkIndexAsDeleted" , zap . Int64 ( "collID" , collID ) ,
zap . Int64s ( "indexIDs" , indexIDs ) )
mt . indexLock . Lock ( )
defer mt . indexLock . Unlock ( )
fieldIndexes , ok := mt . collectionIndexes [ collID ]
if ! ok {
return nil
}
indexes := make ( [ ] * model . Index , 0 )
for _ , indexID := range indexIDs {
index , ok := fieldIndexes [ indexID ]
if ! ok {
2021-06-24 14:36:08 +08:00
continue
}
2022-08-25 15:48:54 +08:00
clonedIndex := model . CloneIndex ( index )
clonedIndex . IsDeleted = true
indexes = append ( indexes , clonedIndex )
}
err := mt . alterIndexes ( indexes )
if err != nil {
log . Error ( "IndexCoord metaTable MarkIndexAsDeleted fail" , zap . Int64 ( "collID" , collID ) ,
zap . Int64s ( "indexIDs" , indexIDs ) , zap . Error ( err ) )
return err
}
log . Info ( "IndexCoord metaTable MarkIndexAsDeleted success" , zap . Int64 ( "collID" , collID ) , zap . Int64s ( "indexIDs" , indexIDs ) )
return nil
}
// MarkSegIndexAsDeleted will mark the index on the segment corresponding the buildID as deleted, and recycleUnusedSegIndexes will recycle these tasks.
func ( mt * metaTable ) MarkSegIndexAsDeleted ( buildID UniqueID ) error {
log . Info ( "IndexCoord metaTable MarkSegIndexAsDeleted" , zap . Int64 ( "buildID" , buildID ) )
mt . segmentIndexLock . Lock ( )
defer mt . segmentIndexLock . Unlock ( )
segIdx , ok := mt . buildID2SegmentIndex [ buildID ]
if ! ok {
return nil
}
updateFunc := func ( segIdx * model . SegmentIndex ) error {
segIdx . IsDeleted = true
return mt . saveSegmentIndexMeta ( segIdx )
}
if err := mt . updateSegIndexMeta ( segIdx , updateFunc ) ; err != nil {
log . Warn ( "IndexCoord metaTable MarkSegIndexAsDeleted fail" , zap . Int64 ( "buildID" , buildID ) , zap . Error ( err ) )
return err
}
log . Info ( "IndexCoord metaTable MarkIndexAsDeleted success" , zap . Int64 ( "collID" , buildID ) )
return nil
}
func ( mt * metaTable ) MarkSegmentsIndexAsDeleted ( segIDs [ ] UniqueID ) error {
log . Info ( "IndexCoord metaTable MarkSegmentsIndexAsDeleted" , zap . Int64s ( "segIDs" , segIDs ) )
mt . segmentIndexLock . Lock ( )
defer mt . segmentIndexLock . Unlock ( )
buildIDs := make ( [ ] UniqueID , 0 )
segIdxes := make ( [ ] * model . SegmentIndex , 0 )
for _ , segID := range segIDs {
if segIndexes , ok := mt . segmentIndexes [ segID ] ; ok {
for _ , segIdx := range segIndexes {
if segIdx . IsDeleted {
continue
}
clonedSegIdx := model . CloneSegmentIndex ( segIdx )
clonedSegIdx . IsDeleted = true
segIdxes = append ( segIdxes , clonedSegIdx )
buildIDs = append ( buildIDs , segIdx . BuildID )
2021-05-27 22:24:29 +08:00
}
}
2022-08-25 15:48:54 +08:00
}
if len ( segIdxes ) == 0 {
log . Debug ( "IndexCoord metaTable MarkSegmentsIndexAsDeleted success, already have deleted" ,
zap . Int64s ( "segIDs" , segIDs ) )
return nil
}
err := mt . alterSegmentIndexes ( segIdxes )
if err != nil {
log . Error ( "IndexCoord metaTable MarkSegmentsIndexAsDeleted fail" , zap . Int64s ( "segIDs" , segIDs ) , zap . Error ( err ) )
return err
}
log . Info ( "IndexCoord metaTable MarkSegmentsIndexAsDeleted success" , zap . Int64s ( "segIDs" , segIDs ) )
return nil
}
// GetIndexFilePathInfo gets the index file paths from meta table.
func ( mt * metaTable ) GetIndexFilePathInfo ( segID , indexID UniqueID ) ( * indexpb . IndexFilePathInfo , error ) {
log . Debug ( "IndexCoord get index file path from meta table" , zap . Int64 ( "segmentID" , segID ) )
mt . segmentIndexLock . RLock ( )
defer mt . segmentIndexLock . RUnlock ( )
ret := & indexpb . IndexFilePathInfo {
SegmentID : segID ,
IndexID : indexID ,
}
segIndexes , ok := mt . segmentIndexes [ segID ]
if ! ok {
return nil , ErrNotIndexExist
}
segIdx , ok := segIndexes [ indexID ]
if ! ok || segIdx . IsDeleted {
return nil , ErrNotIndexExist
}
if segIdx . IndexState != commonpb . IndexState_Finished {
return nil , fmt . Errorf ( "the index state is not finish on segment: %d, index state = %s" , segID , segIdx . IndexState . String ( ) )
}
ret . BuildID = segIdx . BuildID
ret . IndexFilePaths = segIdx . IndexFilePaths
ret . SerializedSize = segIdx . IndexSize
log . Debug ( "IndexCoord get index file path success" , zap . Int64 ( "segID" , segID ) ,
zap . Strings ( "index files num" , ret . IndexFilePaths ) )
return ret , nil
}
func ( mt * metaTable ) GetIndexFilePathByBuildID ( buildID UniqueID ) ( bool , [ ] string ) {
mt . segmentIndexLock . RLock ( )
defer mt . segmentIndexLock . RUnlock ( )
log . Debug ( "IndexCoord get index file path from meta table" , zap . Int64 ( "buildID" , buildID ) )
segIdx , ok := mt . buildID2SegmentIndex [ buildID ]
if ! ok || segIdx . IsDeleted {
return false , [ ] string { }
}
if segIdx . IndexState != commonpb . IndexState_Finished && segIdx . IndexState != commonpb . IndexState_Failed {
return false , [ ] string { }
}
log . Debug ( "IndexCoord get index file path success" , zap . Int64 ( "buildID" , buildID ) ,
zap . Strings ( "index files num" , segIdx . IndexFilePaths ) )
return true , segIdx . IndexFilePaths
}
func ( mt * metaTable ) IsIndexDeleted ( collID , indexID UniqueID ) bool {
mt . indexLock . RLock ( )
defer mt . indexLock . RUnlock ( )
fieldIndexes , ok := mt . collectionIndexes [ collID ]
if ! ok {
return true
}
if index , ok := fieldIndexes [ indexID ] ; ! ok || index . IsDeleted {
return true
}
return false
}
func ( mt * metaTable ) IsSegIndexDeleted ( buildID UniqueID ) bool {
mt . segmentIndexLock . RLock ( )
defer mt . segmentIndexLock . RUnlock ( )
if segIdx , ok := mt . buildID2SegmentIndex [ buildID ] ; ! ok || segIdx . IsDeleted {
return true
}
return false
}
func ( mt * metaTable ) GetMetasByNodeID ( nodeID UniqueID ) [ ] * model . SegmentIndex {
mt . segmentIndexLock . RLock ( )
defer mt . segmentIndexLock . RUnlock ( )
metas := make ( [ ] * model . SegmentIndex , 0 )
for _ , meta := range mt . buildID2SegmentIndex {
if meta . IsDeleted {
2021-06-24 14:36:08 +08:00
continue
}
2022-08-25 15:48:54 +08:00
if nodeID == meta . NodeID {
metas = append ( metas , model . CloneSegmentIndex ( meta ) )
2021-06-24 14:36:08 +08:00
}
2022-08-25 15:48:54 +08:00
}
return metas
}
func ( mt * metaTable ) GetAllSegIndexes ( ) map [ int64 ] * model . SegmentIndex {
mt . segmentIndexLock . RLock ( )
defer mt . segmentIndexLock . RUnlock ( )
segIndexes := make ( map [ int64 ] * model . SegmentIndex )
for _ , meta := range mt . buildID2SegmentIndex {
segIndexes [ meta . SegmentID ] = model . CloneSegmentIndex ( meta )
}
return segIndexes
}
func ( mt * metaTable ) GetDeletedIndexes ( ) [ ] * model . Index {
mt . indexLock . RLock ( )
defer mt . indexLock . RUnlock ( )
var indexes [ ] * model . Index
for _ , fieldIndexes := range mt . collectionIndexes {
for _ , index := range fieldIndexes {
if index . IsDeleted {
indexes = append ( indexes , model . CloneIndex ( index ) )
2021-06-24 14:36:08 +08:00
}
}
2022-08-25 15:48:54 +08:00
}
return indexes
}
func ( mt * metaTable ) GetBuildIDsFromIndexID ( indexID UniqueID ) [ ] UniqueID {
mt . segmentIndexLock . RLock ( )
defer mt . segmentIndexLock . RUnlock ( )
buildIDs := make ( [ ] UniqueID , 0 )
for buildID , segIdx := range mt . buildID2SegmentIndex {
if segIdx . IndexID == indexID {
buildIDs = append ( buildIDs , buildID )
2021-06-24 14:36:08 +08:00
}
2022-08-25 15:48:54 +08:00
}
return buildIDs
}
func ( mt * metaTable ) GetBuildIDsFromSegIDs ( segIDs [ ] UniqueID ) [ ] UniqueID {
mt . segmentIndexLock . RLock ( )
defer mt . segmentIndexLock . RUnlock ( )
buildIDs := make ( [ ] UniqueID , 0 )
for _ , segID := range segIDs {
if segIdxes , ok := mt . segmentIndexes [ segID ] ; ok {
for _ , segIdx := range segIdxes {
buildIDs = append ( buildIDs , segIdx . BuildID )
}
2022-07-07 14:44:21 +08:00
}
2021-05-27 22:24:29 +08:00
}
2022-08-25 15:48:54 +08:00
return buildIDs
}
2021-06-24 14:36:08 +08:00
2022-08-25 15:48:54 +08:00
// RemoveIndex remove the index on the collection from meta table.
func ( mt * metaTable ) RemoveIndex ( collID , indexID UniqueID ) error {
mt . indexLock . Lock ( )
defer mt . indexLock . Unlock ( )
err := mt . catalog . DropIndex ( context . Background ( ) , collID , indexID )
if err != nil {
return err
}
delete ( mt . collectionIndexes [ collID ] , indexID )
return nil
2021-05-27 22:24:29 +08:00
}
2022-08-25 15:48:54 +08:00
// RemoveSegmentIndex remove the index on the segment from meta table.
func ( mt * metaTable ) RemoveSegmentIndex ( collID , partID , segID , buildID UniqueID ) error {
mt . segmentIndexLock . Lock ( )
defer mt . segmentIndexLock . Unlock ( )
2021-05-27 22:24:29 +08:00
2022-08-25 15:48:54 +08:00
err := mt . catalog . DropSegmentIndex ( context . Background ( ) , collID , partID , segID , buildID )
if err != nil {
return err
2021-05-27 22:24:29 +08:00
}
2022-08-25 15:48:54 +08:00
segIdx , ok := mt . buildID2SegmentIndex [ buildID ]
if ! ok {
return nil
2021-05-27 22:24:29 +08:00
}
2022-08-25 15:48:54 +08:00
delete ( mt . segmentIndexes [ segIdx . SegmentID ] , segIdx . IndexID )
delete ( mt . buildID2SegmentIndex , buildID )
return nil
2021-01-19 18:32:57 +08:00
}
2021-09-14 10:41:21 +08:00
2022-08-25 15:48:54 +08:00
// HasBuildID checks if there is an index corresponding the buildID in the meta table.
2022-07-08 16:54:22 +08:00
func ( mt * metaTable ) HasBuildID ( buildID UniqueID ) bool {
2022-08-25 15:48:54 +08:00
mt . segmentIndexLock . RLock ( )
defer mt . segmentIndexLock . RUnlock ( )
2021-09-14 10:41:21 +08:00
2022-08-25 15:48:54 +08:00
_ , ok := mt . buildID2SegmentIndex [ buildID ]
2022-07-08 16:54:22 +08:00
return ok
2021-09-14 10:41:21 +08:00
}
2022-08-25 15:48:54 +08:00
// ResetNodeID resets the nodeID of the index meta corresponding the buildID.
func ( mt * metaTable ) ResetNodeID ( buildID UniqueID ) error {
mt . segmentIndexLock . Lock ( )
defer mt . segmentIndexLock . Unlock ( )
updateFunc := func ( sedIdx * model . SegmentIndex ) error {
sedIdx . NodeID = 0
return mt . saveSegmentIndexMeta ( sedIdx )
}
segIdx , ok := mt . buildID2SegmentIndex [ buildID ]
if ! ok {
return fmt . Errorf ( "there is no index with buildID: %d" , buildID )
}
return mt . updateSegIndexMeta ( segIdx , updateFunc )
}
// ResetMeta resets the nodeID and index state of the index meta corresponding the buildID.
func ( mt * metaTable ) ResetMeta ( buildID UniqueID ) error {
mt . segmentIndexLock . Lock ( )
defer mt . segmentIndexLock . Unlock ( )
segIdx , ok := mt . buildID2SegmentIndex [ buildID ]
if ! ok {
return fmt . Errorf ( "there is no index with buildID: %d" , buildID )
}
updateFunc := func ( sedIdx * model . SegmentIndex ) error {
sedIdx . NodeID = 0
segIdx . IndexState = commonpb . IndexState_Unissued
return mt . saveSegmentIndexMeta ( sedIdx )
}
return mt . updateSegIndexMeta ( segIdx , updateFunc )
}
func ( mt * metaTable ) FinishTask ( buildID UniqueID , state commonpb . IndexState , filePaths [ ] string ) error {
mt . segmentIndexLock . Lock ( )
defer mt . segmentIndexLock . Unlock ( )
segIdx , ok := mt . buildID2SegmentIndex [ buildID ]
if ! ok || segIdx . IsDeleted {
return fmt . Errorf ( "there is no index with buildID: %d" , buildID )
}
updateFunc := func ( segIdx * model . SegmentIndex ) error {
segIdx . IndexState = state
segIdx . IndexFilePaths = filePaths
return mt . saveSegmentIndexMeta ( segIdx )
}
return mt . updateSegIndexMeta ( segIdx , updateFunc )
}