mirror of
https://gitee.com/milvus-io/milvus.git
synced 2025-12-07 09:38:39 +08:00
issue: #33285 - implement producing and consuming server of message - implement management operation for streaming node server --------- Signed-off-by: chyezh <chyezh@outlook.com>
138 lines
4.0 KiB
Go
138 lines
4.0 KiB
Go
package adaptor
|
|
|
|
import (
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/milvus-io/milvus/internal/streamingnode/server/wal"
|
|
"github.com/milvus-io/milvus/internal/streamingnode/server/wal/utility"
|
|
"github.com/milvus-io/milvus/pkg/log"
|
|
"github.com/milvus-io/milvus/pkg/streaming/util/message"
|
|
"github.com/milvus-io/milvus/pkg/streaming/util/types"
|
|
"github.com/milvus-io/milvus/pkg/streaming/walimpls"
|
|
"github.com/milvus-io/milvus/pkg/streaming/walimpls/helper"
|
|
)
|
|
|
|
var _ wal.Scanner = (*scannerAdaptorImpl)(nil)
|
|
|
|
// newScannerAdaptor creates a new scanner adaptor.
|
|
func newScannerAdaptor(
|
|
name string,
|
|
l walimpls.WALImpls,
|
|
readOption wal.ReadOption,
|
|
cleanup func(),
|
|
) wal.Scanner {
|
|
s := &scannerAdaptorImpl{
|
|
logger: log.With(zap.String("name", name), zap.String("channel", l.Channel().Name)),
|
|
innerWAL: l,
|
|
readOption: readOption,
|
|
sendingCh: make(chan message.ImmutableMessage, 1),
|
|
reorderBuffer: utility.NewReOrderBuffer(),
|
|
pendingQueue: utility.NewImmutableMessageQueue(),
|
|
cleanup: cleanup,
|
|
ScannerHelper: helper.NewScannerHelper(name),
|
|
}
|
|
go s.executeConsume()
|
|
return s
|
|
}
|
|
|
|
// scannerAdaptorImpl is a wrapper of ScannerImpls to extend it into a Scanner interface.
|
|
type scannerAdaptorImpl struct {
|
|
*helper.ScannerHelper
|
|
logger *log.MLogger
|
|
innerWAL walimpls.WALImpls
|
|
readOption wal.ReadOption
|
|
sendingCh chan message.ImmutableMessage
|
|
reorderBuffer *utility.ReOrderByTimeTickBuffer // only support time tick reorder now.
|
|
pendingQueue *utility.ImmutableMessageQueue //
|
|
cleanup func()
|
|
}
|
|
|
|
// Channel returns the channel assignment info of the wal.
|
|
func (s *scannerAdaptorImpl) Channel() types.PChannelInfo {
|
|
return s.innerWAL.Channel()
|
|
}
|
|
|
|
// Chan returns the channel of message.
|
|
func (s *scannerAdaptorImpl) Chan() <-chan message.ImmutableMessage {
|
|
return s.sendingCh
|
|
}
|
|
|
|
// Close the scanner, release the underlying resources.
|
|
// Return the error same with `Error`
|
|
func (s *scannerAdaptorImpl) Close() error {
|
|
err := s.ScannerHelper.Close()
|
|
if s.cleanup != nil {
|
|
s.cleanup()
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (s *scannerAdaptorImpl) executeConsume() {
|
|
defer close(s.sendingCh)
|
|
|
|
innerScanner, err := s.innerWAL.Read(s.Context(), walimpls.ReadOption{
|
|
Name: s.Name(),
|
|
DeliverPolicy: s.readOption.DeliverPolicy,
|
|
})
|
|
if err != nil {
|
|
s.Finish(err)
|
|
return
|
|
}
|
|
defer innerScanner.Close()
|
|
|
|
for {
|
|
// generate the event channel and do the event loop.
|
|
// TODO: Consume from local cache.
|
|
upstream, sending := s.getEventCh(innerScanner)
|
|
select {
|
|
case <-s.Context().Done():
|
|
s.Finish(err)
|
|
return
|
|
case msg, ok := <-upstream:
|
|
if !ok {
|
|
s.Finish(innerScanner.Error())
|
|
return
|
|
}
|
|
s.handleUpstream(msg)
|
|
case sending <- s.pendingQueue.Next():
|
|
s.pendingQueue.UnsafeAdvance()
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *scannerAdaptorImpl) getEventCh(scanner walimpls.ScannerImpls) (<-chan message.ImmutableMessage, chan<- message.ImmutableMessage) {
|
|
if s.pendingQueue.Len() == 0 {
|
|
// If pending queue is empty,
|
|
// no more message can be sent,
|
|
// we always need to recv message from upstream to avoid starve.
|
|
return scanner.Chan(), nil
|
|
}
|
|
// TODO: configurable pending buffer count.
|
|
// If the pending queue is full, we need to wait until it's consumed to avoid scanner overloading.
|
|
if s.pendingQueue.Len() > 16 {
|
|
return nil, s.sendingCh
|
|
}
|
|
return scanner.Chan(), s.sendingCh
|
|
}
|
|
|
|
func (s *scannerAdaptorImpl) handleUpstream(msg message.ImmutableMessage) {
|
|
if msg.MessageType() == message.MessageTypeTimeTick {
|
|
// If the time tick message incoming,
|
|
// the reorder buffer can be consumed into a pending queue with latest timetick.
|
|
s.pendingQueue.Add(s.reorderBuffer.PopUtilTimeTick(msg.TimeTick()))
|
|
return
|
|
}
|
|
// Filtering the message if needed.
|
|
if s.readOption.MessageFilter != nil && !s.readOption.MessageFilter(msg) {
|
|
return
|
|
}
|
|
// otherwise add message into reorder buffer directly.
|
|
if err := s.reorderBuffer.Push(msg); err != nil {
|
|
s.logger.Warn("failed to push message into reorder buffer",
|
|
zap.Any("msgID", msg.MessageID()),
|
|
zap.Uint64("timetick", msg.TimeTick()),
|
|
zap.String("vchannel", msg.VChannel()),
|
|
zap.Error(err))
|
|
}
|
|
}
|