2021-10-25 20:21:18 +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-04-19 11:35:38 +08:00
|
|
|
// with the License. You may obtain a copy of the License at
|
|
|
|
//
|
2021-10-25 20:21:18 +08:00
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
2021-04-19 11:35:38 +08:00
|
|
|
//
|
2021-10-25 20:21:18 +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-10-04 17:16:54 +08:00
|
|
|
|
2021-10-05 22:33:01 +08:00
|
|
|
// Package datacoord contains core functions in datacoord
|
2021-06-22 10:42:07 +08:00
|
|
|
package datacoord
|
2021-01-15 17:09:41 +08:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"sync"
|
2021-08-19 14:08:10 +08:00
|
|
|
"time"
|
2021-01-15 17:09:41 +08:00
|
|
|
|
2021-09-29 20:26:00 +08:00
|
|
|
"go.uber.org/zap"
|
|
|
|
|
2021-03-05 20:41:34 +08:00
|
|
|
"github.com/golang/protobuf/proto"
|
2021-04-22 14:45:57 +08:00
|
|
|
"github.com/milvus-io/milvus/internal/kv"
|
2021-10-24 22:39:09 +08:00
|
|
|
"github.com/milvus-io/milvus/internal/log"
|
2021-04-22 14:45:57 +08:00
|
|
|
"github.com/milvus-io/milvus/internal/proto/commonpb"
|
|
|
|
"github.com/milvus-io/milvus/internal/proto/datapb"
|
2021-11-05 22:25:00 +08:00
|
|
|
"github.com/milvus-io/milvus/internal/proto/internalpb"
|
2021-10-24 22:39:09 +08:00
|
|
|
"github.com/milvus-io/milvus/internal/proto/querypb"
|
2021-04-09 09:55:04 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2021-10-24 22:39:09 +08:00
|
|
|
metaPrefix = "datacoord-meta"
|
|
|
|
segmentPrefix = metaPrefix + "/s"
|
|
|
|
handoffSegmentPrefix = "querycoord-handoff"
|
2021-01-15 17:09:41 +08:00
|
|
|
)
|
|
|
|
|
2021-06-22 18:24:08 +08:00
|
|
|
type meta struct {
|
|
|
|
sync.RWMutex
|
|
|
|
client kv.TxnKV // client of a reliable kv service, i.e. etcd client
|
|
|
|
collections map[UniqueID]*datapb.CollectionInfo // collection id to collection info
|
2021-07-07 14:02:01 +08:00
|
|
|
segments *SegmentsInfo // segment id to segment info
|
2021-06-22 18:24:08 +08:00
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// NewMeta create meta from provided `kv.TxnKV`
|
2021-10-02 23:09:56 +08:00
|
|
|
func newMeta(kv kv.TxnKV) (*meta, error) {
|
2021-01-15 17:09:41 +08:00
|
|
|
mt := &meta{
|
|
|
|
client: kv,
|
2021-04-09 09:55:04 +08:00
|
|
|
collections: make(map[UniqueID]*datapb.CollectionInfo),
|
2021-07-07 14:02:01 +08:00
|
|
|
segments: NewSegmentsInfo(),
|
2021-01-15 17:09:41 +08:00
|
|
|
}
|
|
|
|
err := mt.reloadFromKV()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return mt, nil
|
|
|
|
}
|
|
|
|
|
2021-10-07 10:36:03 +08:00
|
|
|
// reloadFromKV load meta from KV storage
|
2021-05-25 15:35:37 +08:00
|
|
|
func (m *meta) reloadFromKV() error {
|
|
|
|
_, values, err := m.client.LoadWithPrefix(segmentPrefix)
|
2021-01-15 17:09:41 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, value := range values {
|
|
|
|
segmentInfo := &datapb.SegmentInfo{}
|
2021-09-29 20:26:00 +08:00
|
|
|
err = proto.Unmarshal([]byte(value), segmentInfo)
|
2021-01-15 17:09:41 +08:00
|
|
|
if err != nil {
|
2021-09-29 20:26:00 +08:00
|
|
|
return fmt.Errorf("DataCoord reloadFromKV UnMarshal datapb.SegmentInfo err:%w", err)
|
2021-01-15 17:09:41 +08:00
|
|
|
}
|
2021-11-05 22:25:00 +08:00
|
|
|
if segmentInfo.State == commonpb.SegmentState_NotExist {
|
|
|
|
continue
|
|
|
|
}
|
2021-07-12 17:24:25 +08:00
|
|
|
m.segments.SetSegment(segmentInfo.GetID(), NewSegmentInfo(segmentInfo))
|
2021-01-15 17:09:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// AddCollection add collection into meta
|
|
|
|
// Note that collection info is just for caching and will not be set into etcd from datacoord
|
2021-07-07 14:02:01 +08:00
|
|
|
func (m *meta) AddCollection(collection *datapb.CollectionInfo) {
|
2021-05-25 15:35:37 +08:00
|
|
|
m.Lock()
|
|
|
|
defer m.Unlock()
|
|
|
|
m.collections[collection.ID] = collection
|
2021-01-15 17:09:41 +08:00
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// GetCollection get collection info with provided collection id from local cache
|
2021-07-07 14:02:01 +08:00
|
|
|
func (m *meta) GetCollection(collectionID UniqueID) *datapb.CollectionInfo {
|
2021-05-25 15:35:37 +08:00
|
|
|
m.RLock()
|
|
|
|
defer m.RUnlock()
|
|
|
|
collection, ok := m.collections[collectionID]
|
2021-01-19 15:35:40 +08:00
|
|
|
if !ok {
|
2021-07-07 14:02:01 +08:00
|
|
|
return nil
|
2021-01-19 15:35:40 +08:00
|
|
|
}
|
2021-07-07 14:02:01 +08:00
|
|
|
return collection
|
2021-01-19 15:35:40 +08:00
|
|
|
}
|
2021-01-15 17:09:41 +08:00
|
|
|
|
2021-11-05 22:25:00 +08:00
|
|
|
type chanPartSegments struct {
|
|
|
|
collecionID UniqueID
|
|
|
|
partitionID UniqueID
|
|
|
|
channelName string
|
|
|
|
segments []*SegmentInfo
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetSegmentsChanPart get segments organized in Channel-Parition dimension with selector applied
|
|
|
|
func (m *meta) GetSegmentsChanPart(selector SegmentInfoSelector) []*chanPartSegments {
|
|
|
|
m.RLock()
|
|
|
|
defer m.RUnlock()
|
|
|
|
mDimEntry := make(map[string]*chanPartSegments)
|
|
|
|
|
|
|
|
for _, segmentInfo := range m.segments.segments {
|
|
|
|
if !selector(segmentInfo) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
dim := fmt.Sprintf("%d-%s", segmentInfo.PartitionID, segmentInfo.InsertChannel)
|
|
|
|
entry, ok := mDimEntry[dim]
|
|
|
|
if !ok {
|
|
|
|
entry = &chanPartSegments{
|
|
|
|
collecionID: segmentInfo.CollectionID,
|
|
|
|
partitionID: segmentInfo.PartitionID,
|
|
|
|
channelName: segmentInfo.InsertChannel,
|
|
|
|
}
|
|
|
|
mDimEntry[dim] = entry
|
|
|
|
}
|
|
|
|
entry.segments = append(entry.segments, segmentInfo)
|
|
|
|
}
|
|
|
|
|
|
|
|
result := make([]*chanPartSegments, 0, len(mDimEntry))
|
|
|
|
for _, entry := range mDimEntry {
|
|
|
|
result = append(result, entry)
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// GetNumRowsOfCollection returns total rows count of segments belongs to provided collection
|
2021-07-07 14:02:01 +08:00
|
|
|
func (m *meta) GetNumRowsOfCollection(collectionID UniqueID) int64 {
|
2021-05-25 15:35:37 +08:00
|
|
|
m.RLock()
|
|
|
|
defer m.RUnlock()
|
2021-02-02 14:25:58 +08:00
|
|
|
var ret int64 = 0
|
2021-07-07 14:02:01 +08:00
|
|
|
segments := m.segments.GetSegments()
|
|
|
|
for _, segment := range segments {
|
|
|
|
if segment.GetCollectionID() == collectionID {
|
2021-06-22 18:24:08 +08:00
|
|
|
ret += segment.GetNumOfRows()
|
2021-02-02 14:25:58 +08:00
|
|
|
}
|
|
|
|
}
|
2021-07-07 14:02:01 +08:00
|
|
|
return ret
|
2021-02-02 14:25:58 +08:00
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// AddSegment records segment info, persisting info into kv store
|
2021-07-12 17:24:25 +08:00
|
|
|
func (m *meta) AddSegment(segment *SegmentInfo) error {
|
2021-05-25 15:35:37 +08:00
|
|
|
m.Lock()
|
|
|
|
defer m.Unlock()
|
2021-07-07 14:02:01 +08:00
|
|
|
m.segments.SetSegment(segment.GetID(), segment)
|
2021-05-25 15:35:37 +08:00
|
|
|
if err := m.saveSegmentInfo(segment); err != nil {
|
2021-01-15 17:09:41 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// DropSegment remove segment with provided id, etcd persistence also removed
|
2021-05-25 15:35:37 +08:00
|
|
|
func (m *meta) DropSegment(segmentID UniqueID) error {
|
|
|
|
m.Lock()
|
|
|
|
defer m.Unlock()
|
2021-07-07 14:02:01 +08:00
|
|
|
segment := m.segments.GetSegment(segmentID)
|
2021-09-08 11:35:59 +08:00
|
|
|
if segment == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2021-07-07 14:02:01 +08:00
|
|
|
m.segments.DropSegment(segmentID)
|
2021-05-25 15:35:37 +08:00
|
|
|
if err := m.removeSegmentInfo(segment); err != nil {
|
2021-02-02 14:25:58 +08:00
|
|
|
return err
|
|
|
|
}
|
2021-01-19 15:35:40 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// GetSegment returns segment info with provided id
|
|
|
|
// if not segment is found, nil will be returned
|
2021-07-12 17:24:25 +08:00
|
|
|
func (m *meta) GetSegment(segID UniqueID) *SegmentInfo {
|
2021-05-25 15:35:37 +08:00
|
|
|
m.RLock()
|
|
|
|
defer m.RUnlock()
|
2021-07-07 14:02:01 +08:00
|
|
|
return m.segments.GetSegment(segID)
|
2021-01-15 17:09:41 +08:00
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// SetState setting segment with provided ID state
|
2021-07-07 14:02:01 +08:00
|
|
|
func (m *meta) SetState(segmentID UniqueID, state commonpb.SegmentState) error {
|
2021-05-25 15:35:37 +08:00
|
|
|
m.Lock()
|
|
|
|
defer m.Unlock()
|
2021-07-07 14:02:01 +08:00
|
|
|
m.segments.SetState(segmentID, state)
|
|
|
|
if segInfo := m.segments.GetSegment(segmentID); segInfo != nil {
|
|
|
|
return m.saveSegmentInfo(segInfo)
|
2021-01-22 11:07:07 +08:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// UpdateFlushSegmentsInfo update segment partial/completed flush info
|
|
|
|
// `flushed` parameter indicating whether segment is flushed completely or partially
|
|
|
|
// `binlogs`, `checkpoints` and `statPositions` are persistence data for segment
|
2021-08-19 13:00:12 +08:00
|
|
|
func (m *meta) UpdateFlushSegmentsInfo(segmentID UniqueID, flushed bool,
|
2021-10-19 14:32:41 +08:00
|
|
|
binlogs, statslogs []*datapb.FieldBinlog, deltalogs []*datapb.DeltaLogInfo, checkpoints []*datapb.CheckPoint,
|
2021-06-15 11:06:42 +08:00
|
|
|
startPositions []*datapb.SegmentStartPosition) error {
|
2021-05-25 15:35:37 +08:00
|
|
|
m.Lock()
|
|
|
|
defer m.Unlock()
|
2021-08-19 13:00:12 +08:00
|
|
|
|
|
|
|
segment := m.segments.GetSegment(segmentID)
|
|
|
|
if segment == nil {
|
|
|
|
return nil
|
2021-05-31 18:47:32 +08:00
|
|
|
}
|
2021-08-19 13:00:12 +08:00
|
|
|
|
2021-10-12 23:46:35 +08:00
|
|
|
clonedSegment := segment.Clone()
|
|
|
|
|
2021-08-19 13:00:12 +08:00
|
|
|
kv := make(map[string]string)
|
2021-10-12 23:46:35 +08:00
|
|
|
modSegments := make(map[UniqueID]*SegmentInfo)
|
2021-08-19 13:00:12 +08:00
|
|
|
|
2021-06-04 11:45:45 +08:00
|
|
|
if flushed {
|
2021-10-12 23:46:35 +08:00
|
|
|
clonedSegment.State = commonpb.SegmentState_Flushing
|
|
|
|
modSegments[segmentID] = clonedSegment
|
2021-06-04 11:45:45 +08:00
|
|
|
}
|
|
|
|
|
2021-10-12 23:46:35 +08:00
|
|
|
currBinlogs := clonedSegment.GetBinlogs()
|
|
|
|
|
2021-08-19 13:00:12 +08:00
|
|
|
var getFieldBinlogs = func(id UniqueID, binlogs []*datapb.FieldBinlog) *datapb.FieldBinlog {
|
|
|
|
for _, binlog := range binlogs {
|
|
|
|
if id == binlog.GetFieldID() {
|
|
|
|
return binlog
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2021-10-19 14:32:41 +08:00
|
|
|
// binlogs
|
2021-08-19 13:00:12 +08:00
|
|
|
for _, tBinlogs := range binlogs {
|
|
|
|
fieldBinlogs := getFieldBinlogs(tBinlogs.GetFieldID(), currBinlogs)
|
|
|
|
if fieldBinlogs == nil {
|
|
|
|
currBinlogs = append(currBinlogs, tBinlogs)
|
|
|
|
} else {
|
|
|
|
fieldBinlogs.Binlogs = append(fieldBinlogs.Binlogs, tBinlogs.Binlogs...)
|
|
|
|
}
|
|
|
|
}
|
2021-10-12 23:46:35 +08:00
|
|
|
clonedSegment.Binlogs = currBinlogs
|
2021-10-19 14:32:41 +08:00
|
|
|
// statlogs
|
|
|
|
currStatsLogs := clonedSegment.GetStatslogs()
|
|
|
|
for _, tStatsLogs := range statslogs {
|
|
|
|
fieldStatsLog := getFieldBinlogs(tStatsLogs.GetFieldID(), currStatsLogs)
|
|
|
|
if fieldStatsLog == nil {
|
|
|
|
currStatsLogs = append(currStatsLogs, tStatsLogs)
|
|
|
|
} else {
|
|
|
|
fieldStatsLog.Binlogs = append(fieldStatsLog.Binlogs, tStatsLogs.Binlogs...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
clonedSegment.Statslogs = currStatsLogs
|
|
|
|
// deltalogs
|
|
|
|
clonedSegment.Deltalogs = append(clonedSegment.Deltalogs, deltalogs...)
|
|
|
|
|
2021-10-12 23:46:35 +08:00
|
|
|
modSegments[segmentID] = clonedSegment
|
2021-08-19 13:00:12 +08:00
|
|
|
|
2021-10-23 13:31:09 +08:00
|
|
|
var getClonedSegment = func(segmentID UniqueID) *SegmentInfo {
|
|
|
|
if s, ok := modSegments[segmentID]; ok {
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
if s := m.segments.GetSegment(segmentID); s != nil {
|
|
|
|
return s.Clone()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-06-15 11:06:42 +08:00
|
|
|
for _, pos := range startPositions {
|
2021-08-19 13:00:12 +08:00
|
|
|
if len(pos.GetStartPosition().GetMsgID()) == 0 {
|
2021-06-15 11:06:42 +08:00
|
|
|
continue
|
|
|
|
}
|
2021-10-23 13:31:09 +08:00
|
|
|
s := getClonedSegment(pos.GetSegmentID())
|
2021-10-12 23:46:35 +08:00
|
|
|
if s == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
s.StartPosition = pos.GetStartPosition()
|
|
|
|
modSegments[pos.GetSegmentID()] = s
|
2021-06-15 11:06:42 +08:00
|
|
|
}
|
|
|
|
|
2021-06-04 11:45:45 +08:00
|
|
|
for _, cp := range checkpoints {
|
2021-10-23 13:31:09 +08:00
|
|
|
s := getClonedSegment(cp.GetSegmentID())
|
2021-10-12 23:46:35 +08:00
|
|
|
if s == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.DmlPosition != nil && s.DmlPosition.Timestamp >= cp.Position.Timestamp {
|
2021-08-19 13:00:12 +08:00
|
|
|
// segment position in etcd is larger than checkpoint, then dont change it
|
|
|
|
continue
|
2021-06-04 11:45:45 +08:00
|
|
|
}
|
2021-10-12 23:46:35 +08:00
|
|
|
|
|
|
|
s.DmlPosition = cp.GetPosition()
|
|
|
|
s.NumOfRows = cp.GetNumOfRows()
|
|
|
|
modSegments[cp.GetSegmentID()] = s
|
2021-06-15 11:06:42 +08:00
|
|
|
}
|
|
|
|
|
2021-11-08 14:16:56 +08:00
|
|
|
for _, segment := range modSegments {
|
|
|
|
segBytes, err := proto.Marshal(segment.SegmentInfo)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("DataCoord UpdateFlushSegmentsInfo segmentID:%d, marshal failed:%w", segment.GetID(), err)
|
2021-07-07 14:02:01 +08:00
|
|
|
}
|
2021-11-08 14:16:56 +08:00
|
|
|
key := buildSegmentPath(segment.GetCollectionID(), segment.GetPartitionID(), segment.GetID())
|
|
|
|
kv[key] = string(segBytes)
|
2021-06-04 11:45:45 +08:00
|
|
|
}
|
2021-05-25 15:35:37 +08:00
|
|
|
|
2021-10-12 23:46:35 +08:00
|
|
|
if len(kv) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-05-25 15:35:37 +08:00
|
|
|
if err := m.saveKvTxn(kv); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-10-12 23:46:35 +08:00
|
|
|
|
|
|
|
// update memory status
|
|
|
|
for id, s := range modSegments {
|
|
|
|
m.segments.SetSegment(id, s)
|
|
|
|
}
|
2021-05-25 15:35:37 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// ListSegmentIDs list all segment ids stored in meta (no collection filter)
|
|
|
|
func (m *meta) ListSegmentIDs() []UniqueID {
|
2021-08-24 15:51:51 +08:00
|
|
|
m.RLock()
|
|
|
|
defer m.RUnlock()
|
|
|
|
|
|
|
|
infos := make([]UniqueID, 0)
|
|
|
|
segments := m.segments.GetSegments()
|
|
|
|
for _, segment := range segments {
|
|
|
|
infos = append(infos, segment.GetID())
|
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
return infos
|
2021-08-24 15:51:51 +08:00
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// GetSegmentsByChannel returns all segment info which insert channel equals provided `dmlCh`
|
2021-07-12 17:24:25 +08:00
|
|
|
func (m *meta) GetSegmentsByChannel(dmlCh string) []*SegmentInfo {
|
2021-06-23 12:20:06 +08:00
|
|
|
m.RLock()
|
|
|
|
defer m.RUnlock()
|
2021-07-12 17:24:25 +08:00
|
|
|
infos := make([]*SegmentInfo, 0)
|
2021-07-07 14:02:01 +08:00
|
|
|
segments := m.segments.GetSegments()
|
|
|
|
for _, segment := range segments {
|
2021-05-31 18:47:32 +08:00
|
|
|
if segment.InsertChannel != dmlCh {
|
|
|
|
continue
|
|
|
|
}
|
2021-07-07 14:02:01 +08:00
|
|
|
infos = append(infos, segment)
|
2021-05-31 18:47:32 +08:00
|
|
|
}
|
|
|
|
return infos
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:25:00 +08:00
|
|
|
// GetSegmentsOfCollection get all segments of collection
|
|
|
|
func (m *meta) GetSegmentsOfCollection(collectionID UniqueID) []*SegmentInfo {
|
|
|
|
m.RLock()
|
|
|
|
defer m.RUnlock()
|
|
|
|
|
|
|
|
ret := make([]*SegmentInfo, 0)
|
|
|
|
segments := m.segments.GetSegments()
|
2021-11-08 21:45:00 +08:00
|
|
|
for _, segment := range segments {
|
|
|
|
if segment.GetCollectionID() == collectionID {
|
|
|
|
ret = append(ret, segment)
|
|
|
|
}
|
|
|
|
}
|
2021-11-05 22:25:00 +08:00
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetSegmentsIDOfCollection returns all segment ids which collection equals to provided `collectionID`
|
|
|
|
func (m *meta) GetSegmentsIDOfCollection(collectionID UniqueID) []UniqueID {
|
2021-05-25 15:35:37 +08:00
|
|
|
m.RLock()
|
|
|
|
defer m.RUnlock()
|
2021-01-19 15:35:40 +08:00
|
|
|
ret := make([]UniqueID, 0)
|
2021-07-07 14:02:01 +08:00
|
|
|
segments := m.segments.GetSegments()
|
|
|
|
for _, info := range segments {
|
2021-01-19 15:35:40 +08:00
|
|
|
if info.CollectionID == collectionID {
|
2021-04-09 09:55:04 +08:00
|
|
|
ret = append(ret, info.ID)
|
2021-01-19 15:35:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:25:00 +08:00
|
|
|
// GetSegmentsIDOfPartition returns all segments ids which collection & partition equals to provided `collectionID`, `partitionID`
|
|
|
|
func (m *meta) GetSegmentsIDOfPartition(collectionID, partitionID UniqueID) []UniqueID {
|
2021-05-25 15:35:37 +08:00
|
|
|
m.RLock()
|
|
|
|
defer m.RUnlock()
|
2021-01-19 15:35:40 +08:00
|
|
|
ret := make([]UniqueID, 0)
|
2021-07-07 14:02:01 +08:00
|
|
|
segments := m.segments.GetSegments()
|
|
|
|
for _, info := range segments {
|
2021-01-22 11:07:07 +08:00
|
|
|
if info.CollectionID == collectionID && info.PartitionID == partitionID {
|
2021-04-09 09:55:04 +08:00
|
|
|
ret = append(ret, info.ID)
|
2021-01-19 15:35:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// GetNumRowsOfPartition returns row count of segments belongs to provided collection & partition
|
2021-07-07 14:02:01 +08:00
|
|
|
func (m *meta) GetNumRowsOfPartition(collectionID UniqueID, partitionID UniqueID) int64 {
|
2021-05-25 15:35:37 +08:00
|
|
|
m.RLock()
|
|
|
|
defer m.RUnlock()
|
2021-02-02 14:25:58 +08:00
|
|
|
var ret int64 = 0
|
2021-07-07 14:02:01 +08:00
|
|
|
segments := m.segments.GetSegments()
|
|
|
|
for _, info := range segments {
|
2021-02-02 14:25:58 +08:00
|
|
|
if info.CollectionID == collectionID && info.PartitionID == partitionID {
|
2021-06-04 11:45:45 +08:00
|
|
|
ret += info.NumOfRows
|
2021-02-02 14:25:58 +08:00
|
|
|
}
|
|
|
|
}
|
2021-07-07 14:02:01 +08:00
|
|
|
return ret
|
2021-02-02 14:25:58 +08:00
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// GetUnFlushedSegments get all segments which state is not `Flushing` nor `Flushed`
|
2021-07-12 17:24:25 +08:00
|
|
|
func (m *meta) GetUnFlushedSegments() []*SegmentInfo {
|
2021-05-25 15:35:37 +08:00
|
|
|
m.RLock()
|
|
|
|
defer m.RUnlock()
|
2021-07-12 17:24:25 +08:00
|
|
|
ret := make([]*SegmentInfo, 0)
|
2021-07-07 14:02:01 +08:00
|
|
|
segments := m.segments.GetSegments()
|
|
|
|
for _, info := range segments {
|
2021-05-28 09:55:21 +08:00
|
|
|
if info.State != commonpb.SegmentState_Flushing && info.State != commonpb.SegmentState_Flushed {
|
2021-07-07 14:02:01 +08:00
|
|
|
ret = append(ret, info)
|
2021-05-28 09:55:21 +08:00
|
|
|
}
|
|
|
|
}
|
2021-07-07 14:02:01 +08:00
|
|
|
return ret
|
2021-05-28 09:55:21 +08:00
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// GetFlushingSegments get all segments which state is `Flushing`
|
2021-07-12 17:24:25 +08:00
|
|
|
func (m *meta) GetFlushingSegments() []*SegmentInfo {
|
2021-05-28 09:55:21 +08:00
|
|
|
m.RLock()
|
|
|
|
defer m.RUnlock()
|
2021-07-12 17:24:25 +08:00
|
|
|
ret := make([]*SegmentInfo, 0)
|
2021-07-07 14:02:01 +08:00
|
|
|
segments := m.segments.GetSegments()
|
|
|
|
for _, info := range segments {
|
2021-05-28 09:55:21 +08:00
|
|
|
if info.State == commonpb.SegmentState_Flushing {
|
2021-07-07 14:02:01 +08:00
|
|
|
ret = append(ret, info)
|
2021-05-21 18:30:41 +08:00
|
|
|
}
|
|
|
|
}
|
2021-07-07 14:02:01 +08:00
|
|
|
return ret
|
2021-05-21 18:30:41 +08:00
|
|
|
}
|
|
|
|
|
2021-10-20 15:02:36 +08:00
|
|
|
// SelectSegments select segments with selector
|
|
|
|
func (m *meta) SelectSegments(selector SegmentInfoSelector) []*SegmentInfo {
|
|
|
|
m.RLock()
|
|
|
|
defer m.RUnlock()
|
|
|
|
var ret []*SegmentInfo
|
|
|
|
segments := m.segments.GetSegments()
|
|
|
|
for _, info := range segments {
|
|
|
|
if selector(info) {
|
|
|
|
ret = append(ret, info)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// AddAllocation add allocation in segment
|
2021-07-12 17:24:25 +08:00
|
|
|
func (m *meta) AddAllocation(segmentID UniqueID, allocation *Allocation) error {
|
|
|
|
m.Lock()
|
|
|
|
defer m.Unlock()
|
|
|
|
m.segments.AddAllocation(segmentID, allocation)
|
|
|
|
if segInfo := m.segments.GetSegment(segmentID); segInfo != nil {
|
|
|
|
return m.saveSegmentInfo(segInfo)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// SetAllocations set Segment allocations, will overwrite ALL original allocations
|
|
|
|
// Note that allocations is not persisted in KV store
|
2021-07-12 17:24:25 +08:00
|
|
|
func (m *meta) SetAllocations(segmentID UniqueID, allocations []*Allocation) {
|
|
|
|
m.Lock()
|
|
|
|
defer m.Unlock()
|
|
|
|
m.segments.SetAllocations(segmentID, allocations)
|
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// SetCurrentRows set current row count for segment with provided `segmentID`
|
|
|
|
// Note that currRows is not persisted in KV store
|
2021-07-12 17:24:25 +08:00
|
|
|
func (m *meta) SetCurrentRows(segmentID UniqueID, rows int64) {
|
|
|
|
m.Lock()
|
|
|
|
defer m.Unlock()
|
|
|
|
m.segments.SetCurrentRows(segmentID, rows)
|
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// SetLastFlushTime set LastFlushTime for segment with provided `segmentID`
|
|
|
|
// Note that lastFlushTime is not persisted in KV store
|
2021-08-19 14:08:10 +08:00
|
|
|
func (m *meta) SetLastFlushTime(segmentID UniqueID, t time.Time) {
|
|
|
|
m.Lock()
|
|
|
|
defer m.Unlock()
|
|
|
|
m.segments.SetFlushTime(segmentID, t)
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:25:00 +08:00
|
|
|
// SetSegmentCompacting sets compaction state for segment
|
|
|
|
func (m *meta) SetSegmentCompacting(segmentID UniqueID, compacting bool) {
|
|
|
|
m.Lock()
|
|
|
|
defer m.Unlock()
|
|
|
|
|
|
|
|
m.segments.SetIsCompacting(segmentID, compacting)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *meta) CompleteMergeCompaction(compactionLogs []*datapb.CompactionSegmentBinlogs, result *datapb.CompactionResult) error {
|
|
|
|
m.Lock()
|
|
|
|
defer m.Unlock()
|
|
|
|
|
|
|
|
segments := make([]*SegmentInfo, 0, len(compactionLogs))
|
|
|
|
for _, cl := range compactionLogs {
|
|
|
|
if segment := m.segments.GetSegment(cl.GetSegmentID()); segment != nil {
|
|
|
|
cloned := segment.Clone()
|
|
|
|
cloned.State = commonpb.SegmentState_NotExist
|
|
|
|
segments = append(segments, cloned)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var dmlPosition *internalpb.MsgPosition
|
|
|
|
for _, s := range segments {
|
|
|
|
if dmlPosition == nil || s.GetDmlPosition().Timestamp > dmlPosition.Timestamp {
|
|
|
|
dmlPosition = s.GetDmlPosition()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// find new added delta logs when executing compaction
|
|
|
|
originDeltalogs := make([]*datapb.DeltaLogInfo, 0)
|
|
|
|
for _, s := range segments {
|
|
|
|
originDeltalogs = append(originDeltalogs, s.GetDeltalogs()...)
|
|
|
|
}
|
|
|
|
|
|
|
|
deletedDeltalogs := make([]*datapb.DeltaLogInfo, 0)
|
|
|
|
for _, l := range compactionLogs {
|
|
|
|
deletedDeltalogs = append(deletedDeltalogs, l.GetDeltalogs()...)
|
|
|
|
}
|
|
|
|
|
|
|
|
newAddedDeltalogs := m.updateDeltalogs(originDeltalogs, deletedDeltalogs, nil)
|
|
|
|
deltalogs := append(result.GetDeltalogs(), newAddedDeltalogs...)
|
|
|
|
|
|
|
|
compactionFrom := make([]UniqueID, 0, len(segments))
|
|
|
|
for _, s := range segments {
|
|
|
|
compactionFrom = append(compactionFrom, s.GetID())
|
|
|
|
}
|
|
|
|
|
|
|
|
segment := &SegmentInfo{
|
|
|
|
SegmentInfo: &datapb.SegmentInfo{
|
|
|
|
ID: result.GetSegmentID(),
|
|
|
|
CollectionID: segments[0].CollectionID,
|
|
|
|
PartitionID: segments[0].PartitionID,
|
|
|
|
InsertChannel: segments[0].InsertChannel,
|
|
|
|
NumOfRows: result.NumOfRows,
|
|
|
|
State: commonpb.SegmentState_Flushing,
|
|
|
|
MaxRowNum: segments[0].MaxRowNum,
|
|
|
|
Binlogs: result.GetInsertLogs(),
|
|
|
|
Statslogs: result.GetField2StatslogPaths(),
|
|
|
|
Deltalogs: deltalogs,
|
|
|
|
DmlPosition: dmlPosition,
|
|
|
|
CreatedByCompaction: true,
|
|
|
|
CompactionFrom: compactionFrom,
|
|
|
|
},
|
|
|
|
isCompacting: false,
|
|
|
|
}
|
|
|
|
|
|
|
|
data := make(map[string]string)
|
|
|
|
|
|
|
|
for _, s := range segments {
|
|
|
|
k, v, err := m.marshal(s)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
data[k] = v
|
|
|
|
}
|
|
|
|
k, v, err := m.marshal(segment)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
data[k] = v
|
|
|
|
|
|
|
|
if err := m.saveKvTxn(data); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, s := range segments {
|
|
|
|
m.segments.DropSegment(s.GetID())
|
|
|
|
}
|
|
|
|
|
|
|
|
m.segments.SetSegment(segment.GetID(), segment)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *meta) CompleteInnerCompaction(segmentBinlogs *datapb.CompactionSegmentBinlogs, result *datapb.CompactionResult) error {
|
|
|
|
m.Lock()
|
|
|
|
defer m.Unlock()
|
|
|
|
|
|
|
|
if segment := m.segments.GetSegment(segmentBinlogs.SegmentID); segment != nil {
|
|
|
|
cloned := segment.Clone()
|
|
|
|
cloned.Binlogs = m.updateBinlogs(cloned.GetBinlogs(), segmentBinlogs.GetFieldBinlogs(), result.GetInsertLogs())
|
|
|
|
cloned.Statslogs = m.updateBinlogs(cloned.GetStatslogs(), segmentBinlogs.GetField2StatslogPaths(), result.GetField2StatslogPaths())
|
|
|
|
cloned.Deltalogs = m.updateDeltalogs(cloned.GetDeltalogs(), segmentBinlogs.GetDeltalogs(), result.GetDeltalogs())
|
|
|
|
if err := m.saveSegmentInfo(cloned); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
cloned.isCompacting = false
|
|
|
|
|
|
|
|
m.segments.SetSegment(cloned.GetID(), cloned)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *meta) updateBinlogs(origin []*datapb.FieldBinlog, removes []*datapb.FieldBinlog, adds []*datapb.FieldBinlog) []*datapb.FieldBinlog {
|
|
|
|
fieldBinlogs := make(map[int64]map[string]struct{})
|
|
|
|
for _, f := range origin {
|
|
|
|
fid := f.GetFieldID()
|
|
|
|
if _, ok := fieldBinlogs[fid]; !ok {
|
|
|
|
fieldBinlogs[fid] = make(map[string]struct{})
|
|
|
|
}
|
|
|
|
for _, p := range f.GetBinlogs() {
|
|
|
|
fieldBinlogs[fid][p] = struct{}{}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, f := range removes {
|
|
|
|
fid := f.GetFieldID()
|
|
|
|
if _, ok := fieldBinlogs[fid]; !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
for _, p := range f.GetBinlogs() {
|
|
|
|
delete(fieldBinlogs[fid], p)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, f := range adds {
|
|
|
|
fid := f.GetFieldID()
|
|
|
|
if _, ok := fieldBinlogs[fid]; !ok {
|
|
|
|
fieldBinlogs[fid] = make(map[string]struct{})
|
|
|
|
}
|
|
|
|
for _, p := range f.GetBinlogs() {
|
|
|
|
fieldBinlogs[fid][p] = struct{}{}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
res := make([]*datapb.FieldBinlog, 0, len(fieldBinlogs))
|
|
|
|
for fid, logs := range fieldBinlogs {
|
|
|
|
if len(logs) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
binlogs := make([]string, 0, len(logs))
|
|
|
|
for path := range logs {
|
|
|
|
binlogs = append(binlogs, path)
|
|
|
|
}
|
|
|
|
|
|
|
|
field := &datapb.FieldBinlog{FieldID: fid, Binlogs: binlogs}
|
|
|
|
res = append(res, field)
|
|
|
|
}
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *meta) updateDeltalogs(origin []*datapb.DeltaLogInfo, removes []*datapb.DeltaLogInfo, adds []*datapb.DeltaLogInfo) []*datapb.DeltaLogInfo {
|
|
|
|
deltalogs := make(map[string]*datapb.DeltaLogInfo)
|
|
|
|
for _, d := range origin {
|
|
|
|
deltalogs[d.GetDeltaLogPath()] = d
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, r := range removes {
|
|
|
|
delete(deltalogs, r.GetDeltaLogPath())
|
|
|
|
}
|
|
|
|
|
|
|
|
res := make([]*datapb.DeltaLogInfo, 0, len(deltalogs))
|
|
|
|
for _, log := range deltalogs {
|
|
|
|
res = append(res, log)
|
|
|
|
}
|
|
|
|
res = append(res, adds...)
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *meta) marshal(segment *SegmentInfo) (string, string, error) {
|
|
|
|
segBytes, err := proto.Marshal(segment.SegmentInfo)
|
|
|
|
if err != nil {
|
|
|
|
return "", "", fmt.Errorf("failed to marshal segment info, %v", err)
|
|
|
|
}
|
|
|
|
key := buildSegmentPath(segment.GetCollectionID(), segment.GetPartitionID(), segment.GetID())
|
|
|
|
return key, string(segBytes), nil
|
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// saveSegmentInfo utility function saving segment info into kv store
|
2021-07-12 17:24:25 +08:00
|
|
|
func (m *meta) saveSegmentInfo(segment *SegmentInfo) error {
|
2021-09-29 20:26:00 +08:00
|
|
|
segBytes, err := proto.Marshal(segment.SegmentInfo)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("DataCoord saveSegmentInfo marshal failed", zap.Int64("segmentID", segment.GetID()), zap.Error(err))
|
|
|
|
return fmt.Errorf("DataCoord saveSegmentInfo segmentID:%d, marshal failed:%w", segment.GetID(), err)
|
|
|
|
}
|
2021-10-24 22:39:09 +08:00
|
|
|
kvs := make(map[string]string)
|
|
|
|
dataKey := buildSegmentPath(segment.GetCollectionID(), segment.GetPartitionID(), segment.GetID())
|
|
|
|
kvs[dataKey] = string(segBytes)
|
|
|
|
if segment.State == commonpb.SegmentState_Flushed {
|
|
|
|
handoffSegmentInfo := &querypb.SegmentInfo{
|
2021-11-05 22:25:00 +08:00
|
|
|
SegmentID: segment.ID,
|
|
|
|
CollectionID: segment.CollectionID,
|
|
|
|
PartitionID: segment.PartitionID,
|
|
|
|
ChannelID: segment.InsertChannel,
|
|
|
|
SegmentState: querypb.SegmentState_sealed,
|
|
|
|
CreatedByCompaction: segment.GetCreatedByCompaction(),
|
|
|
|
CompactionFrom: segment.GetCompactionFrom(),
|
2021-10-24 22:39:09 +08:00
|
|
|
}
|
|
|
|
handoffSegBytes, err := proto.Marshal(handoffSegmentInfo)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("DataCoord saveSegmentInfo marshal handoffSegInfo failed", zap.Int64("segmentID", segment.GetID()), zap.Error(err))
|
|
|
|
return fmt.Errorf("DataCoord saveSegmentInfo segmentID:%d, marshal handoffSegInfo failed:%w", segment.GetID(), err)
|
|
|
|
}
|
|
|
|
queryKey := buildQuerySegmentPath(segment.GetCollectionID(), segment.GetPartitionID(), segment.GetID())
|
|
|
|
kvs[queryKey] = string(handoffSegBytes)
|
|
|
|
}
|
|
|
|
|
|
|
|
return m.client.MultiSave(kvs)
|
2021-01-15 17:09:41 +08:00
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// removeSegmentInfo utility function removing segment info from kv store
|
|
|
|
// Note that nil parameter will cause panicking
|
2021-07-12 17:24:25 +08:00
|
|
|
func (m *meta) removeSegmentInfo(segment *SegmentInfo) error {
|
2021-06-22 18:24:08 +08:00
|
|
|
key := buildSegmentPath(segment.GetCollectionID(), segment.GetPartitionID(), segment.GetID())
|
2021-05-25 15:35:37 +08:00
|
|
|
return m.client.Remove(key)
|
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// saveKvTxn batch save kvs
|
2021-05-25 15:35:37 +08:00
|
|
|
func (m *meta) saveKvTxn(kv map[string]string) error {
|
|
|
|
return m.client.MultiSave(kv)
|
2021-02-02 14:25:58 +08:00
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// buildSegmentPath common logic mapping segment info to corresponding key in kv store
|
2021-06-22 18:24:08 +08:00
|
|
|
func buildSegmentPath(collectionID UniqueID, partitionID UniqueID, segmentID UniqueID) string {
|
|
|
|
return fmt.Sprintf("%s/%d/%d/%d", segmentPrefix, collectionID, partitionID, segmentID)
|
|
|
|
}
|
|
|
|
|
2021-10-24 22:39:09 +08:00
|
|
|
// buildQuerySegmentPath common logic mapping segment info to corresponding key of queryCoord in kv store
|
|
|
|
func buildQuerySegmentPath(collectionID UniqueID, partitionID UniqueID, segmentID UniqueID) string {
|
|
|
|
return fmt.Sprintf("%s/%d/%d/%d", handoffSegmentPrefix, collectionID, partitionID, segmentID)
|
|
|
|
}
|
|
|
|
|
2021-09-08 11:35:59 +08:00
|
|
|
// buildSegment utility function for compose datapb.SegmentInfo struct with provided info
|
2021-07-12 17:24:25 +08:00
|
|
|
func buildSegment(collectionID UniqueID, partitionID UniqueID, segmentID UniqueID, channelName string) *SegmentInfo {
|
|
|
|
info := &datapb.SegmentInfo{
|
2021-04-09 09:55:04 +08:00
|
|
|
ID: segmentID,
|
2021-02-02 18:53:10 +08:00
|
|
|
CollectionID: collectionID,
|
|
|
|
PartitionID: partitionID,
|
|
|
|
InsertChannel: channelName,
|
2021-06-04 11:45:45 +08:00
|
|
|
NumOfRows: 0,
|
2021-03-11 14:14:29 +08:00
|
|
|
State: commonpb.SegmentState_Growing,
|
2021-07-07 14:02:01 +08:00
|
|
|
}
|
2021-07-12 17:24:25 +08:00
|
|
|
return NewSegmentInfo(info)
|
2021-01-25 15:17:17 +08:00
|
|
|
}
|