2021-10-27 10:04:47 +00: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 10:32:57 +00:00
// with the License. You may obtain a copy of the License at
//
2021-10-27 10:04:47 +00:00
// http://www.apache.org/licenses/LICENSE-2.0
2021-01-19 10:32:57 +00:00
//
2021-10-27 10:04:47 +00: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 10:32:57 +00:00
2021-06-21 09:28:03 +00:00
package indexcoord
2021-01-19 10:32:57 +00:00
import (
2021-06-23 01:24:10 +00:00
"context"
2021-09-08 06:23:59 +00:00
"errors"
2021-01-19 10:32:57 +00:00
"fmt"
2022-05-31 08:36:03 +00:00
"path"
2022-06-23 02:40:13 +00:00
"sort"
2021-01-19 10:32:57 +00:00
"strconv"
"sync"
2021-05-27 14:24:29 +00:00
2022-06-27 13:52:17 +00:00
"github.com/milvus-io/milvus/internal/kv"
2022-02-21 09:15:51 +00:00
"github.com/milvus-io/milvus/internal/metrics"
2021-03-10 01:56:09 +00:00
"go.uber.org/zap"
2021-01-19 10:32:57 +00:00
"github.com/golang/protobuf/proto"
2021-04-22 06:45:57 +00:00
"github.com/milvus-io/milvus/internal/log"
"github.com/milvus-io/milvus/internal/proto/commonpb"
"github.com/milvus-io/milvus/internal/proto/indexpb"
2021-12-16 07:31:52 +00:00
"github.com/milvus-io/milvus/internal/util/retry"
2021-01-19 10:32:57 +00:00
)
2021-09-23 13:37:55 +00:00
// Meta is used to record the state of the index.
2021-12-14 10:33:32 +00:00
// revision: The number of times IndexMeta has been changed in etcd. It's the same as Event.Kv.Version in etcd.
// indexMeta: A structure that records the state of the index defined by proto.
2021-05-27 14:24:29 +00:00
type Meta struct {
2022-07-06 05:54:21 +00:00
indexMeta * indexpb . IndexMeta
indexVersion int64
2021-05-27 14:24:29 +00:00
}
2021-12-06 10:31:47 +00:00
// metaTable records the mapping of IndexBuildID to Meta.
2021-01-19 10:32:57 +00:00
type metaTable struct {
2022-06-27 13:52:17 +00:00
client kv . MetaKv // client of a reliable kv service, i.e. etcd client
2021-05-27 14:24:29 +00:00
indexBuildID2Meta map [ UniqueID ] Meta // index build id to index meta
2021-01-19 10:32:57 +00:00
2022-06-27 13:52:17 +00:00
revision int64
2021-01-19 10:32:57 +00:00
lock sync . RWMutex
}
2021-09-23 13:37:55 +00:00
// NewMetaTable is used to create a new meta table.
2022-06-27 13:52:17 +00:00
func NewMetaTable ( kv kv . MetaKv ) ( * metaTable , error ) {
2021-01-19 10:32:57 +00:00
mt := & metaTable {
client : kv ,
lock : sync . RWMutex { } ,
}
err := mt . reloadFromKV ( )
if err != nil {
return nil , err
}
return mt , nil
}
2021-12-08 01:33:41 +00:00
// reloadFromKV reloads the index meta from ETCD.
2021-01-19 10:32:57 +00:00
func ( mt * metaTable ) reloadFromKV ( ) error {
2021-05-27 14:24:29 +00:00
mt . indexBuildID2Meta = make ( map [ UniqueID ] Meta )
2022-06-06 08:26:06 +00:00
key := indexFilePrefix
2021-06-21 09:28:03 +00:00
log . Debug ( "IndexCoord metaTable LoadWithPrefix " , zap . String ( "prefix" , key ) )
2021-01-19 10:32:57 +00:00
2022-06-27 13:52:17 +00:00
_ , values , versions , revision , err := mt . client . LoadWithRevisionAndVersions ( key )
2021-01-19 10:32:57 +00:00
if err != nil {
return err
}
2022-06-27 13:52:17 +00:00
mt . revision = revision
2021-05-27 14:24:29 +00:00
for i := 0 ; i < len ( values ) ; i ++ {
2021-01-26 01:38:40 +00:00
indexMeta := indexpb . IndexMeta { }
2021-09-29 12:26:00 +00:00
err = proto . Unmarshal ( [ ] byte ( values [ i ] ) , & indexMeta )
2021-01-19 10:32:57 +00:00
if err != nil {
2021-12-23 06:25:53 +00:00
return fmt . Errorf ( "IndexCoord metaTable reloadFromKV UnmarshalText indexpb.IndexMeta err:%w" , err )
2021-01-19 10:32:57 +00:00
}
2021-05-27 14:24:29 +00:00
meta := & Meta {
2022-07-06 05:54:21 +00:00
indexMeta : & indexMeta ,
indexVersion : versions [ i ] ,
2021-05-27 14:24:29 +00:00
}
mt . indexBuildID2Meta [ indexMeta . IndexBuildID ] = * meta
2021-01-19 10:32:57 +00:00
}
return nil
}
2021-12-08 01:31:47 +00:00
// saveIndexMeta saves the index meta to ETCD.
2021-01-19 10:32:57 +00:00
// metaTable.lock.Lock() before call this function
2021-05-27 14:24:29 +00:00
func ( mt * metaTable ) saveIndexMeta ( meta * Meta ) error {
2021-09-29 12:26:00 +00:00
value , err := proto . Marshal ( meta . indexMeta )
if err != nil {
return err
}
2022-05-31 08:36:03 +00:00
key := path . Join ( indexFilePrefix , strconv . FormatInt ( meta . indexMeta . IndexBuildID , 10 ) )
2022-07-06 05:54:21 +00:00
success , err := mt . client . CompareVersionAndSwap ( key , meta . indexVersion , string ( value ) )
2021-05-27 14:24:29 +00:00
if err != nil {
2022-07-06 05:54:21 +00:00
// TODO, we don't need to reload if it is just etcd error
log . Warn ( "failed to save index meta in etcd" , zap . Int64 ( "buildID" , meta . indexMeta . IndexBuildID ) , zap . Error ( err ) )
2021-05-27 14:24:29 +00:00
return err
}
2022-07-06 05:54:21 +00:00
if ! success {
log . Warn ( "failed to save index meta in etcd because version compare failure" , zap . Int64 ( "buildID" , meta . indexMeta . IndexBuildID ) , zap . Any ( "index" , meta . indexMeta ) )
return fmt . Errorf ( "failed to save index meta in etcd, buildId: %d, source version: %d" , meta . indexMeta . IndexBuildID , meta . indexVersion )
}
meta . indexVersion = meta . indexVersion + 1
2021-05-27 14:24:29 +00:00
mt . indexBuildID2Meta [ meta . indexMeta . IndexBuildID ] = * meta
2022-07-06 05:54:21 +00:00
log . Info ( "IndexCoord metaTable saveIndexMeta success" , zap . Int64 ( "buildID" , meta . indexMeta . IndexBuildID ) , zap . Any ( "meta.revision" , meta . indexVersion ) )
2021-05-27 14:24:29 +00:00
return nil
}
2021-12-08 01:35:32 +00:00
// reloadMeta reloads the index meta corresponding indexBuildID from ETCD.
2021-05-27 14:24:29 +00:00
func ( mt * metaTable ) reloadMeta ( indexBuildID UniqueID ) ( * Meta , error ) {
2022-06-06 08:26:06 +00:00
key := path . Join ( indexFilePrefix , strconv . FormatInt ( indexBuildID , 10 ) )
2021-05-27 14:24:29 +00:00
_ , values , version , err := mt . client . LoadWithPrefix2 ( key )
2021-06-21 09:28:03 +00:00
log . Debug ( "IndexCoord reloadMeta mt.client.LoadWithPrefix2" , zap . Any ( "indexBuildID" , indexBuildID ) , zap . Error ( err ) )
2021-05-27 14:24:29 +00:00
if err != nil {
return nil , err
}
2021-09-08 06:23:59 +00:00
if len ( values ) == 0 {
log . Error ( "IndexCoord reload Meta" , zap . Any ( "indexBuildID" , indexBuildID ) , zap . Error ( errors . New ( "meta doesn't exist in KV" ) ) )
return nil , errors . New ( "meta doesn't exist in KV" )
}
2021-05-27 14:24:29 +00:00
im := & indexpb . IndexMeta { }
2021-09-29 12:26:00 +00:00
err = proto . Unmarshal ( [ ] byte ( values [ 0 ] ) , im )
2021-05-27 14:24:29 +00:00
if err != nil {
return nil , err
}
2021-06-06 01:41:35 +00:00
//if im.State == commonpb.IndexState_Finished {
// return nil, nil
//}
2021-05-27 14:24:29 +00:00
m := & Meta {
2022-07-06 05:54:21 +00:00
indexVersion : version [ 0 ] ,
indexMeta : im ,
2021-05-27 14:24:29 +00:00
}
2021-01-19 10:32:57 +00:00
2021-05-27 14:24:29 +00:00
return m , nil
2021-01-19 10:32:57 +00:00
}
2021-12-08 08:45:23 +00:00
// AddIndex adds the index meta corresponding the indexBuildID to meta table.
2021-02-02 11:56:04 +00:00
func ( mt * metaTable ) AddIndex ( indexBuildID UniqueID , req * indexpb . BuildIndexRequest ) error {
2021-01-19 10:32:57 +00:00
mt . lock . Lock ( )
defer mt . lock . Unlock ( )
2021-02-02 11:56:04 +00:00
_ , ok := mt . indexBuildID2Meta [ indexBuildID ]
2021-07-22 03:40:11 +00:00
log . Debug ( "IndexCoord metaTable AddIndex" , zap . Any ( "indexBuildID" , indexBuildID ) , zap . Any ( " index already exist" , ok ) )
2021-01-19 10:32:57 +00:00
if ok {
2021-03-05 02:15:27 +00:00
return fmt . Errorf ( "index already exists with ID = %d" , indexBuildID )
2021-01-19 10:32:57 +00:00
}
2021-05-27 14:24:29 +00:00
meta := & Meta {
indexMeta : & indexpb . IndexMeta {
State : commonpb . IndexState_Unissued ,
IndexBuildID : indexBuildID ,
Req : req ,
2021-05-31 02:32:30 +00:00
NodeID : 0 ,
2021-05-27 14:24:29 +00:00
Version : 0 ,
} ,
2022-07-06 05:54:21 +00:00
indexVersion : 0 ,
2021-01-19 10:32:57 +00:00
}
2022-02-21 09:15:51 +00:00
metrics . IndexCoordIndexTaskCounter . WithLabelValues ( metrics . UnissuedIndexTaskLabel ) . Inc ( )
2021-01-19 10:32:57 +00:00
return mt . saveIndexMeta ( meta )
}
2021-12-08 08:47:17 +00:00
// BuildIndex set the index state to be InProgress. It means IndexNode is building the index.
2021-05-31 02:32:30 +00:00
func ( mt * metaTable ) BuildIndex ( indexBuildID UniqueID , nodeID int64 ) error {
2021-04-16 07:37:13 +00:00
mt . lock . Lock ( )
defer mt . lock . Unlock ( )
2021-06-21 09:28:03 +00:00
log . Debug ( "IndexCoord metaTable BuildIndex" )
2021-04-16 07:37:13 +00:00
meta , ok := mt . indexBuildID2Meta [ indexBuildID ]
if ! ok {
2021-09-26 13:23:57 +00:00
log . Error ( "IndexCoord metaTable BuildIndex index not exists" , zap . Any ( "indexBuildID" , indexBuildID ) )
2021-04-16 07:37:13 +00:00
return fmt . Errorf ( "index not exists with ID = %d" , indexBuildID )
}
2021-06-06 01:41:35 +00:00
//if meta.indexMeta.State != commonpb.IndexState_Unissued {
// return fmt.Errorf("can not set lease key, index with ID = %d state is %d", indexBuildID, meta.indexMeta.State)
//}
2021-10-28 10:20:27 +00:00
if meta . indexMeta . State == commonpb . IndexState_Finished || meta . indexMeta . State == commonpb . IndexState_Failed {
log . Debug ( "This index task has been finished" , zap . Int64 ( "indexBuildID" , indexBuildID ) ,
zap . Any ( "index state" , meta . indexMeta . State ) )
return nil
}
2021-05-31 02:32:30 +00:00
meta . indexMeta . NodeID = nodeID
2021-06-06 01:41:35 +00:00
meta . indexMeta . State = commonpb . IndexState_InProgress
2022-02-21 09:15:51 +00:00
metrics . IndexCoordIndexTaskCounter . WithLabelValues ( metrics . UnissuedIndexTaskLabel ) . Dec ( )
metrics . IndexCoordIndexTaskCounter . WithLabelValues ( metrics . InProgressIndexTaskLabel ) . Inc ( )
2021-05-27 14:24:29 +00:00
err := mt . saveIndexMeta ( & meta )
if err != nil {
fn := func ( ) error {
m , err := mt . reloadMeta ( meta . indexMeta . IndexBuildID )
if m == nil {
return err
}
2021-05-31 02:32:30 +00:00
m . indexMeta . NodeID = nodeID
2021-05-27 14:24:29 +00:00
return mt . saveIndexMeta ( m )
}
2021-06-23 01:24:10 +00:00
err2 := retry . Do ( context . TODO ( ) , fn , retry . Attempts ( 5 ) )
2021-05-27 14:24:29 +00:00
if err2 != nil {
return err2
}
}
return nil
2021-04-16 07:37:13 +00:00
}
2021-12-08 08:49:05 +00:00
// UpdateVersion updates the version of the index meta, whenever the task is built once, the version will be updated once.
2021-05-27 14:24:29 +00:00
func ( mt * metaTable ) UpdateVersion ( indexBuildID UniqueID ) error {
2021-02-23 03:57:18 +00:00
mt . lock . Lock ( )
defer mt . lock . Unlock ( )
2021-06-21 09:28:03 +00:00
log . Debug ( "IndexCoord metaTable update UpdateVersion" , zap . Any ( "IndexBuildId" , indexBuildID ) )
2021-05-27 14:24:29 +00:00
meta , ok := mt . indexBuildID2Meta [ indexBuildID ]
if ! ok {
2021-09-26 13:23:57 +00:00
log . Warn ( "IndexCoord metaTable update UpdateVersion indexBuildID not exists" , zap . Any ( "IndexBuildId" , indexBuildID ) )
2021-05-27 14:24:29 +00:00
return fmt . Errorf ( "index not exists with ID = %d" , indexBuildID )
}
2021-02-23 03:57:18 +00:00
2021-06-06 01:41:35 +00:00
//if meta.indexMeta.State != commonpb.IndexState_Unissued {
// return fmt.Errorf("can not set lease key, index with ID = %d state is %d", indexBuildID, meta.indexMeta.State)
//}
2021-03-26 02:01:08 +00:00
2021-05-27 14:24:29 +00:00
meta . indexMeta . Version = meta . indexMeta . Version + 1
2021-06-21 09:28:03 +00:00
log . Debug ( "IndexCoord metaTable update UpdateVersion" , zap . Any ( "IndexBuildId" , indexBuildID ) ,
2021-06-06 01:41:35 +00:00
zap . Any ( "Version" , meta . indexMeta . Version ) )
2021-05-27 14:24:29 +00:00
err := mt . saveIndexMeta ( & meta )
if err != nil {
fn := func ( ) error {
m , err := mt . reloadMeta ( meta . indexMeta . IndexBuildID )
if m == nil {
return err
}
m . indexMeta . Version = m . indexMeta . Version + 1
return mt . saveIndexMeta ( m )
2021-02-23 03:57:18 +00:00
}
2021-06-23 01:24:10 +00:00
err2 := retry . Do ( context . TODO ( ) , fn , retry . Attempts ( 5 ) )
2021-05-27 14:24:29 +00:00
return err2
2021-02-23 03:57:18 +00:00
}
return nil
}
2021-12-09 07:31:18 +00:00
// MarkIndexAsDeleted will mark the corresponding index as deleted, and recycleUnusedIndexFiles will recycle these tasks.
2022-06-28 04:08:17 +00:00
func ( mt * metaTable ) MarkIndexAsDeleted ( indexID UniqueID ) error {
2021-01-19 10:32:57 +00:00
mt . lock . Lock ( )
defer mt . lock . Unlock ( )
2021-03-26 02:01:08 +00:00
2021-06-21 09:28:03 +00:00
log . Debug ( "IndexCoord metaTable MarkIndexAsDeleted " , zap . Int64 ( "indexID" , indexID ) )
2021-01-19 10:32:57 +00:00
2022-06-28 04:08:17 +00:00
for buildID , meta := range mt . indexBuildID2Meta {
2021-07-29 06:47:22 +00:00
if meta . indexMeta . Req . IndexID == indexID && ! meta . indexMeta . MarkDeleted {
2021-05-27 14:24:29 +00:00
meta . indexMeta . MarkDeleted = true
2022-06-28 04:08:17 +00:00
log . Debug ( "IndexCoord metaTable MarkIndexAsDeleted " , zap . Int64 ( "indexID" , indexID ) ,
zap . Int64 ( "buildID" , buildID ) )
2021-09-18 06:45:50 +00:00
// marshal inside
/* #nosec G601 */
2021-05-27 14:24:29 +00:00
if err := mt . saveIndexMeta ( & meta ) ; err != nil {
2021-09-26 13:23:57 +00:00
log . Error ( "IndexCoord metaTable MarkIndexAsDeleted saveIndexMeta failed" , zap . Error ( err ) )
2021-05-27 14:24:29 +00:00
fn := func ( ) error {
m , err := mt . reloadMeta ( meta . indexMeta . IndexBuildID )
if m == nil {
return err
}
m . indexMeta . MarkDeleted = true
return mt . saveIndexMeta ( m )
}
2021-06-23 01:24:10 +00:00
err2 := retry . Do ( context . TODO ( ) , fn , retry . Attempts ( 5 ) )
2021-05-27 14:24:29 +00:00
if err2 != nil {
2022-06-28 04:08:17 +00:00
return err2
2021-05-27 14:24:29 +00:00
}
}
}
2021-01-19 10:32:57 +00:00
}
2022-06-28 04:08:17 +00:00
log . Debug ( "IndexCoord metaTable MarkIndexAsDeleted success" , zap . Int64 ( "indexID" , indexID ) )
return nil
2021-01-19 10:32:57 +00:00
}
2022-06-28 04:08:17 +00:00
func ( mt * metaTable ) MarkIndexAsDeletedByBuildIDs ( buildIDs [ ] UniqueID ) error {
2022-06-17 10:08:12 +00:00
mt . lock . Lock ( )
defer mt . lock . Unlock ( )
log . Debug ( "IndexCoord metaTable MarkIndexAsDeletedByBuildIDs " , zap . Int64s ( "buildIDs" , buildIDs ) )
for _ , buildID := range buildIDs {
if meta , ok := mt . indexBuildID2Meta [ buildID ] ; ok {
clonedMeta := & Meta {
2022-07-06 05:54:21 +00:00
indexMeta : proto . Clone ( meta . indexMeta ) . ( * indexpb . IndexMeta ) ,
indexVersion : meta . indexVersion ,
2022-06-17 10:08:12 +00:00
}
clonedMeta . indexMeta . MarkDeleted = true
// marshal inside
/* #nosec G601 */
if err := mt . saveIndexMeta ( clonedMeta ) ; err != nil {
log . Error ( "IndexCoord metaTable MarkIndexAsDeleted saveIndexMeta failed" , zap . Error ( err ) )
fn := func ( ) error {
m , err := mt . reloadMeta ( meta . indexMeta . IndexBuildID )
if m == nil {
return err
}
m . indexMeta . MarkDeleted = true
return mt . saveIndexMeta ( m )
}
err2 := retry . Do ( context . TODO ( ) , fn , retry . Attempts ( 5 ) )
if err2 != nil {
2022-06-28 04:08:17 +00:00
return err2
2022-06-17 10:08:12 +00:00
}
}
}
}
2022-06-28 04:08:17 +00:00
log . Debug ( "IndexCoord metaTable MarkIndexAsDeletedByBuildIDs success" , zap . Int64s ( "buildIDs" , buildIDs ) )
return nil
2022-06-17 10:08:12 +00:00
}
2021-12-09 07:47:51 +00:00
// GetIndexStates gets the index states from meta table.
2021-06-30 06:32:19 +00:00
func ( mt * metaTable ) GetIndexStates ( indexBuildIDs [ ] UniqueID ) [ ] * indexpb . IndexInfo {
2021-01-19 10:32:57 +00:00
mt . lock . Lock ( )
defer mt . lock . Unlock ( )
2021-12-23 09:13:15 +00:00
log . Debug ( "IndexCoord get index states from meta table" , zap . Int64s ( "indexBuildIDs" , indexBuildIDs ) )
2021-06-30 06:32:19 +00:00
var indexStates [ ] * indexpb . IndexInfo
for _ , id := range indexBuildIDs {
state := & indexpb . IndexInfo {
IndexBuildID : id ,
}
meta , ok := mt . indexBuildID2Meta [ id ]
if ! ok {
state . Reason = fmt . Sprintf ( "index %d not exists" , id )
} else if meta . indexMeta . MarkDeleted {
state . Reason = fmt . Sprintf ( "index %d has been deleted" , id )
} else {
state . State = meta . indexMeta . State
state . IndexID = meta . indexMeta . Req . IndexID
state . IndexName = meta . indexMeta . Req . IndexName
state . Reason = meta . indexMeta . FailReason
}
indexStates = append ( indexStates , state )
2021-02-23 03:57:18 +00:00
}
2021-06-30 06:32:19 +00:00
return indexStates
2021-01-19 10:32:57 +00:00
}
2021-12-09 07:49:51 +00:00
// GetIndexFilePathInfo gets the index file paths from meta table.
2021-02-02 11:56:04 +00:00
func ( mt * metaTable ) GetIndexFilePathInfo ( indexBuildID UniqueID ) ( * indexpb . IndexFilePathInfo , error ) {
2021-01-19 10:32:57 +00:00
mt . lock . Lock ( )
defer mt . lock . Unlock ( )
2021-12-23 13:38:34 +00:00
log . Debug ( "IndexCoord get index file path from meta table" , zap . Int64 ( "indexBuildID" , indexBuildID ) )
2021-01-26 01:38:40 +00:00
ret := & indexpb . IndexFilePathInfo {
2021-02-02 11:56:04 +00:00
IndexBuildID : indexBuildID ,
2021-01-26 01:38:40 +00:00
}
2021-02-02 11:56:04 +00:00
meta , ok := mt . indexBuildID2Meta [ indexBuildID ]
2021-01-19 10:32:57 +00:00
if ! ok {
2021-03-05 02:15:27 +00:00
return nil , fmt . Errorf ( "index not exists with ID = %d" , indexBuildID )
2021-01-19 10:32:57 +00:00
}
2021-05-27 14:24:29 +00:00
if meta . indexMeta . MarkDeleted {
2021-03-05 02:15:27 +00:00
return nil , fmt . Errorf ( "index not exists with ID = %d" , indexBuildID )
2022-05-17 12:41:56 +00:00
}
if meta . indexMeta . State != commonpb . IndexState_Finished {
return nil , fmt . Errorf ( "index not finished with ID = %d" , indexBuildID )
2021-02-23 03:57:18 +00:00
}
2021-05-27 14:24:29 +00:00
ret . IndexFilePaths = meta . indexMeta . IndexFilePaths
2021-12-22 12:27:34 +00:00
ret . SerializedSize = meta . indexMeta . GetSerializeSize ( )
2021-12-23 13:38:34 +00:00
log . Debug ( "IndexCoord get index file path successfully" , zap . Int64 ( "indexBuildID" , indexBuildID ) ,
2022-03-28 13:27:27 +00:00
zap . Int ( "index files num" , len ( ret . IndexFilePaths ) ) )
2021-01-26 01:38:40 +00:00
return ret , nil
2021-01-19 10:32:57 +00:00
}
2021-12-10 13:09:00 +00:00
// DeleteIndex delete the index meta from meta table.
2021-04-16 07:37:13 +00:00
func ( mt * metaTable ) DeleteIndex ( indexBuildID UniqueID ) {
2021-02-23 03:57:18 +00:00
mt . lock . Lock ( )
defer mt . lock . Unlock ( )
2021-04-16 07:37:13 +00:00
delete ( mt . indexBuildID2Meta , indexBuildID )
2022-06-06 08:26:06 +00:00
key := path . Join ( indexFilePrefix , strconv . FormatInt ( indexBuildID , 10 ) )
2021-05-27 14:24:29 +00:00
2021-12-23 13:40:25 +00:00
if err := mt . client . Remove ( key ) ; err != nil {
log . Error ( "IndexCoord delete index meta from etcd failed" , zap . Error ( err ) )
}
log . Debug ( "IndexCoord delete index meta successfully" , zap . Int64 ( "indexBuildID" , indexBuildID ) )
2021-02-23 03:57:18 +00:00
}
2021-12-10 09:07:22 +00:00
// UpdateRecycleState update the recycle state corresponding the indexBuildID,
// when the recycle state is true, means the index files has been recycled with lower version.
2021-05-27 14:24:29 +00:00
func ( mt * metaTable ) UpdateRecycleState ( indexBuildID UniqueID ) error {
2021-02-23 03:57:18 +00:00
mt . lock . Lock ( )
defer mt . lock . Unlock ( )
2021-05-27 14:24:29 +00:00
meta , ok := mt . indexBuildID2Meta [ indexBuildID ]
2021-06-21 09:28:03 +00:00
log . Debug ( "IndexCoord metaTable UpdateRecycleState" , zap . Any ( "indexBuildID" , indexBuildID ) ,
2021-06-06 01:41:35 +00:00
zap . Any ( "exists" , ok ) )
2021-05-27 14:24:29 +00:00
if ! ok {
return fmt . Errorf ( "index not exists with ID = %d" , indexBuildID )
}
2021-06-06 01:41:35 +00:00
if meta . indexMeta . Recycled {
return nil
}
2021-05-27 14:24:29 +00:00
meta . indexMeta . Recycled = true
if err := mt . saveIndexMeta ( & meta ) ; err != nil {
fn := func ( ) error {
m , err := mt . reloadMeta ( meta . indexMeta . IndexBuildID )
if m == nil {
return err
}
2021-01-19 10:32:57 +00:00
2021-05-27 14:24:29 +00:00
m . indexMeta . Recycled = true
return mt . saveIndexMeta ( m )
}
2021-06-23 01:24:10 +00:00
err2 := retry . Do ( context . TODO ( ) , fn , retry . Attempts ( 5 ) )
2021-05-27 14:24:29 +00:00
if err2 != nil {
2021-06-06 01:41:35 +00:00
meta . indexMeta . Recycled = false
2021-09-26 13:23:57 +00:00
log . Error ( "IndexCoord metaTable UpdateRecycleState failed" , zap . Error ( err2 ) )
2021-05-27 14:24:29 +00:00
return err2
}
}
return nil
}
2021-12-10 09:09:08 +00:00
// GetUnusedIndexFiles get the index files with lower version or corresponding the indexBuildIDs which has been deleted.
2021-05-27 14:24:29 +00:00
func ( mt * metaTable ) GetUnusedIndexFiles ( limit int ) [ ] Meta {
mt . lock . Lock ( )
defer mt . lock . Unlock ( )
var metas [ ] Meta
2021-04-16 07:37:13 +00:00
for _ , meta := range mt . indexBuildID2Meta {
2021-05-27 14:24:29 +00:00
if meta . indexMeta . State == commonpb . IndexState_Finished && ( meta . indexMeta . MarkDeleted || ! meta . indexMeta . Recycled ) {
2022-07-06 05:54:21 +00:00
metas = append ( metas , Meta { indexMeta : proto . Clone ( meta . indexMeta ) . ( * indexpb . IndexMeta ) , indexVersion : meta . indexVersion } )
2022-06-28 04:08:17 +00:00
}
if meta . indexMeta . State == commonpb . IndexState_Unissued && meta . indexMeta . MarkDeleted {
2022-07-06 05:54:21 +00:00
metas = append ( metas , Meta { indexMeta : proto . Clone ( meta . indexMeta ) . ( * indexpb . IndexMeta ) , indexVersion : meta . indexVersion } )
2021-05-27 14:24:29 +00:00
}
if len ( metas ) >= limit {
return metas
}
}
return metas
}
2022-06-23 02:40:13 +00:00
func sortMetaPolicy ( metas [ ] Meta ) [ ] Meta {
// the larger the segment, the higher the priority
sort . Slice ( metas , func ( i , j int ) bool {
return metas [ i ] . indexMeta . Version < metas [ j ] . indexMeta . Version ||
( metas [ i ] . indexMeta . Version == metas [ j ] . indexMeta . Version &&
metas [ i ] . indexMeta . Req . NumRows > metas [ j ] . indexMeta . Req . NumRows )
} )
return metas
}
2021-12-14 08:55:07 +00:00
// GetUnassignedTasks get the unassigned tasks.
2021-07-14 06:15:55 +00:00
func ( mt * metaTable ) GetUnassignedTasks ( onlineNodeIDs [ ] int64 ) [ ] Meta {
mt . lock . RLock ( )
defer mt . lock . RUnlock ( )
var metas [ ] Meta
for _ , meta := range mt . indexBuildID2Meta {
2022-06-23 02:40:13 +00:00
if meta . indexMeta . MarkDeleted {
continue
}
2021-07-14 06:15:55 +00:00
if meta . indexMeta . State == commonpb . IndexState_Unissued {
2022-07-06 05:54:21 +00:00
metas = append ( metas , Meta { indexMeta : proto . Clone ( meta . indexMeta ) . ( * indexpb . IndexMeta ) , indexVersion : meta . indexVersion } )
2021-07-14 06:15:55 +00:00
continue
}
if meta . indexMeta . State == commonpb . IndexState_Finished || meta . indexMeta . State == commonpb . IndexState_Failed {
continue
}
2021-05-27 14:24:29 +00:00
alive := false
2021-07-14 06:15:55 +00:00
for _ , serverID := range onlineNodeIDs {
2021-05-31 02:32:30 +00:00
if meta . indexMeta . NodeID == serverID {
2021-05-27 14:24:29 +00:00
alive = true
2021-07-14 06:15:55 +00:00
break
2021-05-27 14:24:29 +00:00
}
}
if ! alive {
2021-12-04 03:39:34 +00:00
log . Info ( "Reassign because node no longer alive" , zap . Any ( "onlineID" , onlineNodeIDs ) , zap . Int64 ( "nodeID" , meta . indexMeta . NodeID ) )
2022-07-06 05:54:21 +00:00
metas = append ( metas , Meta { indexMeta : proto . Clone ( meta . indexMeta ) . ( * indexpb . IndexMeta ) , indexVersion : meta . indexVersion } )
2021-05-27 14:24:29 +00:00
}
}
2022-06-23 02:40:13 +00:00
return sortMetaPolicy ( metas )
2021-05-27 14:24:29 +00:00
}
2021-12-14 10:39:09 +00:00
// HasSameReq determine whether there are same indexing tasks.
2021-05-27 14:24:29 +00:00
func ( mt * metaTable ) HasSameReq ( req * indexpb . BuildIndexRequest ) ( bool , UniqueID ) {
2022-05-31 08:36:03 +00:00
mt . lock . RLock ( )
defer mt . lock . RUnlock ( )
2021-05-27 14:24:29 +00:00
for _ , meta := range mt . indexBuildID2Meta {
2022-05-31 08:36:03 +00:00
if req . GetSegmentID ( ) != meta . indexMeta . Req . GetSegmentID ( ) {
continue
}
2021-06-24 06:36:08 +00:00
if meta . indexMeta . Req . IndexID != req . IndexID {
continue
}
if meta . indexMeta . Req . IndexName != req . IndexName {
continue
}
if len ( meta . indexMeta . Req . DataPaths ) != len ( req . DataPaths ) {
continue
}
notEq := false
for i := range meta . indexMeta . Req . DataPaths {
if meta . indexMeta . Req . DataPaths [ i ] != req . DataPaths [ i ] {
notEq = true
break
2021-05-27 14:24:29 +00:00
}
2021-06-24 06:36:08 +00:00
}
if notEq {
continue
}
if len ( meta . indexMeta . Req . TypeParams ) != len ( req . TypeParams ) {
continue
}
notEq = false
for i := range meta . indexMeta . Req . TypeParams {
if meta . indexMeta . Req . TypeParams [ i ] . Key != req . TypeParams [ i ] . Key {
notEq = true
break
}
if meta . indexMeta . Req . TypeParams [ i ] . Value != req . TypeParams [ i ] . Value {
notEq = true
break
2021-05-27 14:24:29 +00:00
}
}
2021-06-24 06:36:08 +00:00
if notEq {
continue
}
if len ( meta . indexMeta . Req . IndexParams ) != len ( req . IndexParams ) {
continue
}
notEq = false
for i := range meta . indexMeta . Req . IndexParams {
if meta . indexMeta . Req . IndexParams [ i ] . Key != req . IndexParams [ i ] . Key {
notEq = true
break
}
if meta . indexMeta . Req . IndexParams [ i ] . Value != req . IndexParams [ i ] . Value {
notEq = true
break
}
}
if notEq {
continue
}
return true , meta . indexMeta . IndexBuildID
2021-05-27 14:24:29 +00:00
}
2021-06-24 06:36:08 +00:00
2022-05-31 08:36:03 +00:00
return false , 0
2021-05-27 14:24:29 +00:00
}
2021-12-14 08:45:34 +00:00
// LoadMetaFromETCD load the meta of specified indexBuildID from ETCD.
// If the version of meta in memory is greater equal to the version in ETCD, no need to reload.
2022-07-06 05:54:21 +00:00
func ( mt * metaTable ) LoadMetaFromETCD ( indexBuildID int64 , indexVersion int64 ) bool {
2021-05-27 14:24:29 +00:00
mt . lock . Lock ( )
defer mt . lock . Unlock ( )
meta , ok := mt . indexBuildID2Meta [ indexBuildID ]
2021-12-25 06:58:19 +00:00
log . Debug ( "IndexCoord metaTable LoadMetaFromETCD" , zap . Int64 ( "indexBuildID" , indexBuildID ) ,
2022-07-06 05:54:21 +00:00
zap . Int64 ( "indexVersion" , indexVersion ) , zap . Bool ( "ok" , ok ) )
2021-05-27 14:24:29 +00:00
if ok {
2021-06-21 09:28:03 +00:00
log . Debug ( "IndexCoord metaTable LoadMetaFromETCD" ,
2022-07-06 05:54:21 +00:00
zap . Int64 ( "meta.indexVersion" , meta . indexVersion ) ,
zap . Int64 ( "indexVersion" , indexVersion ) )
2021-06-06 01:41:35 +00:00
2022-07-06 05:54:21 +00:00
if meta . indexVersion >= indexVersion {
2021-05-27 14:24:29 +00:00
return false
}
2021-07-29 06:47:22 +00:00
} else {
2021-09-26 13:23:57 +00:00
log . Error ( "Index not exist" , zap . Int64 ( "IndexBuildID" , indexBuildID ) )
2021-07-29 06:47:22 +00:00
return false
2021-05-27 14:24:29 +00:00
}
2021-07-29 06:47:22 +00:00
m , err := mt . reloadMeta ( indexBuildID )
2021-05-27 14:24:29 +00:00
if m == nil {
2021-09-26 13:23:57 +00:00
log . Error ( "IndexCoord metaTable reloadMeta failed" , zap . Error ( err ) )
2021-05-27 14:24:29 +00:00
return false
}
mt . indexBuildID2Meta [ indexBuildID ] = * m
2021-06-21 09:28:03 +00:00
log . Debug ( "IndexCoord LoadMetaFromETCD success" , zap . Any ( "IndexMeta" , m ) )
2021-05-27 14:24:29 +00:00
return true
}
2021-12-14 08:37:58 +00:00
// GetNodeTaskStats get task stats of IndexNode.
2021-07-14 06:15:55 +00:00
func ( mt * metaTable ) GetNodeTaskStats ( ) map [ UniqueID ] int {
mt . lock . RLock ( )
defer mt . lock . RUnlock ( )
2021-06-11 08:53:42 +00:00
2021-07-14 06:15:55 +00:00
log . Debug ( "IndexCoord MetaTable GetPriorityForNodeID" )
nodePriority := make ( map [ UniqueID ] int )
for _ , meta := range mt . indexBuildID2Meta {
if meta . indexMeta . State == commonpb . IndexState_InProgress {
nodePriority [ meta . indexMeta . NodeID ] ++
2021-06-15 10:25:55 +00:00
}
2021-05-27 14:24:29 +00:00
}
2021-07-14 06:15:55 +00:00
return nodePriority
2021-01-19 10:32:57 +00:00
}
2021-09-14 02:41:21 +00:00
2021-12-14 08:39:46 +00:00
// GetIndexMetaByIndexBuildID get the index meta of the specified indexBuildID.
2021-09-14 02:41:21 +00:00
func ( mt * metaTable ) GetIndexMetaByIndexBuildID ( indexBuildID UniqueID ) * indexpb . IndexMeta {
mt . lock . RLock ( )
defer mt . lock . RUnlock ( )
log . Debug ( "IndexCoord MetaTable GetIndexMeta" , zap . Int64 ( "IndexBuildID" , indexBuildID ) )
meta , ok := mt . indexBuildID2Meta [ indexBuildID ]
if ! ok {
log . Error ( "IndexCoord MetaTable GetIndexMeta not exist" , zap . Int64 ( "IndexBuildID" , indexBuildID ) )
return nil
}
2021-10-24 05:29:10 +00:00
return proto . Clone ( meta . indexMeta ) . ( * indexpb . IndexMeta )
2021-09-14 02:41:21 +00:00
}