milvus/internal/datanode/flush_manager.go
congqixia 90f88c6559
Add flush manager structure (#9986)
Signed-off-by: Congqi Xia <congqi.xia@zilliz.com>
2021-10-18 10:38:35 +08:00

176 lines
5.0 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 datanode
import (
"sync"
"github.com/milvus-io/milvus/internal/kv"
"github.com/milvus-io/milvus/internal/proto/internalpb"
)
// flushManager defines a flush manager signature
type flushManager interface {
// notify flush manager insert buffer data
flushBufferData(data *BufferData, segmentID UniqueID, pos *internalpb.MsgPosition)
// notify flush manager del buffer data
flushDelData(data *DelDataBuf, segmentID UniqueID, pos *internalpb.MsgPosition)
}
// segmentFlushPack contains result to save into meta
type segmentFlushPack struct {
segmentID UniqueID
insertLogs []string
statsLogs []string
deltaLogs []string
pos *internalpb.MsgPosition
}
// notifyMetaFunc notify meta to persistent flush result
type notifyMetaFunc func(*segmentFlushPack) error
// taskPostFunc clean up function after single flush task done
type taskPostFunc func()
// make sure implementation
var _ flushManager = (*rendezvousFlushManager)(nil)
type orderFlushQueue struct {
sync.Once
// MsgID => flushTask
working sync.Map
notifyFunc notifyMetaFunc
tailMut sync.Mutex
tailCh chan struct{}
}
// newOrderFlushQueue creates a orderFlushQueue
func newOrderFlushQueue(f notifyMetaFunc) *orderFlushQueue {
return &orderFlushQueue{
notifyFunc: f,
}
}
// init orderFlushQueue use once protect init, init tailCh
func (q *orderFlushQueue) init() {
q.Once.Do(func() {
// new queue acts like tailing task is done
q.tailCh = make(chan struct{})
close(q.tailCh)
})
}
func (q *orderFlushQueue) getFlushTaskRunner(pos *internalpb.MsgPosition) *flushTaskRunner {
actual, loaded := q.working.LoadOrStore(string(pos.MsgID), newFlushTaskRunner())
t := actual.(*flushTaskRunner)
if !loaded {
q.tailMut.Lock()
t.init(q.notifyFunc, func() {
q.working.Delete(string(pos.MsgID))
}, q.tailCh)
t.pos = pos
q.tailCh = t.finishSignal
q.tailMut.Unlock()
}
return t
}
// enqueueInsertBuffer put insert buffer data into queue
func (q *orderFlushQueue) enqueueInsertFlush(task flushInsertTask, pos *internalpb.MsgPosition) {
q.getFlushTaskRunner(pos).runFlushInsert(task)
}
// enqueueDelBuffer put delete buffer data into queue
func (q *orderFlushQueue) enqueueDelFlush(task flushDeleteTask, pos *internalpb.MsgPosition) {
q.getFlushTaskRunner(pos).runFlushDel(task)
}
// rendezvousFlushManager makes sure insert & del buf all flushed
type rendezvousFlushManager struct {
allocatorInterface
kv.BaseKV
// segment id => flush queue
dispatcher sync.Map
notifyFunc notifyMetaFunc
}
// getFlushQueue
func (m *rendezvousFlushManager) getFlushQueue(segmentID UniqueID) *orderFlushQueue {
actual, loaded := m.dispatcher.LoadOrStore(segmentID, newOrderFlushQueue(m.notifyFunc))
// all operation on dispatcher is private, assertion ok guaranteed
queue := actual.(*orderFlushQueue)
if !loaded {
queue.init()
}
return queue
}
// notify flush manager insert buffer data
func (m *rendezvousFlushManager) flushBufferData(data *BufferData, segmentID UniqueID,
pos *internalpb.MsgPosition) {
m.getFlushQueue(segmentID).enqueueInsertFlush(&flushBufferInsertTask{
BaseKV: m.BaseKV,
allocatorInterface: m.allocatorInterface,
data: data,
}, pos)
}
// notify flush manager del buffer data
func (m *rendezvousFlushManager) flushDelData(data *DelDataBuf, segmentID UniqueID,
pos *internalpb.MsgPosition) {
m.getFlushQueue(segmentID).enqueueDelFlush(&flushBufferDeleteTask{
BaseKV: m.BaseKV,
allocatorInterface: m.allocatorInterface,
data: data,
}, pos)
}
type flushBufferInsertTask struct {
kv.BaseKV
allocatorInterface
data *BufferData
}
// flushInsertData implements flushInsertTask
func (t *flushBufferInsertTask) flushInsertData() error {
//TODO implement
return nil
}
type flushBufferDeleteTask struct {
kv.BaseKV
allocatorInterface
data *DelDataBuf
}
// flushDeleteData implements flushDeleteTask
func (t *flushBufferDeleteTask) flushDeleteData() error {
//TODO implement
return nil
}
// NewRendezvousFlushManager create rendezvousFlushManager with provided allocator and kv
func NewRendezvousFlushManager(allocator allocatorInterface, kv kv.BaseKV, f notifyMetaFunc) *rendezvousFlushManager {
return &rendezvousFlushManager{
allocatorInterface: allocator,
BaseKV: kv,
notifyFunc: f,
}
}