2021-01-18 02:09:17 +00:00
|
|
|
package querynode
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
2021-01-21 07:20:23 +00:00
|
|
|
"strconv"
|
2021-01-18 02:09:17 +00:00
|
|
|
|
|
|
|
"github.com/zilliztech/milvus-distributed/internal/kv"
|
2021-01-19 03:37:16 +00:00
|
|
|
miniokv "github.com/zilliztech/milvus-distributed/internal/kv/minio"
|
|
|
|
"github.com/zilliztech/milvus-distributed/internal/msgstream"
|
2021-01-18 02:09:17 +00:00
|
|
|
"github.com/zilliztech/milvus-distributed/internal/proto/commonpb"
|
|
|
|
"github.com/zilliztech/milvus-distributed/internal/proto/datapb"
|
|
|
|
"github.com/zilliztech/milvus-distributed/internal/proto/indexpb"
|
2021-01-19 03:37:16 +00:00
|
|
|
internalPb "github.com/zilliztech/milvus-distributed/internal/proto/internalpb2"
|
2021-01-27 06:41:56 +00:00
|
|
|
"github.com/zilliztech/milvus-distributed/internal/proto/milvuspb"
|
2021-01-18 02:09:17 +00:00
|
|
|
"github.com/zilliztech/milvus-distributed/internal/storage"
|
|
|
|
)
|
|
|
|
|
|
|
|
type segmentManager struct {
|
|
|
|
replica collectionReplica
|
|
|
|
|
2021-01-26 01:38:40 +00:00
|
|
|
dmStream msgstream.MsgStream
|
2021-01-19 03:37:16 +00:00
|
|
|
loadIndexReqChan chan []msgstream.TsMsg
|
|
|
|
|
2021-01-27 06:41:56 +00:00
|
|
|
masterClient MasterServiceInterface
|
|
|
|
dataClient DataServiceInterface
|
|
|
|
indexClient IndexServiceInterface
|
2021-01-18 02:09:17 +00:00
|
|
|
|
2021-01-19 03:37:16 +00:00
|
|
|
kv kv.Base // minio kv
|
|
|
|
iCodec *storage.InsertCodec
|
|
|
|
}
|
|
|
|
|
2021-01-26 01:38:40 +00:00
|
|
|
func (s *segmentManager) seekSegment(positions []*internalPb.MsgPosition) error {
|
|
|
|
// TODO: open seek
|
|
|
|
//for _, position := range positions {
|
|
|
|
// err := s.dmStream.Seek(position)
|
|
|
|
// if err != nil {
|
|
|
|
// return err
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
return nil
|
2021-01-24 10:02:08 +00:00
|
|
|
}
|
|
|
|
|
2021-01-29 07:22:24 +00:00
|
|
|
func (s *segmentManager) getIndexInfo(collectionID UniqueID, segmentID UniqueID) (UniqueID, UniqueID, error) {
|
2021-01-27 06:41:56 +00:00
|
|
|
req := &milvuspb.DescribeSegmentRequest{
|
|
|
|
Base: &commonpb.MsgBase{
|
|
|
|
MsgType: commonpb.MsgType_kDescribeSegment,
|
|
|
|
},
|
|
|
|
CollectionID: collectionID,
|
|
|
|
SegmentID: segmentID,
|
|
|
|
}
|
|
|
|
response, err := s.masterClient.DescribeSegment(req)
|
|
|
|
if err != nil {
|
2021-01-29 07:22:24 +00:00
|
|
|
return 0, 0, err
|
2021-01-27 06:41:56 +00:00
|
|
|
}
|
2021-01-29 07:22:24 +00:00
|
|
|
return response.IndexID, response.BuildID, nil
|
2021-01-27 06:41:56 +00:00
|
|
|
}
|
|
|
|
|
2021-01-21 07:20:23 +00:00
|
|
|
func (s *segmentManager) loadSegment(collectionID UniqueID, partitionID UniqueID, segmentIDs []UniqueID, fieldIDs []int64) error {
|
|
|
|
// TODO: interim solution
|
|
|
|
if len(fieldIDs) == 0 {
|
|
|
|
collection, err := s.replica.getCollectionByID(collectionID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
fieldIDs = make([]int64, 0)
|
|
|
|
for _, field := range collection.Schema().Fields {
|
|
|
|
fieldIDs = append(fieldIDs, field.FieldID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, segmentID := range segmentIDs {
|
2021-01-29 07:22:24 +00:00
|
|
|
// we don't need index id yet
|
|
|
|
_, buildID, err := s.getIndexInfo(collectionID, segmentID)
|
|
|
|
if err == nil {
|
2021-01-30 08:02:10 +00:00
|
|
|
// we don't need load to vector fields
|
2021-01-29 07:22:24 +00:00
|
|
|
vectorFields, err := s.replica.getVecFieldsBySegmentID(segmentID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
fieldIDs = s.filterOutVectorFields(fieldIDs, vectorFields)
|
2021-01-27 06:41:56 +00:00
|
|
|
}
|
2021-01-21 07:20:23 +00:00
|
|
|
paths, srcFieldIDs, err := s.getInsertBinlogPaths(segmentID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-01-29 07:22:24 +00:00
|
|
|
targetFields := s.getTargetFields(paths, srcFieldIDs, fieldIDs)
|
2021-01-26 01:38:40 +00:00
|
|
|
// replace segment
|
|
|
|
err = s.replica.removeSegment(segmentID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-01-21 07:20:23 +00:00
|
|
|
err = s.replica.addSegment(segmentID, partitionID, collectionID, segTypeSealed)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = s.loadSegmentFieldsData(segmentID, targetFields)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-01-29 07:22:24 +00:00
|
|
|
indexPaths, err := s.getIndexPaths(buildID)
|
2021-01-21 07:20:23 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-01-29 07:22:24 +00:00
|
|
|
err = s.loadIndex(segmentID, indexPaths)
|
2021-01-21 07:20:23 +00:00
|
|
|
if err != nil {
|
|
|
|
// TODO: return or continue?
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *segmentManager) releaseSegment(segmentID UniqueID) error {
|
|
|
|
err := s.replica.removeSegment(segmentID)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------------------------- internal functions
|
|
|
|
func (s *segmentManager) getInsertBinlogPaths(segmentID UniqueID) ([]*internalPb.StringList, []int64, error) {
|
2021-01-26 05:41:41 +00:00
|
|
|
if s.dataClient == nil {
|
|
|
|
return nil, nil, errors.New("null data service client")
|
|
|
|
}
|
|
|
|
|
2021-01-18 02:38:41 +00:00
|
|
|
insertBinlogPathRequest := &datapb.InsertBinlogPathRequest{
|
2021-01-18 02:09:17 +00:00
|
|
|
SegmentID: segmentID,
|
|
|
|
}
|
|
|
|
|
2021-01-26 05:41:41 +00:00
|
|
|
pathResponse, err := s.dataClient.GetInsertBinlogPaths(insertBinlogPathRequest)
|
2021-01-18 02:09:17 +00:00
|
|
|
if err != nil {
|
2021-01-21 07:20:23 +00:00
|
|
|
return nil, nil, err
|
2021-01-18 02:09:17 +00:00
|
|
|
}
|
|
|
|
|
2021-01-26 05:41:41 +00:00
|
|
|
if len(pathResponse.FieldIDs) != len(pathResponse.Paths) {
|
|
|
|
return nil, nil, errors.New("illegal InsertBinlogPathsResponse")
|
2021-01-18 02:09:17 +00:00
|
|
|
}
|
|
|
|
|
2021-01-26 05:41:41 +00:00
|
|
|
return pathResponse.Paths, pathResponse.FieldIDs, nil
|
2021-01-21 07:20:23 +00:00
|
|
|
}
|
|
|
|
|
2021-01-29 07:22:24 +00:00
|
|
|
func (s *segmentManager) filterOutVectorFields(fieldIDs []int64, vectorFields map[int64]string) []int64 {
|
|
|
|
targetFields := make([]int64, 0)
|
|
|
|
for _, id := range fieldIDs {
|
|
|
|
if _, ok := vectorFields[id]; !ok {
|
|
|
|
targetFields = append(targetFields, id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return targetFields
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *segmentManager) getTargetFields(paths []*internalPb.StringList, srcFieldIDS []int64, dstFields []int64) map[int64]*internalPb.StringList {
|
2021-01-21 07:20:23 +00:00
|
|
|
targetFields := make(map[int64]*internalPb.StringList)
|
2021-01-20 01:36:50 +00:00
|
|
|
|
2021-01-18 02:38:41 +00:00
|
|
|
containsFunc := func(s []int64, e int64) bool {
|
|
|
|
for _, a := range s {
|
|
|
|
if a == e {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2021-01-21 07:20:23 +00:00
|
|
|
for i, fieldID := range srcFieldIDS {
|
|
|
|
if containsFunc(dstFields, fieldID) {
|
|
|
|
targetFields[fieldID] = paths[i]
|
2021-01-18 02:38:41 +00:00
|
|
|
}
|
2021-01-21 07:20:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return targetFields
|
|
|
|
}
|
2021-01-18 02:38:41 +00:00
|
|
|
|
2021-01-21 07:20:23 +00:00
|
|
|
func (s *segmentManager) loadSegmentFieldsData(segmentID UniqueID, targetFields map[int64]*internalPb.StringList) error {
|
|
|
|
for id, p := range targetFields {
|
2021-01-29 07:22:24 +00:00
|
|
|
if id == timestampFieldID {
|
|
|
|
// seg core doesn't need timestamp field
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2021-01-21 07:20:23 +00:00
|
|
|
paths := p.Values
|
2021-01-18 02:09:17 +00:00
|
|
|
blobs := make([]*storage.Blob, 0)
|
|
|
|
for _, path := range paths {
|
|
|
|
binLog, err := s.kv.Load(path)
|
|
|
|
if err != nil {
|
|
|
|
// TODO: return or continue?
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
blobs = append(blobs, &storage.Blob{
|
2021-01-21 07:20:23 +00:00
|
|
|
Key: strconv.FormatInt(id, 10), // TODO: key???
|
2021-01-18 02:09:17 +00:00
|
|
|
Value: []byte(binLog),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
_, _, insertData, err := s.iCodec.Deserialize(blobs)
|
|
|
|
if err != nil {
|
|
|
|
// TODO: return or continue
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if len(insertData.Data) != 1 {
|
|
|
|
return errors.New("we expect only one field in deserialized insert data")
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, value := range insertData.Data {
|
2021-01-20 01:36:50 +00:00
|
|
|
var numRows int
|
|
|
|
var data interface{}
|
|
|
|
|
2021-01-18 02:09:17 +00:00
|
|
|
switch fieldData := value.(type) {
|
2021-01-21 07:20:23 +00:00
|
|
|
case *storage.BoolFieldData:
|
2021-01-20 01:36:50 +00:00
|
|
|
numRows = fieldData.NumRows
|
|
|
|
data = fieldData.Data
|
2021-01-21 07:20:23 +00:00
|
|
|
case *storage.Int8FieldData:
|
2021-01-20 01:36:50 +00:00
|
|
|
numRows = fieldData.NumRows
|
|
|
|
data = fieldData.Data
|
2021-01-21 07:20:23 +00:00
|
|
|
case *storage.Int16FieldData:
|
2021-01-20 01:36:50 +00:00
|
|
|
numRows = fieldData.NumRows
|
|
|
|
data = fieldData.Data
|
2021-01-21 07:20:23 +00:00
|
|
|
case *storage.Int32FieldData:
|
2021-01-20 01:36:50 +00:00
|
|
|
numRows = fieldData.NumRows
|
|
|
|
data = fieldData.Data
|
2021-01-21 07:20:23 +00:00
|
|
|
case *storage.Int64FieldData:
|
2021-01-20 01:36:50 +00:00
|
|
|
numRows = fieldData.NumRows
|
|
|
|
data = fieldData.Data
|
2021-01-21 07:20:23 +00:00
|
|
|
case *storage.FloatFieldData:
|
2021-01-20 01:36:50 +00:00
|
|
|
numRows = fieldData.NumRows
|
|
|
|
data = fieldData.Data
|
2021-01-21 07:20:23 +00:00
|
|
|
case *storage.DoubleFieldData:
|
2021-01-20 01:36:50 +00:00
|
|
|
numRows = fieldData.NumRows
|
|
|
|
data = fieldData.Data
|
2021-01-18 02:38:41 +00:00
|
|
|
case storage.StringFieldData:
|
2021-01-20 01:36:50 +00:00
|
|
|
numRows = fieldData.NumRows
|
|
|
|
data = fieldData.Data
|
2021-01-21 07:20:23 +00:00
|
|
|
case *storage.FloatVectorFieldData:
|
2021-01-30 08:02:10 +00:00
|
|
|
numRows = fieldData.NumRows
|
|
|
|
data = fieldData.Data
|
2021-01-21 07:20:23 +00:00
|
|
|
case *storage.BinaryVectorFieldData:
|
2021-01-30 08:02:10 +00:00
|
|
|
numRows = fieldData.NumRows
|
|
|
|
data = fieldData.Data
|
2021-01-18 02:09:17 +00:00
|
|
|
default:
|
2021-01-18 02:38:41 +00:00
|
|
|
return errors.New("unexpected field data type")
|
2021-01-18 02:09:17 +00:00
|
|
|
}
|
2021-01-20 01:36:50 +00:00
|
|
|
|
|
|
|
segment, err := s.replica.getSegmentByID(segmentID)
|
|
|
|
if err != nil {
|
|
|
|
// TODO: return or continue?
|
|
|
|
return err
|
|
|
|
}
|
2021-01-21 07:20:23 +00:00
|
|
|
err = segment.segmentLoadFieldData(id, numRows, data)
|
2021-01-20 01:36:50 +00:00
|
|
|
if err != nil {
|
|
|
|
// TODO: return or continue?
|
|
|
|
return err
|
|
|
|
}
|
2021-01-18 02:09:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-18 02:38:41 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-01-29 07:22:24 +00:00
|
|
|
func (s *segmentManager) getIndexPaths(buildID UniqueID) ([]string, error) {
|
2021-01-26 05:41:41 +00:00
|
|
|
if s.indexClient == nil {
|
|
|
|
return nil, errors.New("null index service client")
|
|
|
|
}
|
|
|
|
|
2021-01-21 02:01:29 +00:00
|
|
|
indexFilePathRequest := &indexpb.IndexFilePathsRequest{
|
2021-01-29 07:22:24 +00:00
|
|
|
// TODO: rename indexIDs to buildIDs
|
|
|
|
IndexIDs: []UniqueID{buildID},
|
2021-01-18 02:38:41 +00:00
|
|
|
}
|
2021-01-26 05:41:41 +00:00
|
|
|
pathResponse, err := s.indexClient.GetIndexFilePaths(indexFilePathRequest)
|
|
|
|
if err != nil || pathResponse.Status.ErrorCode != commonpb.ErrorCode_SUCCESS {
|
2021-01-21 07:20:23 +00:00
|
|
|
return nil, err
|
2021-01-18 02:38:41 +00:00
|
|
|
}
|
|
|
|
|
2021-01-26 05:41:41 +00:00
|
|
|
if len(pathResponse.FilePaths) <= 0 {
|
|
|
|
return nil, errors.New("illegal index file paths")
|
|
|
|
}
|
|
|
|
|
|
|
|
return pathResponse.FilePaths[0].IndexFilePaths, nil
|
2021-01-21 07:20:23 +00:00
|
|
|
}
|
|
|
|
|
2021-01-29 07:22:24 +00:00
|
|
|
func (s *segmentManager) loadIndex(segmentID UniqueID, indexPaths []string) error {
|
2021-01-18 02:38:41 +00:00
|
|
|
// get vector field ids from schema to load index
|
2021-01-20 01:36:50 +00:00
|
|
|
vecFieldIDs, err := s.replica.getVecFieldsBySegmentID(segmentID)
|
2021-01-18 02:38:41 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-01-20 01:36:50 +00:00
|
|
|
for id, name := range vecFieldIDs {
|
2021-01-30 08:02:10 +00:00
|
|
|
// non-blocking sending
|
2021-01-29 07:22:24 +00:00
|
|
|
go s.sendLoadIndex(indexPaths, segmentID, id, name)
|
2021-01-18 02:09:17 +00:00
|
|
|
}
|
2021-01-18 02:38:41 +00:00
|
|
|
|
2021-01-18 02:09:17 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-01-19 03:37:16 +00:00
|
|
|
func (s *segmentManager) sendLoadIndex(indexPaths []string,
|
|
|
|
segmentID int64,
|
|
|
|
fieldID int64,
|
2021-01-29 07:22:24 +00:00
|
|
|
fieldName string) {
|
2021-01-19 03:37:16 +00:00
|
|
|
loadIndexRequest := internalPb.LoadIndex{
|
|
|
|
Base: &commonpb.MsgBase{
|
|
|
|
MsgType: commonpb.MsgType_kSearchResult,
|
|
|
|
},
|
2021-01-29 07:22:24 +00:00
|
|
|
SegmentID: segmentID,
|
|
|
|
FieldName: fieldName,
|
|
|
|
FieldID: fieldID,
|
|
|
|
IndexPaths: indexPaths,
|
2021-01-19 03:37:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
loadIndexMsg := &msgstream.LoadIndexMsg{
|
|
|
|
LoadIndex: loadIndexRequest,
|
|
|
|
}
|
|
|
|
|
|
|
|
messages := []msgstream.TsMsg{loadIndexMsg}
|
|
|
|
s.loadIndexReqChan <- messages
|
|
|
|
}
|
2021-01-26 01:38:40 +00:00
|
|
|
|
2021-01-27 06:41:56 +00:00
|
|
|
func newSegmentManager(ctx context.Context, masterClient MasterServiceInterface, dataClient DataServiceInterface, indexClient IndexServiceInterface, replica collectionReplica, dmStream msgstream.MsgStream, loadIndexReqChan chan []msgstream.TsMsg) *segmentManager {
|
2021-01-26 01:38:40 +00:00
|
|
|
bucketName := Params.MinioBucketName
|
|
|
|
option := &miniokv.Option{
|
|
|
|
Address: Params.MinioEndPoint,
|
|
|
|
AccessKeyID: Params.MinioAccessKeyID,
|
|
|
|
SecretAccessKeyID: Params.MinioSecretAccessKey,
|
|
|
|
UseSSL: Params.MinioUseSSLStr,
|
|
|
|
BucketName: bucketName,
|
|
|
|
CreateBucket: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
minioKV, err := miniokv.NewMinIOKV(ctx, option)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &segmentManager{
|
|
|
|
replica: replica,
|
|
|
|
dmStream: dmStream,
|
|
|
|
loadIndexReqChan: loadIndexReqChan,
|
|
|
|
|
2021-01-27 06:41:56 +00:00
|
|
|
masterClient: masterClient,
|
|
|
|
dataClient: dataClient,
|
|
|
|
indexClient: indexClient,
|
2021-01-26 01:38:40 +00:00
|
|
|
|
|
|
|
kv: minioKV,
|
|
|
|
iCodec: &storage.InsertCodec{},
|
|
|
|
}
|
|
|
|
}
|