2021-04-19 11:30:19 +08:00
|
|
|
// Copyright (C) 2019-2020 Zilliz. All rights reserved.
|
|
|
|
//
|
|
|
|
// Licensed 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.
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
package msgstream
|
2021-03-26 20:10:11 +08:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
|
|
|
"path/filepath"
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/golang/protobuf/proto"
|
2021-04-22 14:45:57 +08:00
|
|
|
"github.com/milvus-io/milvus/internal/log"
|
|
|
|
"github.com/milvus-io/milvus/internal/proto/commonpb"
|
|
|
|
"github.com/milvus-io/milvus/internal/proto/internalpb"
|
|
|
|
"github.com/milvus-io/milvus/internal/util/mqclient"
|
|
|
|
"github.com/milvus-io/milvus/internal/util/trace"
|
2021-03-30 10:52:42 +08:00
|
|
|
"github.com/opentracing/opentracing-go"
|
2021-03-26 20:10:11 +08:00
|
|
|
"go.uber.org/zap"
|
|
|
|
)
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
type mqMsgStream struct {
|
2021-03-26 20:10:11 +08:00
|
|
|
ctx context.Context
|
2021-04-02 13:48:25 +08:00
|
|
|
client mqclient.Client
|
|
|
|
producers map[string]mqclient.Producer
|
2021-03-26 20:10:11 +08:00
|
|
|
producerChannels []string
|
2021-04-02 13:48:25 +08:00
|
|
|
consumers map[string]mqclient.Consumer
|
2021-03-26 20:10:11 +08:00
|
|
|
consumerChannels []string
|
|
|
|
repackFunc RepackFunc
|
|
|
|
unmarshal UnmarshalDispatcher
|
|
|
|
receiveBuf chan *MsgPack
|
|
|
|
wait *sync.WaitGroup
|
|
|
|
streamCancel func()
|
|
|
|
bufSize int64
|
|
|
|
producerLock *sync.Mutex
|
|
|
|
consumerLock *sync.Mutex
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
func NewMqMsgStream(ctx context.Context,
|
2021-03-26 20:10:11 +08:00
|
|
|
receiveBufSize int64,
|
|
|
|
bufSize int64,
|
2021-04-02 13:48:25 +08:00
|
|
|
client mqclient.Client,
|
|
|
|
unmarshal UnmarshalDispatcher) (*mqMsgStream, error) {
|
2021-03-26 20:10:11 +08:00
|
|
|
|
|
|
|
streamCtx, streamCancel := context.WithCancel(ctx)
|
2021-04-02 13:48:25 +08:00
|
|
|
producers := make(map[string]mqclient.Producer)
|
|
|
|
consumers := make(map[string]mqclient.Consumer)
|
2021-03-26 20:10:11 +08:00
|
|
|
producerChannels := make([]string, 0)
|
|
|
|
consumerChannels := make([]string, 0)
|
|
|
|
receiveBuf := make(chan *MsgPack, receiveBufSize)
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
stream := &mqMsgStream{
|
2021-03-26 20:10:11 +08:00
|
|
|
ctx: streamCtx,
|
|
|
|
client: client,
|
|
|
|
producers: producers,
|
|
|
|
producerChannels: producerChannels,
|
|
|
|
consumers: consumers,
|
|
|
|
consumerChannels: consumerChannels,
|
|
|
|
unmarshal: unmarshal,
|
|
|
|
bufSize: bufSize,
|
|
|
|
receiveBuf: receiveBuf,
|
|
|
|
streamCancel: streamCancel,
|
|
|
|
producerLock: &sync.Mutex{},
|
|
|
|
consumerLock: &sync.Mutex{},
|
|
|
|
wait: &sync.WaitGroup{},
|
|
|
|
}
|
|
|
|
|
|
|
|
return stream, nil
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
func (ms *mqMsgStream) AsProducer(channels []string) {
|
2021-03-26 20:10:11 +08:00
|
|
|
for _, channel := range channels {
|
|
|
|
fn := func() error {
|
2021-04-02 10:01:11 +08:00
|
|
|
pp, err := ms.client.CreateProducer(mqclient.ProducerOptions{Topic: channel})
|
2021-03-26 20:10:11 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if pp == nil {
|
|
|
|
return errors.New("Producer is nil")
|
|
|
|
}
|
|
|
|
|
|
|
|
ms.producerLock.Lock()
|
|
|
|
ms.producers[channel] = pp
|
|
|
|
ms.producerChannels = append(ms.producerChannels, channel)
|
|
|
|
ms.producerLock.Unlock()
|
|
|
|
return nil
|
|
|
|
}
|
2021-04-02 13:48:25 +08:00
|
|
|
err := Retry(20, time.Millisecond*200, fn)
|
2021-03-26 20:10:11 +08:00
|
|
|
if err != nil {
|
|
|
|
errMsg := "Failed to create producer " + channel + ", error = " + err.Error()
|
|
|
|
panic(errMsg)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-27 10:38:37 +08:00
|
|
|
func (ms *mqMsgStream) AsConsumer(channels []string, subName string) {
|
2021-03-26 20:10:11 +08:00
|
|
|
for _, channel := range channels {
|
|
|
|
if _, ok := ms.consumers[channel]; ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
fn := func() error {
|
2021-04-02 10:01:11 +08:00
|
|
|
receiveChannel := make(chan mqclient.ConsumerMessage, ms.bufSize)
|
|
|
|
pc, err := ms.client.Subscribe(mqclient.ConsumerOptions{
|
2021-03-26 20:10:11 +08:00
|
|
|
Topic: channel,
|
|
|
|
SubscriptionName: subName,
|
2021-04-02 10:01:11 +08:00
|
|
|
Type: mqclient.KeyShared,
|
|
|
|
SubscriptionInitialPosition: mqclient.SubscriptionPositionEarliest,
|
2021-03-26 20:10:11 +08:00
|
|
|
MessageChannel: receiveChannel,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if pc == nil {
|
|
|
|
return errors.New("Consumer is nil")
|
|
|
|
}
|
|
|
|
|
|
|
|
ms.consumers[channel] = pc
|
|
|
|
ms.consumerChannels = append(ms.consumerChannels, channel)
|
|
|
|
ms.wait.Add(1)
|
|
|
|
go ms.receiveMsg(pc)
|
|
|
|
return nil
|
|
|
|
}
|
2021-04-02 13:48:25 +08:00
|
|
|
err := Retry(20, time.Millisecond*200, fn)
|
2021-03-26 20:10:11 +08:00
|
|
|
if err != nil {
|
|
|
|
errMsg := "Failed to create consumer " + channel + ", error = " + err.Error()
|
|
|
|
panic(errMsg)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
func (ms *mqMsgStream) SetRepackFunc(repackFunc RepackFunc) {
|
2021-03-26 20:10:11 +08:00
|
|
|
ms.repackFunc = repackFunc
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
func (ms *mqMsgStream) Start() {
|
2021-03-26 20:10:11 +08:00
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
func (ms *mqMsgStream) Close() {
|
2021-03-26 20:10:11 +08:00
|
|
|
ms.streamCancel()
|
|
|
|
ms.wait.Wait()
|
|
|
|
|
|
|
|
for _, producer := range ms.producers {
|
|
|
|
if producer != nil {
|
|
|
|
producer.Close()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, consumer := range ms.consumers {
|
|
|
|
if consumer != nil {
|
|
|
|
consumer.Close()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ms.client != nil {
|
|
|
|
ms.client.Close()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-24 16:30:09 +08:00
|
|
|
func (ms *mqMsgStream) ComputeProduceChannelIndexes(tsMsgs []TsMsg) [][]int32 {
|
2021-03-26 20:10:11 +08:00
|
|
|
if len(tsMsgs) <= 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
reBucketValues := make([][]int32, len(tsMsgs))
|
2021-05-24 16:30:09 +08:00
|
|
|
channelNum := uint32(len(ms.producerChannels))
|
2021-05-25 19:53:15 +08:00
|
|
|
|
2021-05-24 16:30:09 +08:00
|
|
|
if channelNum == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
2021-03-26 20:10:11 +08:00
|
|
|
for idx, tsMsg := range tsMsgs {
|
|
|
|
hashValues := tsMsg.HashKeys()
|
|
|
|
bucketValues := make([]int32, len(hashValues))
|
|
|
|
for index, hashValue := range hashValues {
|
2021-05-24 16:30:09 +08:00
|
|
|
bucketValues[index] = int32(hashValue % channelNum)
|
2021-03-26 20:10:11 +08:00
|
|
|
}
|
|
|
|
reBucketValues[idx] = bucketValues
|
|
|
|
}
|
2021-05-24 16:30:09 +08:00
|
|
|
return reBucketValues
|
|
|
|
}
|
2021-03-26 20:10:11 +08:00
|
|
|
|
2021-05-25 19:53:15 +08:00
|
|
|
func (ms *mqMsgStream) GetProduceChannels() []string {
|
|
|
|
return ms.producerChannels
|
|
|
|
}
|
|
|
|
|
2021-05-24 16:30:09 +08:00
|
|
|
func (ms *mqMsgStream) Produce(msgPack *MsgPack) error {
|
2021-05-27 10:38:37 +08:00
|
|
|
if msgPack == nil || len(msgPack.Msgs) <= 0 {
|
2021-05-24 16:30:09 +08:00
|
|
|
log.Debug("Warning: Receive empty msgPack")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if len(ms.producers) <= 0 {
|
|
|
|
return errors.New("nil producer in msg stream")
|
|
|
|
}
|
2021-05-27 10:38:37 +08:00
|
|
|
tsMsgs := msgPack.Msgs
|
2021-05-24 16:30:09 +08:00
|
|
|
reBucketValues := ms.ComputeProduceChannelIndexes(msgPack.Msgs)
|
2021-03-26 20:10:11 +08:00
|
|
|
var result map[int32]*MsgPack
|
|
|
|
var err error
|
|
|
|
if ms.repackFunc != nil {
|
|
|
|
result, err = ms.repackFunc(tsMsgs, reBucketValues)
|
|
|
|
} else {
|
|
|
|
msgType := (tsMsgs[0]).Type()
|
|
|
|
switch msgType {
|
|
|
|
case commonpb.MsgType_Insert:
|
2021-04-02 13:48:25 +08:00
|
|
|
result, err = InsertRepackFunc(tsMsgs, reBucketValues)
|
2021-03-26 20:10:11 +08:00
|
|
|
case commonpb.MsgType_Delete:
|
2021-04-02 13:48:25 +08:00
|
|
|
result, err = DeleteRepackFunc(tsMsgs, reBucketValues)
|
2021-03-26 20:10:11 +08:00
|
|
|
default:
|
2021-04-02 13:48:25 +08:00
|
|
|
result, err = DefaultRepackFunc(tsMsgs, reBucketValues)
|
2021-03-26 20:10:11 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
for k, v := range result {
|
|
|
|
channel := ms.producerChannels[k]
|
|
|
|
for i := 0; i < len(v.Msgs); i++ {
|
2021-04-02 13:48:25 +08:00
|
|
|
sp, spanCtx := MsgSpanFromCtx(v.Msgs[i].TraceCtx(), v.Msgs[i])
|
2021-03-30 10:52:42 +08:00
|
|
|
|
2021-03-26 20:10:11 +08:00
|
|
|
mb, err := v.Msgs[i].Marshal(v.Msgs[i])
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
m, err := ConvertToByteArray(mb)
|
2021-03-26 20:10:11 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-04-02 10:01:11 +08:00
|
|
|
msg := &mqclient.ProducerMessage{Payload: m, Properties: map[string]string{}}
|
2021-03-26 20:10:11 +08:00
|
|
|
|
|
|
|
trace.InjectContextToPulsarMsgProperties(sp.Context(), msg.Properties)
|
|
|
|
|
|
|
|
if err := ms.producers[channel].Send(
|
|
|
|
spanCtx,
|
|
|
|
msg,
|
|
|
|
); err != nil {
|
|
|
|
trace.LogError(sp, err)
|
|
|
|
sp.Finish()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
sp.Finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
func (ms *mqMsgStream) Broadcast(msgPack *MsgPack) error {
|
2021-05-27 10:38:37 +08:00
|
|
|
if msgPack == nil || len(msgPack.Msgs) <= 0 {
|
|
|
|
log.Debug("Warning: Receive empty msgPack")
|
|
|
|
return nil
|
|
|
|
}
|
2021-03-26 20:10:11 +08:00
|
|
|
for _, v := range msgPack.Msgs {
|
2021-04-02 13:48:25 +08:00
|
|
|
sp, spanCtx := MsgSpanFromCtx(v.TraceCtx(), v)
|
2021-03-30 10:52:42 +08:00
|
|
|
|
2021-03-26 20:10:11 +08:00
|
|
|
mb, err := v.Marshal(v)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
m, err := ConvertToByteArray(mb)
|
2021-03-26 20:10:11 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-04-02 10:01:11 +08:00
|
|
|
msg := &mqclient.ProducerMessage{Payload: m, Properties: map[string]string{}}
|
2021-03-26 20:10:11 +08:00
|
|
|
|
|
|
|
trace.InjectContextToPulsarMsgProperties(sp.Context(), msg.Properties)
|
|
|
|
|
|
|
|
ms.producerLock.Lock()
|
|
|
|
for _, producer := range ms.producers {
|
|
|
|
if err := producer.Send(
|
|
|
|
spanCtx,
|
|
|
|
msg,
|
|
|
|
); err != nil {
|
|
|
|
trace.LogError(sp, err)
|
|
|
|
sp.Finish()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ms.producerLock.Unlock()
|
|
|
|
sp.Finish()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
func (ms *mqMsgStream) Consume() *MsgPack {
|
2021-03-26 20:10:11 +08:00
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case cm, ok := <-ms.receiveBuf:
|
|
|
|
if !ok {
|
|
|
|
log.Debug("buf chan closed")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return cm
|
|
|
|
case <-ms.ctx.Done():
|
|
|
|
//log.Debug("context closed")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
func (ms *mqMsgStream) receiveMsg(consumer mqclient.Consumer) {
|
2021-03-26 20:10:11 +08:00
|
|
|
defer ms.wait.Done()
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ms.ctx.Done():
|
|
|
|
return
|
|
|
|
case msg, ok := <-consumer.Chan():
|
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
consumer.Ack(msg)
|
|
|
|
headerMsg := commonpb.MsgHeader{}
|
|
|
|
err := proto.Unmarshal(msg.Payload(), &headerMsg)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("Failed to unmarshal message header", zap.Error(err))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
tsMsg, err := ms.unmarshal.Unmarshal(msg.Payload(), headerMsg.Base.MsgType)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("Failed to unmarshal tsMsg", zap.Error(err))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
sp, ok := ExtractFromPulsarMsgProperties(tsMsg, msg.Properties())
|
2021-03-30 10:52:42 +08:00
|
|
|
if ok {
|
|
|
|
tsMsg.SetTraceCtx(opentracing.ContextWithSpan(context.Background(), sp))
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
tsMsg.SetPosition(&MsgPosition{
|
2021-03-26 20:10:11 +08:00
|
|
|
ChannelName: filepath.Base(msg.Topic()),
|
|
|
|
//FIXME
|
2021-03-27 09:46:54 +08:00
|
|
|
MsgID: msg.ID().Serialize(),
|
2021-03-26 20:10:11 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
msgPack := MsgPack{Msgs: []TsMsg{tsMsg}}
|
|
|
|
ms.receiveBuf <- &msgPack
|
|
|
|
|
|
|
|
sp.Finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
func (ms *mqMsgStream) Chan() <-chan *MsgPack {
|
2021-03-26 20:10:11 +08:00
|
|
|
return ms.receiveBuf
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
func (ms *mqMsgStream) Seek(mp *internalpb.MsgPosition) error {
|
2021-03-26 20:10:11 +08:00
|
|
|
if _, ok := ms.consumers[mp.ChannelName]; ok {
|
|
|
|
consumer := ms.consumers[mp.ChannelName]
|
2021-03-27 09:46:54 +08:00
|
|
|
messageID, err := ms.client.BytesToMsgID(mp.MsgID)
|
2021-03-26 20:10:11 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = consumer.Seek(messageID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return errors.New("msgStream seek fail")
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
type MqTtMsgStream struct {
|
|
|
|
mqMsgStream
|
|
|
|
unsolvedBuf map[mqclient.Consumer][]TsMsg
|
|
|
|
msgPositions map[mqclient.Consumer]*internalpb.MsgPosition
|
2021-03-26 20:10:11 +08:00
|
|
|
unsolvedMutex *sync.Mutex
|
|
|
|
lastTimeStamp Timestamp
|
|
|
|
syncConsumer chan int
|
2021-04-02 13:48:25 +08:00
|
|
|
stopConsumeChan map[mqclient.Consumer]chan bool
|
2021-03-26 20:10:11 +08:00
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
func NewMqTtMsgStream(ctx context.Context,
|
2021-03-26 20:10:11 +08:00
|
|
|
receiveBufSize int64,
|
|
|
|
bufSize int64,
|
2021-04-02 13:48:25 +08:00
|
|
|
client mqclient.Client,
|
|
|
|
unmarshal UnmarshalDispatcher) (*MqTtMsgStream, error) {
|
|
|
|
msgStream, err := NewMqMsgStream(ctx, receiveBufSize, bufSize, client, unmarshal)
|
2021-03-26 20:10:11 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-04-02 13:48:25 +08:00
|
|
|
unsolvedBuf := make(map[mqclient.Consumer][]TsMsg)
|
|
|
|
stopChannel := make(map[mqclient.Consumer]chan bool)
|
|
|
|
msgPositions := make(map[mqclient.Consumer]*internalpb.MsgPosition)
|
2021-03-26 20:10:11 +08:00
|
|
|
syncConsumer := make(chan int, 1)
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
return &MqTtMsgStream{
|
|
|
|
mqMsgStream: *msgStream,
|
2021-03-26 20:10:11 +08:00
|
|
|
unsolvedBuf: unsolvedBuf,
|
|
|
|
msgPositions: msgPositions,
|
|
|
|
unsolvedMutex: &sync.Mutex{},
|
|
|
|
syncConsumer: syncConsumer,
|
|
|
|
stopConsumeChan: stopChannel,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
func (ms *MqTtMsgStream) addConsumer(consumer mqclient.Consumer, channel string) {
|
2021-03-26 20:10:11 +08:00
|
|
|
if len(ms.consumers) == 0 {
|
|
|
|
ms.syncConsumer <- 1
|
|
|
|
}
|
|
|
|
ms.consumers[channel] = consumer
|
|
|
|
ms.unsolvedBuf[consumer] = make([]TsMsg, 0)
|
|
|
|
ms.consumerChannels = append(ms.consumerChannels, channel)
|
|
|
|
ms.msgPositions[consumer] = &internalpb.MsgPosition{
|
|
|
|
ChannelName: channel,
|
2021-03-27 09:46:54 +08:00
|
|
|
MsgID: make([]byte, 0),
|
2021-03-26 20:10:11 +08:00
|
|
|
Timestamp: ms.lastTimeStamp,
|
|
|
|
}
|
|
|
|
stopConsumeChan := make(chan bool)
|
|
|
|
ms.stopConsumeChan[consumer] = stopConsumeChan
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
func (ms *MqTtMsgStream) AsConsumer(channels []string,
|
2021-03-26 20:10:11 +08:00
|
|
|
subName string) {
|
|
|
|
for _, channel := range channels {
|
|
|
|
if _, ok := ms.consumers[channel]; ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
fn := func() error {
|
2021-04-02 10:01:11 +08:00
|
|
|
receiveChannel := make(chan mqclient.ConsumerMessage, ms.bufSize)
|
|
|
|
pc, err := ms.client.Subscribe(mqclient.ConsumerOptions{
|
2021-03-26 20:10:11 +08:00
|
|
|
Topic: channel,
|
|
|
|
SubscriptionName: subName,
|
2021-04-02 10:01:11 +08:00
|
|
|
Type: mqclient.KeyShared,
|
|
|
|
SubscriptionInitialPosition: mqclient.SubscriptionPositionEarliest,
|
2021-03-26 20:10:11 +08:00
|
|
|
MessageChannel: receiveChannel,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if pc == nil {
|
|
|
|
return errors.New("Consumer is nil")
|
|
|
|
}
|
|
|
|
|
|
|
|
ms.consumerLock.Lock()
|
|
|
|
ms.addConsumer(pc, channel)
|
|
|
|
ms.consumerLock.Unlock()
|
|
|
|
return nil
|
|
|
|
}
|
2021-04-02 13:48:25 +08:00
|
|
|
err := Retry(10, time.Millisecond*200, fn)
|
2021-03-26 20:10:11 +08:00
|
|
|
if err != nil {
|
|
|
|
errMsg := "Failed to create consumer " + channel + ", error = " + err.Error()
|
|
|
|
panic(errMsg)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
func (ms *MqTtMsgStream) Start() {
|
2021-03-26 20:10:11 +08:00
|
|
|
if ms.consumers != nil {
|
|
|
|
ms.wait.Add(1)
|
|
|
|
go ms.bufMsgPackToChannel()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
func (ms *MqTtMsgStream) Close() {
|
2021-03-26 20:10:11 +08:00
|
|
|
ms.streamCancel()
|
|
|
|
close(ms.syncConsumer)
|
|
|
|
ms.wait.Wait()
|
|
|
|
|
|
|
|
for _, producer := range ms.producers {
|
|
|
|
if producer != nil {
|
|
|
|
producer.Close()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, consumer := range ms.consumers {
|
|
|
|
if consumer != nil {
|
|
|
|
consumer.Close()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ms.client != nil {
|
|
|
|
ms.client.Close()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
func (ms *MqTtMsgStream) bufMsgPackToChannel() {
|
2021-03-26 20:10:11 +08:00
|
|
|
defer ms.wait.Done()
|
2021-04-02 13:48:25 +08:00
|
|
|
isChannelReady := make(map[mqclient.Consumer]bool)
|
|
|
|
eofMsgTimeStamp := make(map[mqclient.Consumer]Timestamp)
|
2021-03-26 20:10:11 +08:00
|
|
|
|
|
|
|
if _, ok := <-ms.syncConsumer; !ok {
|
|
|
|
log.Debug("consumer closed!")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ms.ctx.Done():
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
wg := sync.WaitGroup{}
|
|
|
|
findMapMutex := sync.RWMutex{}
|
|
|
|
ms.consumerLock.Lock()
|
|
|
|
for _, consumer := range ms.consumers {
|
|
|
|
if isChannelReady[consumer] {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
wg.Add(1)
|
|
|
|
go ms.findTimeTick(consumer, eofMsgTimeStamp, &wg, &findMapMutex)
|
|
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
timeStamp, ok := checkTimeTickMsg(eofMsgTimeStamp, isChannelReady, &findMapMutex)
|
|
|
|
if !ok || timeStamp <= ms.lastTimeStamp {
|
|
|
|
//log.Printf("All timeTick's timestamps are inconsistent")
|
2021-05-27 10:38:37 +08:00
|
|
|
ms.consumerLock.Unlock()
|
2021-03-26 20:10:11 +08:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
timeTickBuf := make([]TsMsg, 0)
|
|
|
|
startMsgPosition := make([]*internalpb.MsgPosition, 0)
|
|
|
|
endMsgPositions := make([]*internalpb.MsgPosition, 0)
|
|
|
|
ms.unsolvedMutex.Lock()
|
|
|
|
for consumer, msgs := range ms.unsolvedBuf {
|
|
|
|
if len(msgs) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
tempBuffer := make([]TsMsg, 0)
|
|
|
|
var timeTickMsg TsMsg
|
|
|
|
for _, v := range msgs {
|
|
|
|
if v.Type() == commonpb.MsgType_TimeTick {
|
|
|
|
timeTickMsg = v
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if v.EndTs() <= timeStamp {
|
|
|
|
timeTickBuf = append(timeTickBuf, v)
|
|
|
|
} else {
|
|
|
|
tempBuffer = append(tempBuffer, v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ms.unsolvedBuf[consumer] = tempBuffer
|
|
|
|
|
|
|
|
startMsgPosition = append(startMsgPosition, ms.msgPositions[consumer])
|
|
|
|
var newPos *internalpb.MsgPosition
|
|
|
|
if len(tempBuffer) > 0 {
|
|
|
|
newPos = &internalpb.MsgPosition{
|
|
|
|
ChannelName: tempBuffer[0].Position().ChannelName,
|
|
|
|
MsgID: tempBuffer[0].Position().MsgID,
|
|
|
|
Timestamp: timeStamp,
|
2021-05-28 10:26:30 +08:00
|
|
|
MsgGroup: consumer.Subscription(),
|
2021-03-26 20:10:11 +08:00
|
|
|
}
|
|
|
|
endMsgPositions = append(endMsgPositions, newPos)
|
|
|
|
} else {
|
|
|
|
newPos = &internalpb.MsgPosition{
|
|
|
|
ChannelName: timeTickMsg.Position().ChannelName,
|
|
|
|
MsgID: timeTickMsg.Position().MsgID,
|
|
|
|
Timestamp: timeStamp,
|
2021-05-28 10:26:30 +08:00
|
|
|
MsgGroup: consumer.Subscription(),
|
2021-03-26 20:10:11 +08:00
|
|
|
}
|
|
|
|
endMsgPositions = append(endMsgPositions, newPos)
|
|
|
|
}
|
|
|
|
ms.msgPositions[consumer] = newPos
|
|
|
|
}
|
|
|
|
ms.unsolvedMutex.Unlock()
|
2021-05-27 10:38:37 +08:00
|
|
|
ms.consumerLock.Unlock()
|
2021-03-26 20:10:11 +08:00
|
|
|
|
|
|
|
msgPack := MsgPack{
|
|
|
|
BeginTs: ms.lastTimeStamp,
|
|
|
|
EndTs: timeStamp,
|
|
|
|
Msgs: timeTickBuf,
|
|
|
|
StartPositions: startMsgPosition,
|
|
|
|
EndPositions: endMsgPositions,
|
|
|
|
}
|
|
|
|
|
|
|
|
ms.receiveBuf <- &msgPack
|
|
|
|
ms.lastTimeStamp = timeStamp
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
func (ms *MqTtMsgStream) findTimeTick(consumer mqclient.Consumer,
|
|
|
|
eofMsgMap map[mqclient.Consumer]Timestamp,
|
2021-03-26 20:10:11 +08:00
|
|
|
wg *sync.WaitGroup,
|
|
|
|
findMapMutex *sync.RWMutex) {
|
|
|
|
defer wg.Done()
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ms.ctx.Done():
|
|
|
|
return
|
|
|
|
case msg, ok := <-consumer.Chan():
|
|
|
|
if !ok {
|
|
|
|
log.Debug("consumer closed!")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
consumer.Ack(msg)
|
|
|
|
|
|
|
|
headerMsg := commonpb.MsgHeader{}
|
|
|
|
err := proto.Unmarshal(msg.Payload(), &headerMsg)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("Failed to unmarshal message header", zap.Error(err))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
tsMsg, err := ms.unmarshal.Unmarshal(msg.Payload(), headerMsg.Base.MsgType)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("Failed to unmarshal tsMsg", zap.Error(err))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// set msg info to tsMsg
|
2021-04-02 13:48:25 +08:00
|
|
|
tsMsg.SetPosition(&MsgPosition{
|
2021-03-26 20:10:11 +08:00
|
|
|
ChannelName: filepath.Base(msg.Topic()),
|
2021-03-27 09:46:54 +08:00
|
|
|
MsgID: msg.ID().Serialize(),
|
2021-03-26 20:10:11 +08:00
|
|
|
})
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
sp, ok := ExtractFromPulsarMsgProperties(tsMsg, msg.Properties())
|
2021-03-26 20:10:11 +08:00
|
|
|
if ok {
|
2021-03-30 10:52:42 +08:00
|
|
|
tsMsg.SetTraceCtx(opentracing.ContextWithSpan(context.Background(), sp))
|
2021-03-26 20:10:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ms.unsolvedMutex.Lock()
|
|
|
|
ms.unsolvedBuf[consumer] = append(ms.unsolvedBuf[consumer], tsMsg)
|
|
|
|
ms.unsolvedMutex.Unlock()
|
|
|
|
|
|
|
|
if headerMsg.Base.MsgType == commonpb.MsgType_TimeTick {
|
|
|
|
findMapMutex.Lock()
|
|
|
|
eofMsgMap[consumer] = tsMsg.(*TimeTickMsg).Base.Timestamp
|
|
|
|
findMapMutex.Unlock()
|
|
|
|
sp.Finish()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
sp.Finish()
|
|
|
|
case <-ms.stopConsumeChan[consumer]:
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
func checkTimeTickMsg(msg map[mqclient.Consumer]Timestamp,
|
|
|
|
isChannelReady map[mqclient.Consumer]bool,
|
2021-03-26 20:10:11 +08:00
|
|
|
mu *sync.RWMutex) (Timestamp, bool) {
|
|
|
|
checkMap := make(map[Timestamp]int)
|
|
|
|
var maxTime Timestamp = 0
|
|
|
|
for _, v := range msg {
|
|
|
|
checkMap[v]++
|
|
|
|
if v > maxTime {
|
|
|
|
maxTime = v
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(checkMap) <= 1 {
|
|
|
|
for consumer := range msg {
|
|
|
|
isChannelReady[consumer] = false
|
|
|
|
}
|
|
|
|
return maxTime, true
|
|
|
|
}
|
|
|
|
for consumer := range msg {
|
|
|
|
mu.RLock()
|
|
|
|
v := msg[consumer]
|
|
|
|
mu.RUnlock()
|
|
|
|
if v != maxTime {
|
|
|
|
isChannelReady[consumer] = false
|
|
|
|
} else {
|
|
|
|
isChannelReady[consumer] = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0, false
|
|
|
|
}
|
|
|
|
|
2021-04-02 13:48:25 +08:00
|
|
|
func (ms *MqTtMsgStream) Seek(mp *internalpb.MsgPosition) error {
|
2021-03-26 20:10:11 +08:00
|
|
|
if len(mp.MsgID) == 0 {
|
|
|
|
return errors.New("when msgID's length equal to 0, please use AsConsumer interface")
|
|
|
|
}
|
2021-04-02 13:48:25 +08:00
|
|
|
var consumer mqclient.Consumer
|
2021-03-26 20:10:11 +08:00
|
|
|
var err error
|
|
|
|
var hasWatched bool
|
|
|
|
seekChannel := mp.ChannelName
|
|
|
|
subName := mp.MsgGroup
|
|
|
|
ms.consumerLock.Lock()
|
|
|
|
defer ms.consumerLock.Unlock()
|
|
|
|
consumer, hasWatched = ms.consumers[seekChannel]
|
|
|
|
|
|
|
|
if hasWatched {
|
2021-04-15 15:15:46 +08:00
|
|
|
return errors.New("the channel should has not been subscribed")
|
2021-03-26 20:10:11 +08:00
|
|
|
}
|
|
|
|
|
2021-03-30 13:53:49 +08:00
|
|
|
fn := func() error {
|
2021-04-02 10:01:11 +08:00
|
|
|
receiveChannel := make(chan mqclient.ConsumerMessage, ms.bufSize)
|
|
|
|
consumer, err = ms.client.Subscribe(mqclient.ConsumerOptions{
|
2021-03-30 13:53:49 +08:00
|
|
|
Topic: seekChannel,
|
|
|
|
SubscriptionName: subName,
|
2021-04-02 10:01:11 +08:00
|
|
|
SubscriptionInitialPosition: mqclient.SubscriptionPositionEarliest,
|
|
|
|
Type: mqclient.KeyShared,
|
2021-03-30 13:53:49 +08:00
|
|
|
MessageChannel: receiveChannel,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if consumer == nil {
|
|
|
|
err = errors.New("consumer is nil")
|
|
|
|
log.Debug("subscribe error", zap.String("error = ", err.Error()))
|
|
|
|
return err
|
|
|
|
}
|
2021-03-26 20:10:11 +08:00
|
|
|
|
2021-03-30 13:53:49 +08:00
|
|
|
seekMsgID, err := ms.client.BytesToMsgID(mp.MsgID)
|
|
|
|
if err != nil {
|
|
|
|
log.Debug("convert messageID error", zap.String("error = ", err.Error()))
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = consumer.Seek(seekMsgID)
|
|
|
|
if err != nil {
|
|
|
|
log.Debug("seek error ", zap.String("error = ", err.Error()))
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2021-04-02 13:48:25 +08:00
|
|
|
err = Retry(20, time.Millisecond*200, fn)
|
2021-03-26 20:10:11 +08:00
|
|
|
if err != nil {
|
2021-03-30 13:53:49 +08:00
|
|
|
errMsg := "Failed to seek, error = " + err.Error()
|
|
|
|
panic(errMsg)
|
2021-03-26 20:10:11 +08:00
|
|
|
}
|
|
|
|
ms.addConsumer(consumer, seekChannel)
|
|
|
|
|
|
|
|
//TODO: May cause problem
|
2021-05-27 10:38:37 +08:00
|
|
|
//if len(consumer.Chan()) == 0 {
|
|
|
|
// return nil
|
|
|
|
//}
|
2021-03-26 20:10:11 +08:00
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ms.ctx.Done():
|
|
|
|
return nil
|
|
|
|
case msg, ok := <-consumer.Chan():
|
|
|
|
if !ok {
|
|
|
|
return errors.New("consumer closed")
|
|
|
|
}
|
|
|
|
consumer.Ack(msg)
|
|
|
|
|
|
|
|
headerMsg := commonpb.MsgHeader{}
|
|
|
|
err := proto.Unmarshal(msg.Payload(), &headerMsg)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("Failed to unmarshal message header", zap.Error(err))
|
|
|
|
}
|
|
|
|
tsMsg, err := ms.unmarshal.Unmarshal(msg.Payload(), headerMsg.Base.MsgType)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("Failed to unmarshal tsMsg", zap.Error(err))
|
|
|
|
}
|
|
|
|
if tsMsg.Type() == commonpb.MsgType_TimeTick {
|
|
|
|
if tsMsg.BeginTs() >= mp.Timestamp {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if tsMsg.BeginTs() > mp.Timestamp {
|
2021-04-02 13:48:25 +08:00
|
|
|
tsMsg.SetPosition(&MsgPosition{
|
2021-03-26 20:10:11 +08:00
|
|
|
ChannelName: filepath.Base(msg.Topic()),
|
2021-03-27 09:46:54 +08:00
|
|
|
MsgID: msg.ID().Serialize(),
|
2021-03-26 20:10:11 +08:00
|
|
|
})
|
|
|
|
ms.unsolvedBuf[consumer] = append(ms.unsolvedBuf[consumer], tsMsg)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//TODO test InMemMsgStream
|
|
|
|
/*
|
|
|
|
type InMemMsgStream struct {
|
|
|
|
buffer chan *MsgPack
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ms *InMemMsgStream) Start() {}
|
|
|
|
func (ms *InMemMsgStream) Close() {}
|
|
|
|
|
|
|
|
func (ms *InMemMsgStream) ProduceOne(msg TsMsg) error {
|
|
|
|
msgPack := MsgPack{}
|
|
|
|
msgPack.BeginTs = msg.BeginTs()
|
|
|
|
msgPack.EndTs = msg.EndTs()
|
|
|
|
msgPack.Msgs = append(msgPack.Msgs, msg)
|
|
|
|
buffer <- &msgPack
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ms *InMemMsgStream) Produce(msgPack *MsgPack) error {
|
|
|
|
buffer <- msgPack
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ms *InMemMsgStream) Broadcast(msgPack *MsgPack) error {
|
|
|
|
return ms.Produce(msgPack)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ms *InMemMsgStream) Consume() *MsgPack {
|
|
|
|
select {
|
|
|
|
case msgPack := <-ms.buffer:
|
|
|
|
return msgPack
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ms *InMemMsgStream) Chan() <- chan *MsgPack {
|
|
|
|
return buffer
|
|
|
|
}
|
|
|
|
*/
|