2020-08-25 15:45:19 +08:00
|
|
|
package reader
|
|
|
|
|
2020-09-02 10:38:08 +08:00
|
|
|
/*
|
|
|
|
|
2020-09-18 15:44:09 +08:00
|
|
|
#cgo CFLAGS: -I${SRCDIR}/../../core/include
|
2020-09-02 10:38:08 +08:00
|
|
|
|
2020-09-18 15:44:09 +08:00
|
|
|
#cgo LDFLAGS: -L${SRCDIR}/../../core/lib -lmilvus_dog_segment -Wl,-rpath=${SRCDIR}/../../core/lib
|
2020-09-02 10:38:08 +08:00
|
|
|
|
|
|
|
#include "collection_c.h"
|
|
|
|
#include "partition_c.h"
|
|
|
|
#include "segment_c.h"
|
|
|
|
|
|
|
|
*/
|
2020-08-25 15:45:19 +08:00
|
|
|
import "C"
|
2020-09-02 10:38:08 +08:00
|
|
|
|
2020-08-25 15:45:19 +08:00
|
|
|
import (
|
2020-09-22 11:21:19 +08:00
|
|
|
"encoding/json"
|
2020-08-28 17:29:26 +08:00
|
|
|
"fmt"
|
2020-09-22 21:10:51 +08:00
|
|
|
"github.com/stretchr/testify/assert"
|
2020-09-22 11:21:19 +08:00
|
|
|
"log"
|
2020-09-08 10:39:09 +08:00
|
|
|
"sort"
|
2020-08-28 17:29:26 +08:00
|
|
|
"sync"
|
2020-09-15 15:53:10 +08:00
|
|
|
"sync/atomic"
|
2020-09-18 15:44:09 +08:00
|
|
|
|
|
|
|
msgPb "github.com/czs007/suvlim/pkg/master/grpc/message"
|
|
|
|
"github.com/czs007/suvlim/pkg/master/kv"
|
|
|
|
"github.com/czs007/suvlim/reader/message_client"
|
|
|
|
//"github.com/stretchr/testify/assert"
|
2020-08-25 15:45:19 +08:00
|
|
|
)
|
|
|
|
|
2020-09-09 15:24:07 +08:00
|
|
|
type InsertData struct {
|
2020-09-15 15:53:10 +08:00
|
|
|
insertIDs map[int64][]int64
|
|
|
|
insertTimestamps map[int64][]uint64
|
|
|
|
insertRecords map[int64][][]byte
|
|
|
|
insertOffset map[int64]int64
|
2020-09-09 15:24:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
type DeleteData struct {
|
2020-09-15 15:53:10 +08:00
|
|
|
deleteIDs map[int64][]int64
|
|
|
|
deleteTimestamps map[int64][]uint64
|
|
|
|
deleteOffset map[int64]int64
|
2020-09-09 15:24:07 +08:00
|
|
|
}
|
|
|
|
|
2020-09-07 17:01:46 +08:00
|
|
|
type DeleteRecord struct {
|
2020-09-15 15:53:10 +08:00
|
|
|
entityID int64
|
|
|
|
timestamp uint64
|
|
|
|
segmentID int64
|
2020-09-07 17:01:46 +08:00
|
|
|
}
|
|
|
|
|
2020-09-09 15:24:07 +08:00
|
|
|
type DeletePreprocessData struct {
|
2020-09-15 15:53:10 +08:00
|
|
|
deleteRecords []*DeleteRecord
|
|
|
|
count int32
|
2020-08-28 18:39:00 +08:00
|
|
|
}
|
|
|
|
|
2020-09-07 17:01:46 +08:00
|
|
|
type QueryNodeDataBuffer struct {
|
2020-09-08 10:39:09 +08:00
|
|
|
InsertDeleteBuffer []*msgPb.InsertOrDeleteMsg
|
|
|
|
SearchBuffer []*msgPb.SearchMsg
|
2020-09-07 17:01:46 +08:00
|
|
|
validInsertDeleteBuffer []bool
|
|
|
|
validSearchBuffer []bool
|
2020-08-25 15:45:19 +08:00
|
|
|
}
|
|
|
|
|
2020-09-22 11:21:19 +08:00
|
|
|
type QueryInfo struct {
|
|
|
|
NumQueries int64 `json:"num_queries"`
|
|
|
|
TopK int `json:"topK"`
|
|
|
|
FieldName string `json:"field_name"`
|
|
|
|
}
|
|
|
|
|
2020-08-25 15:45:19 +08:00
|
|
|
type QueryNode struct {
|
2020-09-18 15:44:09 +08:00
|
|
|
QueryNodeId uint64
|
|
|
|
Collections []*Collection
|
|
|
|
SegmentsMap map[int64]*Segment
|
|
|
|
messageClient *message_client.MessageClient
|
2020-09-15 17:41:05 +08:00
|
|
|
//mc *message_client.MessageClient
|
2020-09-09 15:24:07 +08:00
|
|
|
queryNodeTimeSync *QueryNodeTime
|
|
|
|
buffer QueryNodeDataBuffer
|
|
|
|
deletePreprocessData DeletePreprocessData
|
2020-09-15 15:53:10 +08:00
|
|
|
deleteData DeleteData
|
2020-09-09 15:24:07 +08:00
|
|
|
insertData InsertData
|
2020-09-18 15:44:09 +08:00
|
|
|
kvBase *kv.EtcdKVBase
|
2020-08-25 15:45:19 +08:00
|
|
|
}
|
|
|
|
|
2020-09-02 10:38:08 +08:00
|
|
|
func NewQueryNode(queryNodeId uint64, timeSync uint64) *QueryNode {
|
2020-09-08 10:39:09 +08:00
|
|
|
mc := message_client.MessageClient{}
|
2020-09-07 17:01:46 +08:00
|
|
|
|
|
|
|
queryNodeTimeSync := &QueryNodeTime{
|
|
|
|
ReadTimeSyncMin: timeSync,
|
|
|
|
ReadTimeSyncMax: timeSync,
|
|
|
|
WriteTimeSync: timeSync,
|
|
|
|
SearchTimeSync: timeSync,
|
|
|
|
TSOTimeSync: timeSync,
|
2020-08-25 15:45:19 +08:00
|
|
|
}
|
|
|
|
|
2020-09-07 17:01:46 +08:00
|
|
|
segmentsMap := make(map[int64]*Segment)
|
|
|
|
|
2020-09-15 15:53:10 +08:00
|
|
|
buffer := QueryNodeDataBuffer{
|
|
|
|
InsertDeleteBuffer: make([]*msgPb.InsertOrDeleteMsg, 0),
|
|
|
|
SearchBuffer: make([]*msgPb.SearchMsg, 0),
|
|
|
|
validInsertDeleteBuffer: make([]bool, 0),
|
|
|
|
validSearchBuffer: make([]bool, 0),
|
|
|
|
}
|
|
|
|
|
2020-09-15 17:41:05 +08:00
|
|
|
return &QueryNode{
|
2020-09-18 15:44:09 +08:00
|
|
|
QueryNodeId: queryNodeId,
|
|
|
|
Collections: nil,
|
|
|
|
SegmentsMap: segmentsMap,
|
|
|
|
messageClient: &mc,
|
|
|
|
queryNodeTimeSync: queryNodeTimeSync,
|
|
|
|
buffer: buffer,
|
2020-09-15 17:41:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (node *QueryNode) Close() {
|
|
|
|
node.messageClient.Close()
|
2020-09-21 15:10:54 +08:00
|
|
|
node.kvBase.Close()
|
2020-09-15 17:41:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func CreateQueryNode(queryNodeId uint64, timeSync uint64, mc *message_client.MessageClient) *QueryNode {
|
|
|
|
queryNodeTimeSync := &QueryNodeTime{
|
|
|
|
ReadTimeSyncMin: timeSync,
|
|
|
|
ReadTimeSyncMax: timeSync,
|
|
|
|
WriteTimeSync: timeSync,
|
|
|
|
SearchTimeSync: timeSync,
|
|
|
|
TSOTimeSync: timeSync,
|
|
|
|
}
|
|
|
|
|
|
|
|
segmentsMap := make(map[int64]*Segment)
|
|
|
|
|
|
|
|
buffer := QueryNodeDataBuffer{
|
|
|
|
InsertDeleteBuffer: make([]*msgPb.InsertOrDeleteMsg, 0),
|
|
|
|
SearchBuffer: make([]*msgPb.SearchMsg, 0),
|
|
|
|
validInsertDeleteBuffer: make([]bool, 0),
|
|
|
|
validSearchBuffer: make([]bool, 0),
|
|
|
|
}
|
|
|
|
|
2020-08-25 15:45:19 +08:00
|
|
|
return &QueryNode{
|
2020-09-18 15:44:09 +08:00
|
|
|
QueryNodeId: queryNodeId,
|
|
|
|
Collections: nil,
|
|
|
|
SegmentsMap: segmentsMap,
|
|
|
|
messageClient: mc,
|
|
|
|
queryNodeTimeSync: queryNodeTimeSync,
|
|
|
|
buffer: buffer,
|
2020-09-15 15:53:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (node *QueryNode) QueryNodeDataInit() {
|
|
|
|
deletePreprocessData := DeletePreprocessData{
|
|
|
|
deleteRecords: make([]*DeleteRecord, 0),
|
|
|
|
count: 0,
|
|
|
|
}
|
|
|
|
|
|
|
|
deleteData := DeleteData{
|
|
|
|
deleteIDs: make(map[int64][]int64),
|
|
|
|
deleteTimestamps: make(map[int64][]uint64),
|
|
|
|
deleteOffset: make(map[int64]int64),
|
|
|
|
}
|
|
|
|
|
|
|
|
insertData := InsertData{
|
|
|
|
insertIDs: make(map[int64][]int64),
|
|
|
|
insertTimestamps: make(map[int64][]uint64),
|
|
|
|
insertRecords: make(map[int64][][]byte),
|
|
|
|
insertOffset: make(map[int64]int64),
|
2020-09-14 11:26:35 +08:00
|
|
|
}
|
2020-09-15 15:53:10 +08:00
|
|
|
|
|
|
|
node.deletePreprocessData = deletePreprocessData
|
|
|
|
node.deleteData = deleteData
|
|
|
|
node.insertData = insertData
|
2020-09-14 11:26:35 +08:00
|
|
|
}
|
|
|
|
|
2020-09-21 15:10:54 +08:00
|
|
|
func (node *QueryNode) NewCollection(collectionID uint64, collectionName string, schemaConfig string) *Collection {
|
2020-09-21 18:16:06 +08:00
|
|
|
/*
|
|
|
|
void
|
|
|
|
UpdateIndexes(CCollection c_collection, const char *index_string);
|
|
|
|
*/
|
2020-08-31 15:54:44 +08:00
|
|
|
cName := C.CString(collectionName)
|
2020-09-02 10:38:08 +08:00
|
|
|
cSchema := C.CString(schemaConfig)
|
2020-09-01 16:23:39 +08:00
|
|
|
collection := C.NewCollection(cName, cSchema)
|
2020-08-31 15:54:44 +08:00
|
|
|
|
2020-09-21 15:10:54 +08:00
|
|
|
var newCollection = &Collection{CollectionPtr: collection, CollectionName: collectionName, CollectionID: collectionID}
|
2020-08-31 15:54:44 +08:00
|
|
|
node.Collections = append(node.Collections, newCollection)
|
|
|
|
|
2020-09-01 16:23:39 +08:00
|
|
|
return newCollection
|
2020-08-31 15:54:44 +08:00
|
|
|
}
|
|
|
|
|
2020-09-01 16:23:39 +08:00
|
|
|
func (node *QueryNode) DeleteCollection(collection *Collection) {
|
2020-09-21 18:16:06 +08:00
|
|
|
/*
|
|
|
|
void
|
|
|
|
DeleteCollection(CCollection collection);
|
|
|
|
*/
|
2020-09-01 16:23:39 +08:00
|
|
|
cPtr := collection.CollectionPtr
|
|
|
|
C.DeleteCollection(cPtr)
|
2020-08-31 15:54:44 +08:00
|
|
|
|
|
|
|
// TODO: remove from node.Collections
|
|
|
|
}
|
|
|
|
|
2020-09-21 18:16:06 +08:00
|
|
|
func (node *QueryNode) UpdateIndexes(collection *Collection, indexConfig *string) {
|
|
|
|
/*
|
|
|
|
void
|
|
|
|
UpdateIndexes(CCollection c_collection, const char *index_string);
|
|
|
|
*/
|
|
|
|
cCollectionPtr := collection.CollectionPtr
|
|
|
|
cIndexConfig := C.CString(*indexConfig)
|
|
|
|
C.UpdateIndexes(cCollectionPtr, cIndexConfig)
|
|
|
|
}
|
|
|
|
|
2020-08-31 15:54:44 +08:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2020-09-15 15:53:10 +08:00
|
|
|
func (node *QueryNode) PrepareBatchMsg() []int {
|
2020-09-18 15:44:09 +08:00
|
|
|
var msgLen = node.messageClient.PrepareBatchMsg()
|
2020-09-15 15:53:10 +08:00
|
|
|
return msgLen
|
2020-08-28 17:29:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (node *QueryNode) InitQueryNodeCollection() {
|
|
|
|
// TODO: remove hard code, add collection creation request
|
2020-08-31 15:54:44 +08:00
|
|
|
// TODO: error handle
|
2020-09-21 15:10:54 +08:00
|
|
|
var newCollection = node.NewCollection(0, "collection1", "fakeSchema")
|
2020-09-01 16:23:39 +08:00
|
|
|
var newPartition = newCollection.NewPartition("partition1")
|
2020-08-29 17:42:41 +08:00
|
|
|
// TODO: add segment id
|
2020-09-15 15:53:10 +08:00
|
|
|
var segment = newPartition.NewSegment(0)
|
|
|
|
node.SegmentsMap[0] = segment
|
2020-08-28 17:29:26 +08:00
|
|
|
}
|
|
|
|
|
2020-09-09 15:24:07 +08:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2020-09-18 15:44:09 +08:00
|
|
|
func (node *QueryNode) RunInsertDelete(wg *sync.WaitGroup) {
|
2020-09-09 15:24:07 +08:00
|
|
|
for {
|
|
|
|
// TODO: get timeRange from message client
|
2020-09-15 15:53:10 +08:00
|
|
|
var msgLen = node.PrepareBatchMsg()
|
2020-09-15 17:41:05 +08:00
|
|
|
var timeRange = TimeRange{node.messageClient.TimeSyncStart(), node.messageClient.TimeSyncEnd()}
|
2020-09-22 21:10:51 +08:00
|
|
|
assert.NotEqual(nil, 0, timeRange.timestampMin)
|
|
|
|
assert.NotEqual(nil, 0, timeRange.timestampMax)
|
2020-09-15 17:41:05 +08:00
|
|
|
|
2020-09-16 15:21:10 +08:00
|
|
|
if msgLen[0] == 0 && len(node.buffer.InsertDeleteBuffer) <= 0 {
|
2020-09-15 15:53:10 +08:00
|
|
|
continue
|
|
|
|
}
|
2020-09-15 17:41:05 +08:00
|
|
|
|
|
|
|
node.QueryNodeDataInit()
|
2020-09-09 15:24:07 +08:00
|
|
|
node.MessagesPreprocess(node.messageClient.InsertOrDeleteMsg, timeRange)
|
2020-09-22 21:10:51 +08:00
|
|
|
//fmt.Println("MessagesPreprocess Done")
|
2020-09-09 15:24:07 +08:00
|
|
|
node.WriterDelete()
|
|
|
|
node.PreInsertAndDelete()
|
2020-09-22 21:10:51 +08:00
|
|
|
//fmt.Println("PreInsertAndDelete Done")
|
2020-09-09 15:24:07 +08:00
|
|
|
node.DoInsertAndDelete()
|
2020-09-22 21:10:51 +08:00
|
|
|
//fmt.Println("DoInsertAndDelete Done")
|
2020-09-09 15:24:07 +08:00
|
|
|
node.queryNodeTimeSync.UpdateSearchTimeSync(timeRange)
|
2020-08-28 17:29:26 +08:00
|
|
|
}
|
2020-09-15 17:41:05 +08:00
|
|
|
wg.Done()
|
2020-08-28 17:29:26 +08:00
|
|
|
}
|
|
|
|
|
2020-09-15 17:41:05 +08:00
|
|
|
func (node *QueryNode) TestInsertDelete(timeRange TimeRange) {
|
|
|
|
node.QueryNodeDataInit()
|
|
|
|
node.MessagesPreprocess(node.messageClient.InsertOrDeleteMsg, timeRange)
|
|
|
|
fmt.Println("MessagesPreprocess Done")
|
|
|
|
node.WriterDelete()
|
|
|
|
node.PreInsertAndDelete()
|
|
|
|
fmt.Println("PreInsertAndDelete Done")
|
|
|
|
node.DoInsertAndDelete()
|
|
|
|
fmt.Println("DoInsertAndDelete Done")
|
|
|
|
node.queryNodeTimeSync.UpdateSearchTimeSync(timeRange)
|
|
|
|
fmt.Print("UpdateSearchTimeSync Done\n\n\n")
|
|
|
|
}
|
2020-09-15 15:53:10 +08:00
|
|
|
|
2020-09-15 17:41:05 +08:00
|
|
|
func (node *QueryNode) RunSearch(wg *sync.WaitGroup) {
|
|
|
|
for {
|
|
|
|
msg, ok := <-node.messageClient.GetSearchChan()
|
|
|
|
if ok {
|
|
|
|
node.messageClient.SearchMsg = node.messageClient.SearchMsg[:0]
|
|
|
|
node.messageClient.SearchMsg = append(node.messageClient.SearchMsg, msg)
|
|
|
|
fmt.Println("Do Search...")
|
2020-09-16 15:21:10 +08:00
|
|
|
var status = node.Search(node.messageClient.SearchMsg)
|
|
|
|
if status.ErrorCode != 0 {
|
|
|
|
fmt.Println("Search Failed")
|
|
|
|
node.PublishFailedSearchResult()
|
|
|
|
}
|
2020-09-15 15:53:10 +08:00
|
|
|
}
|
2020-08-28 17:29:26 +08:00
|
|
|
}
|
2020-09-15 17:41:05 +08:00
|
|
|
wg.Done()
|
2020-08-28 17:29:26 +08:00
|
|
|
}
|
|
|
|
|
2020-09-09 15:24:07 +08:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
2020-09-09 14:34:03 +08:00
|
|
|
|
2020-09-09 15:24:07 +08:00
|
|
|
func (node *QueryNode) MessagesPreprocess(insertDeleteMessages []*msgPb.InsertOrDeleteMsg, timeRange TimeRange) msgPb.Status {
|
2020-09-15 17:41:05 +08:00
|
|
|
var tMax = timeRange.timestampMax
|
2020-09-07 17:01:46 +08:00
|
|
|
|
|
|
|
// 1. Extract messages before readTimeSync from QueryNodeDataBuffer.
|
|
|
|
// Set valid bitmap to false.
|
|
|
|
for i, msg := range node.buffer.InsertDeleteBuffer {
|
2020-09-15 17:41:05 +08:00
|
|
|
if msg.Timestamp < tMax {
|
|
|
|
if msg.Op == msgPb.OpType_INSERT {
|
|
|
|
if msg.RowsData == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
node.insertData.insertIDs[msg.SegmentId] = append(node.insertData.insertIDs[msg.SegmentId], msg.Uid)
|
|
|
|
node.insertData.insertTimestamps[msg.SegmentId] = append(node.insertData.insertTimestamps[msg.SegmentId], msg.Timestamp)
|
|
|
|
node.insertData.insertRecords[msg.SegmentId] = append(node.insertData.insertRecords[msg.SegmentId], msg.RowsData.Blob)
|
|
|
|
} else if msg.Op == msgPb.OpType_DELETE {
|
|
|
|
var r = DeleteRecord{
|
|
|
|
entityID: msg.Uid,
|
|
|
|
timestamp: msg.Timestamp,
|
|
|
|
}
|
|
|
|
node.deletePreprocessData.deleteRecords = append(node.deletePreprocessData.deleteRecords, &r)
|
|
|
|
atomic.AddInt32(&node.deletePreprocessData.count, 1)
|
2020-09-14 11:26:35 +08:00
|
|
|
}
|
2020-09-15 17:41:05 +08:00
|
|
|
node.buffer.validInsertDeleteBuffer[i] = false
|
2020-08-28 18:39:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-07 17:01:46 +08:00
|
|
|
// 2. Remove invalid messages from buffer.
|
2020-09-18 15:44:09 +08:00
|
|
|
tmpInsertOrDeleteBuffer := make([]*msgPb.InsertOrDeleteMsg, 0)
|
2020-09-16 11:07:55 +08:00
|
|
|
for i, isValid := range node.buffer.validInsertDeleteBuffer {
|
|
|
|
if isValid {
|
|
|
|
tmpInsertOrDeleteBuffer = append(tmpInsertOrDeleteBuffer, node.buffer.InsertDeleteBuffer[i])
|
2020-08-28 18:39:00 +08:00
|
|
|
}
|
|
|
|
}
|
2020-09-16 11:07:55 +08:00
|
|
|
node.buffer.InsertDeleteBuffer = tmpInsertOrDeleteBuffer
|
2020-08-28 18:39:00 +08:00
|
|
|
|
2020-09-16 11:07:55 +08:00
|
|
|
// 3. Resize the valid bitmap and set all bits to true.
|
2020-09-15 17:41:05 +08:00
|
|
|
node.buffer.validInsertDeleteBuffer = node.buffer.validInsertDeleteBuffer[:len(node.buffer.InsertDeleteBuffer)]
|
|
|
|
for i := range node.buffer.validInsertDeleteBuffer {
|
|
|
|
node.buffer.validInsertDeleteBuffer[i] = true
|
|
|
|
}
|
|
|
|
|
2020-09-16 11:07:55 +08:00
|
|
|
// 4. Extract messages before readTimeSync from current messageClient.
|
2020-09-07 17:01:46 +08:00
|
|
|
// Move massages after readTimeSync to QueryNodeDataBuffer.
|
|
|
|
// Set valid bitmap to true.
|
|
|
|
for _, msg := range insertDeleteMessages {
|
2020-09-15 17:41:05 +08:00
|
|
|
if msg.Timestamp < tMax {
|
|
|
|
if msg.Op == msgPb.OpType_INSERT {
|
|
|
|
if msg.RowsData == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
node.insertData.insertIDs[msg.SegmentId] = append(node.insertData.insertIDs[msg.SegmentId], msg.Uid)
|
|
|
|
node.insertData.insertTimestamps[msg.SegmentId] = append(node.insertData.insertTimestamps[msg.SegmentId], msg.Timestamp)
|
|
|
|
node.insertData.insertRecords[msg.SegmentId] = append(node.insertData.insertRecords[msg.SegmentId], msg.RowsData.Blob)
|
|
|
|
} else if msg.Op == msgPb.OpType_DELETE {
|
|
|
|
var r = DeleteRecord{
|
|
|
|
entityID: msg.Uid,
|
|
|
|
timestamp: msg.Timestamp,
|
|
|
|
}
|
|
|
|
node.deletePreprocessData.deleteRecords = append(node.deletePreprocessData.deleteRecords, &r)
|
|
|
|
atomic.AddInt32(&node.deletePreprocessData.count, 1)
|
2020-09-07 17:01:46 +08:00
|
|
|
}
|
2020-09-15 17:41:05 +08:00
|
|
|
} else {
|
|
|
|
node.buffer.InsertDeleteBuffer = append(node.buffer.InsertDeleteBuffer, msg)
|
|
|
|
node.buffer.validInsertDeleteBuffer = append(node.buffer.validInsertDeleteBuffer, true)
|
2020-08-28 18:39:00 +08:00
|
|
|
}
|
2020-08-28 17:29:26 +08:00
|
|
|
}
|
|
|
|
|
2020-09-12 16:57:37 +08:00
|
|
|
return msgPb.Status{ErrorCode: msgPb.ErrorCode_SUCCESS}
|
2020-09-09 15:24:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (node *QueryNode) WriterDelete() msgPb.Status {
|
|
|
|
// TODO: set timeout
|
|
|
|
for {
|
2020-09-15 15:53:10 +08:00
|
|
|
if node.deletePreprocessData.count == 0 {
|
|
|
|
return msgPb.Status{ErrorCode: msgPb.ErrorCode_SUCCESS}
|
|
|
|
}
|
|
|
|
node.messageClient.PrepareKey2SegmentMsg()
|
2020-09-09 15:24:07 +08:00
|
|
|
var ids, timestamps, segmentIDs = node.GetKey2Segments()
|
2020-09-15 15:53:10 +08:00
|
|
|
for i := 0; i < len(*ids); i++ {
|
2020-09-12 16:57:37 +08:00
|
|
|
id := (*ids)[i]
|
|
|
|
timestamp := (*timestamps)[i]
|
|
|
|
segmentID := (*segmentIDs)[i]
|
2020-09-09 15:24:07 +08:00
|
|
|
for _, r := range node.deletePreprocessData.deleteRecords {
|
|
|
|
if r.timestamp == timestamp && r.entityID == id {
|
|
|
|
r.segmentID = segmentID
|
2020-09-15 15:53:10 +08:00
|
|
|
atomic.AddInt32(&node.deletePreprocessData.count, -1)
|
2020-09-09 15:24:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (node *QueryNode) PreInsertAndDelete() msgPb.Status {
|
|
|
|
// 1. Do PreInsert
|
|
|
|
for segmentID := range node.insertData.insertRecords {
|
2020-09-07 17:01:46 +08:00
|
|
|
var targetSegment, err = node.GetSegmentBySegmentID(segmentID)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
2020-09-08 10:39:09 +08:00
|
|
|
return msgPb.Status{ErrorCode: 1}
|
2020-09-07 17:01:46 +08:00
|
|
|
}
|
2020-09-09 15:24:07 +08:00
|
|
|
|
|
|
|
var numOfRecords = len(node.insertData.insertRecords[segmentID])
|
|
|
|
var offset = targetSegment.SegmentPreInsert(numOfRecords)
|
|
|
|
node.insertData.insertOffset[segmentID] = offset
|
|
|
|
}
|
|
|
|
|
|
|
|
// 2. Sort delete preprocess data by segment id
|
|
|
|
for _, r := range node.deletePreprocessData.deleteRecords {
|
|
|
|
node.deleteData.deleteIDs[r.segmentID] = append(node.deleteData.deleteIDs[r.segmentID], r.entityID)
|
|
|
|
node.deleteData.deleteTimestamps[r.segmentID] = append(node.deleteData.deleteTimestamps[r.segmentID], r.timestamp)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 3. Do PreDelete
|
|
|
|
for segmentID := range node.deleteData.deleteIDs {
|
2020-09-18 01:53:18 +08:00
|
|
|
if segmentID < 0 {
|
|
|
|
continue
|
|
|
|
}
|
2020-09-09 15:24:07 +08:00
|
|
|
var targetSegment, err = node.GetSegmentBySegmentID(segmentID)
|
2020-09-07 17:01:46 +08:00
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
2020-09-08 10:39:09 +08:00
|
|
|
return msgPb.Status{ErrorCode: 1}
|
2020-09-07 17:01:46 +08:00
|
|
|
}
|
2020-09-09 15:24:07 +08:00
|
|
|
|
|
|
|
var numOfRecords = len(node.deleteData.deleteIDs[segmentID])
|
|
|
|
var offset = targetSegment.SegmentPreDelete(numOfRecords)
|
|
|
|
node.deleteData.deleteOffset[segmentID] = offset
|
2020-08-28 17:29:26 +08:00
|
|
|
}
|
|
|
|
|
2020-09-12 16:57:37 +08:00
|
|
|
return msgPb.Status{ErrorCode: msgPb.ErrorCode_SUCCESS}
|
2020-09-07 17:01:46 +08:00
|
|
|
}
|
2020-08-28 18:39:00 +08:00
|
|
|
|
2020-09-09 15:24:07 +08:00
|
|
|
func (node *QueryNode) DoInsertAndDelete() msgPb.Status {
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
// Do insert
|
|
|
|
for segmentID, records := range node.insertData.insertRecords {
|
|
|
|
wg.Add(1)
|
|
|
|
go node.DoInsert(segmentID, &records, &wg)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do delete
|
|
|
|
for segmentID, deleteIDs := range node.deleteData.deleteIDs {
|
2020-09-18 01:53:18 +08:00
|
|
|
if segmentID < 0 {
|
|
|
|
continue
|
|
|
|
}
|
2020-09-09 15:24:07 +08:00
|
|
|
wg.Add(1)
|
|
|
|
var deleteTimestamps = node.deleteData.deleteTimestamps[segmentID]
|
2020-09-15 15:53:10 +08:00
|
|
|
fmt.Println("Doing delete......")
|
2020-09-09 15:24:07 +08:00
|
|
|
go node.DoDelete(segmentID, &deleteIDs, &deleteTimestamps, &wg)
|
2020-08-28 17:29:26 +08:00
|
|
|
}
|
2020-09-09 15:24:07 +08:00
|
|
|
|
|
|
|
wg.Wait()
|
2020-09-12 16:57:37 +08:00
|
|
|
return msgPb.Status{ErrorCode: msgPb.ErrorCode_SUCCESS}
|
2020-08-28 17:29:26 +08:00
|
|
|
}
|
|
|
|
|
2020-09-09 15:24:07 +08:00
|
|
|
func (node *QueryNode) DoInsert(segmentID int64, records *[][]byte, wg *sync.WaitGroup) msgPb.Status {
|
2020-09-15 17:41:05 +08:00
|
|
|
fmt.Println("Doing insert..., len = ", len(node.insertData.insertIDs[segmentID]))
|
2020-09-09 15:24:07 +08:00
|
|
|
var targetSegment, err = node.GetSegmentBySegmentID(segmentID)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
|
|
|
return msgPb.Status{ErrorCode: 1}
|
2020-09-09 10:28:16 +08:00
|
|
|
}
|
2020-09-09 15:24:07 +08:00
|
|
|
|
|
|
|
ids := node.insertData.insertIDs[segmentID]
|
|
|
|
timestamps := node.insertData.insertTimestamps[segmentID]
|
|
|
|
offsets := node.insertData.insertOffset[segmentID]
|
|
|
|
|
|
|
|
err = targetSegment.SegmentInsert(offsets, &ids, ×tamps, records)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
|
|
|
return msgPb.Status{ErrorCode: 1}
|
|
|
|
}
|
|
|
|
|
|
|
|
wg.Done()
|
2020-09-12 16:57:37 +08:00
|
|
|
return msgPb.Status{ErrorCode: msgPb.ErrorCode_SUCCESS}
|
2020-09-09 15:24:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (node *QueryNode) DoDelete(segmentID int64, deleteIDs *[]int64, deleteTimestamps *[]uint64, wg *sync.WaitGroup) msgPb.Status {
|
|
|
|
var segment, err = node.GetSegmentBySegmentID(segmentID)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
|
|
|
return msgPb.Status{ErrorCode: 1}
|
|
|
|
}
|
|
|
|
|
|
|
|
offset := node.deleteData.deleteOffset[segmentID]
|
|
|
|
|
|
|
|
err = segment.SegmentDelete(offset, deleteIDs, deleteTimestamps)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
|
|
|
return msgPb.Status{ErrorCode: 1}
|
2020-09-09 10:28:16 +08:00
|
|
|
}
|
|
|
|
|
2020-09-09 15:24:07 +08:00
|
|
|
wg.Done()
|
2020-09-12 16:57:37 +08:00
|
|
|
return msgPb.Status{ErrorCode: msgPb.ErrorCode_SUCCESS}
|
2020-09-09 10:28:16 +08:00
|
|
|
}
|
|
|
|
|
2020-09-22 11:21:19 +08:00
|
|
|
func (node *QueryNode) QueryJson2Info(queryJson *string) *QueryInfo {
|
|
|
|
var query QueryInfo
|
|
|
|
var err = json.Unmarshal([]byte(*queryJson), &query)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Unmarshal query json failed")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println(query)
|
|
|
|
return &query
|
|
|
|
}
|
|
|
|
|
2020-09-09 15:24:07 +08:00
|
|
|
func (node *QueryNode) Search(searchMessages []*msgPb.SearchMsg) msgPb.Status {
|
2020-09-16 15:21:10 +08:00
|
|
|
// TODO: use client id to publish results to different clients
|
|
|
|
// var clientId = (*(searchMessages[0])).ClientId
|
2020-08-28 18:39:00 +08:00
|
|
|
|
2020-09-08 10:39:09 +08:00
|
|
|
type SearchResultTmp struct {
|
2020-09-15 15:53:10 +08:00
|
|
|
ResultId int64
|
|
|
|
ResultDistance float32
|
2020-09-08 10:39:09 +08:00
|
|
|
}
|
|
|
|
|
2020-09-07 17:01:46 +08:00
|
|
|
// Traverse all messages in the current messageClient.
|
|
|
|
// TODO: Do not receive batched search requests
|
2020-08-28 17:29:26 +08:00
|
|
|
for _, msg := range searchMessages {
|
2020-09-15 15:53:10 +08:00
|
|
|
var resultsTmp = make([]SearchResultTmp, 0)
|
2020-09-07 17:01:46 +08:00
|
|
|
|
|
|
|
var timestamp = msg.Timestamp
|
|
|
|
var vector = msg.Records
|
2020-09-15 17:41:05 +08:00
|
|
|
// We now only the first Json is valid.
|
|
|
|
var queryJson = msg.Json[0]
|
2020-09-09 15:24:07 +08:00
|
|
|
|
|
|
|
// 1. Timestamp check
|
|
|
|
// TODO: return or wait? Or adding graceful time
|
2020-09-15 17:41:05 +08:00
|
|
|
if timestamp > node.queryNodeTimeSync.SearchTimeSync {
|
|
|
|
fmt.Println("Invalid query time, timestamp = ", timestamp, ", SearchTimeSync = ", node.queryNodeTimeSync.SearchTimeSync)
|
|
|
|
return msgPb.Status{ErrorCode: 1}
|
|
|
|
}
|
2020-09-09 15:24:07 +08:00
|
|
|
|
2020-09-22 11:21:19 +08:00
|
|
|
// 2. Get query information from query json
|
|
|
|
query := node.QueryJson2Info(&queryJson)
|
|
|
|
|
|
|
|
// 3. Do search in all segments
|
|
|
|
for _, segment := range node.SegmentsMap {
|
|
|
|
var res, err = segment.SegmentSearch(query, timestamp, vector)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
|
|
|
return msgPb.Status{ErrorCode: 1}
|
2020-09-08 10:39:09 +08:00
|
|
|
}
|
2020-09-22 11:21:19 +08:00
|
|
|
fmt.Println(res.ResultIds)
|
|
|
|
for i := 0; i < len(res.ResultIds); i++ {
|
|
|
|
resultsTmp = append(resultsTmp, SearchResultTmp{ResultId: res.ResultIds[i], ResultDistance: res.ResultDistances[i]})
|
2020-09-07 17:01:46 +08:00
|
|
|
}
|
2020-08-28 18:39:00 +08:00
|
|
|
}
|
2020-08-28 17:29:26 +08:00
|
|
|
|
2020-09-22 11:21:19 +08:00
|
|
|
// 4. Reduce results
|
2020-09-08 10:39:09 +08:00
|
|
|
sort.Slice(resultsTmp, func(i, j int) bool {
|
|
|
|
return resultsTmp[i].ResultDistance < resultsTmp[j].ResultDistance
|
|
|
|
})
|
2020-09-22 11:21:19 +08:00
|
|
|
resultsTmp = resultsTmp[:query.TopK]
|
2020-09-15 15:53:10 +08:00
|
|
|
var entities = msgPb.Entities{
|
|
|
|
Ids: make([]int64, 0),
|
|
|
|
}
|
|
|
|
var results = msgPb.QueryResult{
|
2020-09-15 17:41:05 +08:00
|
|
|
Status: &msgPb.Status{
|
|
|
|
ErrorCode: 0,
|
|
|
|
},
|
2020-09-15 15:53:10 +08:00
|
|
|
Entities: &entities,
|
|
|
|
Distances: make([]float32, 0),
|
|
|
|
QueryId: msg.Uid,
|
|
|
|
}
|
2020-09-08 10:39:09 +08:00
|
|
|
for _, res := range resultsTmp {
|
2020-09-12 16:57:37 +08:00
|
|
|
results.Entities.Ids = append(results.Entities.Ids, res.ResultId)
|
|
|
|
results.Distances = append(results.Distances, res.ResultDistance)
|
2020-09-15 15:53:10 +08:00
|
|
|
results.Scores = append(results.Distances, float32(0))
|
2020-09-08 10:39:09 +08:00
|
|
|
}
|
2020-08-28 17:29:26 +08:00
|
|
|
|
2020-09-15 15:53:10 +08:00
|
|
|
results.RowNum = int64(len(results.Distances))
|
|
|
|
|
2020-09-22 11:21:19 +08:00
|
|
|
// 5. publish result to pulsar
|
2020-09-16 15:21:10 +08:00
|
|
|
node.PublishSearchResult(&results)
|
2020-09-07 17:01:46 +08:00
|
|
|
}
|
2020-08-28 17:29:26 +08:00
|
|
|
|
2020-09-12 16:57:37 +08:00
|
|
|
return msgPb.Status{ErrorCode: msgPb.ErrorCode_SUCCESS}
|
2020-08-28 17:29:26 +08:00
|
|
|
}
|