mirror of
https://gitee.com/milvus-io/milvus.git
synced 2024-12-05 05:18:52 +08:00
956c5e1b9d
Signed-off-by: Enwei Jiao <enwei.jiao@zilliz.com> Signed-off-by: Enwei Jiao <enwei.jiao@zilliz.com>
422 lines
12 KiB
Go
422 lines
12 KiB
Go
// Licensed to the LF AI & Data foundation under one
|
|
// or more contributor license agreements. See the NOTICE file
|
|
// distributed with this work for additional information
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
// to you under the Apache License, Version 2.0 (the
|
|
// "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package querynode
|
|
|
|
/*
|
|
#cgo pkg-config: milvus_segcore
|
|
|
|
#include "segcore/collection_c.h"
|
|
#include "segcore/segment_c.h"
|
|
*/
|
|
import "C"
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"sync"
|
|
"sync/atomic"
|
|
"unsafe"
|
|
|
|
"github.com/milvus-io/milvus/internal/util/paramtable"
|
|
"github.com/milvus-io/milvus/internal/util/typeutil"
|
|
|
|
"github.com/milvus-io/milvus/internal/metrics"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/golang/protobuf/proto"
|
|
|
|
"github.com/milvus-io/milvus-proto/go-api/schemapb"
|
|
"github.com/milvus-io/milvus/internal/log"
|
|
)
|
|
|
|
// Collection is a wrapper of the underlying C-structure C.CCollection
|
|
type Collection struct {
|
|
mu sync.RWMutex // protects colllectionPtr
|
|
collectionPtr C.CCollection
|
|
id UniqueID
|
|
partitionIDs []UniqueID
|
|
schema *schemapb.CollectionSchema
|
|
|
|
// TODO, remove delta channels
|
|
channelMu sync.RWMutex
|
|
vChannels []Channel
|
|
pChannels []Channel
|
|
vDeltaChannels []Channel
|
|
pDeltaChannels []Channel
|
|
|
|
loadType int32
|
|
|
|
releaseMu sync.RWMutex // guards release
|
|
releasedPartitions map[UniqueID]struct{}
|
|
releaseTime Timestamp
|
|
released bool
|
|
}
|
|
|
|
// ID returns collection id
|
|
func (c *Collection) ID() UniqueID {
|
|
return c.id
|
|
}
|
|
|
|
// Schema returns the schema of collection
|
|
func (c *Collection) Schema() *schemapb.CollectionSchema {
|
|
return c.schema
|
|
}
|
|
|
|
// getPartitionIDs return partitionIDs of collection
|
|
func (c *Collection) getPartitionIDs() []UniqueID {
|
|
dst := make([]UniqueID, len(c.partitionIDs))
|
|
copy(dst, c.partitionIDs)
|
|
return dst
|
|
}
|
|
|
|
// addPartitionID would add a partition id to partition id list of collection
|
|
func (c *Collection) addPartitionID(partitionID UniqueID) {
|
|
c.partitionIDs = append(c.partitionIDs, partitionID)
|
|
log.Info("queryNode collection info after add a partition",
|
|
zap.Int64("partitionID", partitionID), zap.Int64("collectionID", c.id),
|
|
zap.Int64s("partitions", c.partitionIDs))
|
|
}
|
|
|
|
// removePartitionID removes the partition id from partition id list of collection
|
|
func (c *Collection) removePartitionID(partitionID UniqueID) {
|
|
tmpIDs := make([]UniqueID, 0, len(c.partitionIDs))
|
|
for _, id := range c.partitionIDs {
|
|
if id != partitionID {
|
|
tmpIDs = append(tmpIDs, id)
|
|
}
|
|
}
|
|
c.partitionIDs = tmpIDs
|
|
}
|
|
|
|
// addVChannels adds virtual channels to collection
|
|
func (c *Collection) addVChannels(channels []Channel) {
|
|
c.channelMu.Lock()
|
|
defer c.channelMu.Unlock()
|
|
OUTER:
|
|
for _, dstChan := range channels {
|
|
for _, srcChan := range c.vChannels {
|
|
if dstChan == srcChan {
|
|
log.Warn("vChannel has been existed in collection's vChannels",
|
|
zap.Int64("collectionID", c.ID()),
|
|
zap.String("vChannel", dstChan),
|
|
)
|
|
continue OUTER
|
|
}
|
|
}
|
|
log.Info("add vChannel to collection",
|
|
zap.Int64("collectionID", c.ID()),
|
|
zap.String("vChannel", dstChan),
|
|
)
|
|
c.vChannels = append(c.vChannels, dstChan)
|
|
}
|
|
|
|
metrics.QueryNodeNumDmlChannels.WithLabelValues(fmt.Sprint(paramtable.GetNodeID())).Add(float64(len(c.vChannels)))
|
|
}
|
|
|
|
// getVChannels get virtual channels of collection
|
|
func (c *Collection) getVChannels() []Channel {
|
|
c.channelMu.RLock()
|
|
defer c.channelMu.RUnlock()
|
|
tmpChannels := make([]Channel, len(c.vChannels))
|
|
copy(tmpChannels, c.vChannels)
|
|
return tmpChannels
|
|
}
|
|
|
|
// removeVChannel remove the virtual channel from collection
|
|
func (c *Collection) removeVChannel(channel Channel) {
|
|
c.channelMu.Lock()
|
|
defer c.channelMu.Unlock()
|
|
tmpChannels := make([]Channel, 0)
|
|
for _, vChannel := range c.vChannels {
|
|
if channel != vChannel {
|
|
tmpChannels = append(tmpChannels, vChannel)
|
|
}
|
|
}
|
|
c.vChannels = tmpChannels
|
|
log.Info("remove vChannel from collection",
|
|
zap.Int64("collectionID", c.ID()),
|
|
zap.String("channel", channel),
|
|
)
|
|
|
|
metrics.QueryNodeNumDmlChannels.WithLabelValues(fmt.Sprint(paramtable.GetNodeID())).Sub(float64(len(c.vChannels)))
|
|
}
|
|
|
|
// addPChannels add physical channels to physical channels of collection
|
|
func (c *Collection) addPChannels(channels []Channel) {
|
|
c.channelMu.Lock()
|
|
defer c.channelMu.Unlock()
|
|
OUTER:
|
|
for _, dstChan := range channels {
|
|
for _, srcChan := range c.pChannels {
|
|
if dstChan == srcChan {
|
|
log.Info("pChannel has been existed in collection's pChannels",
|
|
zap.Int64("collectionID", c.ID()),
|
|
zap.String("pChannel", dstChan),
|
|
)
|
|
continue OUTER
|
|
}
|
|
}
|
|
log.Info("add pChannel to collection",
|
|
zap.Int64("collectionID", c.ID()),
|
|
zap.String("pChannel", dstChan),
|
|
)
|
|
c.pChannels = append(c.pChannels, dstChan)
|
|
}
|
|
}
|
|
|
|
// getPChannels get physical channels of collection
|
|
func (c *Collection) getPChannels() []Channel {
|
|
c.channelMu.RLock()
|
|
defer c.channelMu.RUnlock()
|
|
tmpChannels := make([]Channel, len(c.pChannels))
|
|
copy(tmpChannels, c.pChannels)
|
|
return tmpChannels
|
|
}
|
|
|
|
// addPChannels add physical channels to physical channels of collection
|
|
func (c *Collection) addPDeltaChannels(channels []Channel) {
|
|
c.channelMu.Lock()
|
|
defer c.channelMu.Unlock()
|
|
OUTER:
|
|
for _, dstChan := range channels {
|
|
for _, srcChan := range c.pDeltaChannels {
|
|
if dstChan == srcChan {
|
|
log.Info("pChannel has been existed in collection's pChannels",
|
|
zap.Int64("collectionID", c.ID()),
|
|
zap.String("pChannel", dstChan),
|
|
)
|
|
continue OUTER
|
|
}
|
|
}
|
|
log.Info("add pChannel to collection",
|
|
zap.Int64("collectionID", c.ID()),
|
|
zap.String("pChannel", dstChan),
|
|
)
|
|
c.pDeltaChannels = append(c.pDeltaChannels, dstChan)
|
|
}
|
|
}
|
|
|
|
// getPChannels get physical channels of collection
|
|
func (c *Collection) getPDeltaChannels() []Channel {
|
|
c.channelMu.RLock()
|
|
defer c.channelMu.RUnlock()
|
|
tmpChannels := make([]Channel, len(c.pDeltaChannels))
|
|
copy(tmpChannels, c.pDeltaChannels)
|
|
return tmpChannels
|
|
}
|
|
|
|
func (c *Collection) getVDeltaChannels() []Channel {
|
|
c.channelMu.RLock()
|
|
defer c.channelMu.RUnlock()
|
|
tmpChannels := make([]Channel, len(c.vDeltaChannels))
|
|
copy(tmpChannels, c.vDeltaChannels)
|
|
return tmpChannels
|
|
}
|
|
|
|
func (c *Collection) AddChannels(toLoadChannels []Channel, VPChannels map[string]string) []Channel {
|
|
c.channelMu.Lock()
|
|
defer c.channelMu.Unlock()
|
|
|
|
retVChannels := []Channel{}
|
|
for _, toLoadChannel := range toLoadChannels {
|
|
if !c.isVChannelExist(toLoadChannel) {
|
|
retVChannels = append(retVChannels, toLoadChannel)
|
|
c.vChannels = append(c.vChannels, toLoadChannel)
|
|
if !c.isPChannelExist(VPChannels[toLoadChannel]) {
|
|
c.pChannels = append(c.pChannels, VPChannels[toLoadChannel])
|
|
}
|
|
}
|
|
}
|
|
return retVChannels
|
|
}
|
|
|
|
func (c *Collection) isVChannelExist(channel string) bool {
|
|
for _, vChannel := range c.vChannels {
|
|
if vChannel == channel {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (c *Collection) isPChannelExist(channel string) bool {
|
|
for _, vChannel := range c.pChannels {
|
|
if vChannel == channel {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// addVChannels add virtual channels to collection
|
|
func (c *Collection) addVDeltaChannels(channels []Channel) {
|
|
c.channelMu.Lock()
|
|
defer c.channelMu.Unlock()
|
|
OUTER:
|
|
for _, dstChan := range channels {
|
|
for _, srcChan := range c.vDeltaChannels {
|
|
if dstChan == srcChan {
|
|
log.Info("vDeltaChannel has been existed in collection's vDeltaChannels",
|
|
zap.Int64("collectionID", c.ID()),
|
|
zap.String("vChannel", dstChan),
|
|
)
|
|
continue OUTER
|
|
}
|
|
}
|
|
log.Info("add vDeltaChannel to collection",
|
|
zap.Int64("collectionID", c.ID()),
|
|
zap.String("vDeltaChannel", dstChan),
|
|
)
|
|
c.vDeltaChannels = append(c.vDeltaChannels, dstChan)
|
|
}
|
|
|
|
metrics.QueryNodeNumDeltaChannels.WithLabelValues(fmt.Sprint(paramtable.GetNodeID())).Add(float64(len(c.vDeltaChannels)))
|
|
}
|
|
|
|
func (c *Collection) removeVDeltaChannel(channel Channel) {
|
|
c.channelMu.Lock()
|
|
defer c.channelMu.Unlock()
|
|
tmpChannels := make([]Channel, 0)
|
|
for _, vChannel := range c.vDeltaChannels {
|
|
if channel != vChannel {
|
|
tmpChannels = append(tmpChannels, vChannel)
|
|
}
|
|
}
|
|
c.vDeltaChannels = tmpChannels
|
|
log.Info("remove vDeltaChannel from collection",
|
|
zap.Int64("collectionID", c.ID()),
|
|
zap.String("channel", channel),
|
|
)
|
|
|
|
metrics.QueryNodeNumDeltaChannels.WithLabelValues(fmt.Sprint(paramtable.GetNodeID())).Sub(float64(len(c.vDeltaChannels)))
|
|
}
|
|
|
|
func (c *Collection) AddVDeltaChannels(toLoadChannels []Channel, VPChannels map[string]string) []Channel {
|
|
c.channelMu.Lock()
|
|
defer c.channelMu.Unlock()
|
|
|
|
retVDeltaChannels := []Channel{}
|
|
for _, toLoadChannel := range toLoadChannels {
|
|
if !c.isVDeltaChannelExist(toLoadChannel) {
|
|
retVDeltaChannels = append(retVDeltaChannels, toLoadChannel)
|
|
c.vDeltaChannels = append(c.vDeltaChannels, toLoadChannel)
|
|
if !c.isPDeltaChannelExist(VPChannels[toLoadChannel]) {
|
|
c.pDeltaChannels = append(c.pDeltaChannels, VPChannels[toLoadChannel])
|
|
}
|
|
}
|
|
}
|
|
return retVDeltaChannels
|
|
}
|
|
|
|
func (c *Collection) isVDeltaChannelExist(channel string) bool {
|
|
for _, vDeltaChanel := range c.vDeltaChannels {
|
|
if vDeltaChanel == channel {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (c *Collection) isPDeltaChannelExist(channel string) bool {
|
|
for _, vChannel := range c.pDeltaChannels {
|
|
if vChannel == channel {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// setReleaseTime records when collection is released
|
|
func (c *Collection) setReleaseTime(t Timestamp, released bool) {
|
|
c.releaseMu.Lock()
|
|
defer c.releaseMu.Unlock()
|
|
c.releaseTime = t
|
|
c.released = released
|
|
}
|
|
|
|
// getReleaseTime gets the time when collection is released
|
|
func (c *Collection) getReleaseTime() (Timestamp, bool) {
|
|
c.releaseMu.RLock()
|
|
defer c.releaseMu.RUnlock()
|
|
return c.releaseTime, c.released
|
|
}
|
|
|
|
// setLoadType set the loading type of collection, which is loadTypeCollection or loadTypePartition
|
|
func (c *Collection) setLoadType(l loadType) {
|
|
atomic.StoreInt32(&c.loadType, int32(l))
|
|
}
|
|
|
|
// getLoadType get the loadType of collection, which is loadTypeCollection or loadTypePartition
|
|
func (c *Collection) getLoadType() loadType {
|
|
l := atomic.LoadInt32(&c.loadType)
|
|
return loadType(l)
|
|
}
|
|
|
|
// getFieldType get the field type according to the field id.
|
|
func (c *Collection) getFieldType(fieldID FieldID) (schemapb.DataType, error) {
|
|
helper, err := typeutil.CreateSchemaHelper(c.schema)
|
|
if err != nil {
|
|
return schemapb.DataType_None, err
|
|
}
|
|
field, err := helper.GetFieldFromID(fieldID)
|
|
if err != nil {
|
|
return schemapb.DataType_None, err
|
|
}
|
|
return field.GetDataType(), nil
|
|
}
|
|
|
|
// newCollection returns a new Collection
|
|
func newCollection(collectionID UniqueID, schema *schemapb.CollectionSchema) *Collection {
|
|
/*
|
|
CCollection
|
|
NewCollection(const char* schema_proto_blob);
|
|
*/
|
|
schemaBlob := proto.MarshalTextString(schema)
|
|
|
|
cSchemaBlob := C.CString(schemaBlob)
|
|
collection := C.NewCollection(cSchemaBlob)
|
|
|
|
var newCollection = &Collection{
|
|
collectionPtr: collection,
|
|
id: collectionID,
|
|
schema: schema,
|
|
releasedPartitions: make(map[UniqueID]struct{}),
|
|
}
|
|
C.free(unsafe.Pointer(cSchemaBlob))
|
|
|
|
log.Info("create collection", zap.Int64("collectionID", collectionID))
|
|
|
|
newCollection.setReleaseTime(Timestamp(math.MaxUint64), false)
|
|
return newCollection
|
|
}
|
|
|
|
// deleteCollection delete collection and free the collection memory
|
|
func deleteCollection(collection *Collection) {
|
|
/*
|
|
void
|
|
deleteCollection(CCollection collection);
|
|
*/
|
|
cPtr := collection.collectionPtr
|
|
C.DeleteCollection(cPtr)
|
|
|
|
collection.collectionPtr = nil
|
|
|
|
log.Info("delete collection", zap.Int64("collectionID", collection.ID()))
|
|
|
|
collection = nil
|
|
}
|