2023-12-12 04:05:54 +08:00
|
|
|
package sub_coordinator
|
|
|
|
|
|
|
|
import (
|
2024-05-28 08:30:16 +08:00
|
|
|
"fmt"
|
2023-12-12 04:05:54 +08:00
|
|
|
cmap "github.com/orcaman/concurrent-map/v2"
|
2024-06-07 10:44:19 +08:00
|
|
|
"github.com/seaweedfs/seaweedfs/weed/filer_client"
|
2023-12-29 12:35:15 +08:00
|
|
|
"github.com/seaweedfs/seaweedfs/weed/glog"
|
2023-12-12 04:05:54 +08:00
|
|
|
"github.com/seaweedfs/seaweedfs/weed/mq/topic"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/pb/mq_pb"
|
2023-12-29 03:56:37 +08:00
|
|
|
"time"
|
2023-12-12 04:05:54 +08:00
|
|
|
)
|
2023-12-23 03:33:50 +08:00
|
|
|
|
2023-12-12 04:05:54 +08:00
|
|
|
type ConsumerGroup struct {
|
2024-03-01 01:38:52 +08:00
|
|
|
topic topic.Topic
|
2023-12-12 04:05:54 +08:00
|
|
|
// map a consumer group instance id to a consumer group instance
|
|
|
|
ConsumerGroupInstances cmap.ConcurrentMap[string, *ConsumerGroupInstance]
|
2024-05-28 08:30:16 +08:00
|
|
|
Market *Market
|
2024-03-01 01:38:52 +08:00
|
|
|
reBalanceTimer *time.Timer
|
2024-06-07 10:44:19 +08:00
|
|
|
filerClientAccessor *filer_client.FilerClientAccessor
|
2024-05-28 08:30:16 +08:00
|
|
|
stopCh chan struct{}
|
2023-12-12 04:05:54 +08:00
|
|
|
}
|
|
|
|
|
2024-06-07 10:44:19 +08:00
|
|
|
func NewConsumerGroup(t *mq_pb.Topic, reblanceSeconds int32, filerClientAccessor *filer_client.FilerClientAccessor) *ConsumerGroup {
|
2024-05-28 08:30:16 +08:00
|
|
|
cg := &ConsumerGroup{
|
2023-12-29 12:35:15 +08:00
|
|
|
topic: topic.FromPbTopic(t),
|
2023-12-12 04:05:54 +08:00
|
|
|
ConsumerGroupInstances: cmap.New[*ConsumerGroupInstance](),
|
2024-05-14 23:50:17 +08:00
|
|
|
filerClientAccessor: filerClientAccessor,
|
2024-05-30 07:18:02 +08:00
|
|
|
stopCh: make(chan struct{}),
|
2023-12-12 04:05:54 +08:00
|
|
|
}
|
2024-05-28 08:30:16 +08:00
|
|
|
if conf, err := cg.filerClientAccessor.ReadTopicConfFromFiler(cg.topic); err == nil {
|
|
|
|
var partitions []topic.Partition
|
|
|
|
for _, assignment := range conf.BrokerPartitionAssignments {
|
|
|
|
partitions = append(partitions, topic.FromPbPartition(assignment.Partition))
|
|
|
|
}
|
|
|
|
cg.Market = NewMarket(partitions, time.Duration(reblanceSeconds)*time.Second)
|
|
|
|
} else {
|
|
|
|
glog.V(0).Infof("fail to read topic conf from filer: %v", err)
|
|
|
|
return nil
|
2024-05-20 05:52:38 +08:00
|
|
|
}
|
2024-05-28 08:30:16 +08:00
|
|
|
|
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case adjustment := <-cg.Market.AdjustmentChan:
|
|
|
|
cgi, found := cg.ConsumerGroupInstances.Get(string(adjustment.consumer))
|
|
|
|
if !found {
|
|
|
|
glog.V(0).Infof("consumer group instance %s not found", adjustment.consumer)
|
|
|
|
continue
|
2024-05-20 05:52:38 +08:00
|
|
|
}
|
2024-05-28 08:30:16 +08:00
|
|
|
if adjustment.isAssign {
|
|
|
|
if conf, err := cg.filerClientAccessor.ReadTopicConfFromFiler(cg.topic); err == nil {
|
|
|
|
for _, assignment := range conf.BrokerPartitionAssignments {
|
|
|
|
if adjustment.partition.Equals(topic.FromPbPartition(assignment.Partition)) {
|
|
|
|
cgi.ResponseChan <- &mq_pb.SubscriberToSubCoordinatorResponse{
|
|
|
|
Message: &mq_pb.SubscriberToSubCoordinatorResponse_Assignment_{
|
|
|
|
Assignment: &mq_pb.SubscriberToSubCoordinatorResponse_Assignment{
|
|
|
|
PartitionAssignment: &mq_pb.BrokerPartitionAssignment{
|
2024-05-30 07:18:02 +08:00
|
|
|
Partition: adjustment.partition.ToPbPartition(),
|
|
|
|
LeaderBroker: assignment.LeaderBroker,
|
2024-05-28 08:30:16 +08:00
|
|
|
FollowerBroker: assignment.FollowerBroker,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
glog.V(0).Infof("send assignment %v to %s", adjustment.partition, adjustment.consumer)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
cgi.ResponseChan <- &mq_pb.SubscriberToSubCoordinatorResponse{
|
|
|
|
Message: &mq_pb.SubscriberToSubCoordinatorResponse_UnAssignment_{
|
|
|
|
UnAssignment: &mq_pb.SubscriberToSubCoordinatorResponse_UnAssignment{
|
|
|
|
Partition: adjustment.partition.ToPbPartition(),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
glog.V(0).Infof("send unassignment %v to %s", adjustment.partition, adjustment.consumer)
|
|
|
|
}
|
|
|
|
case <-cg.stopCh:
|
2024-05-20 05:52:38 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2024-05-28 08:30:16 +08:00
|
|
|
}()
|
|
|
|
|
|
|
|
return cg
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cg *ConsumerGroup) AckAssignment(cgi *ConsumerGroupInstance, assignment *mq_pb.SubscriberToSubCoordinatorRequest_AckAssignmentMessage) {
|
|
|
|
fmt.Printf("ack assignment %v\n", assignment)
|
|
|
|
cg.Market.ConfirmAdjustment(&Adjustment{
|
|
|
|
consumer: cgi.InstanceId,
|
|
|
|
partition: topic.FromPbPartition(assignment.Partition),
|
|
|
|
isAssign: true,
|
2023-12-29 03:56:37 +08:00
|
|
|
})
|
2023-12-12 04:05:54 +08:00
|
|
|
}
|
2024-05-28 08:30:16 +08:00
|
|
|
func (cg *ConsumerGroup) AckUnAssignment(cgi *ConsumerGroupInstance, assignment *mq_pb.SubscriberToSubCoordinatorRequest_AckUnAssignmentMessage) {
|
|
|
|
fmt.Printf("ack unassignment %v\n", assignment)
|
|
|
|
cg.Market.ConfirmAdjustment(&Adjustment{
|
|
|
|
consumer: cgi.InstanceId,
|
|
|
|
partition: topic.FromPbPartition(assignment.Partition),
|
|
|
|
isAssign: false,
|
|
|
|
})
|
2023-12-29 03:56:37 +08:00
|
|
|
}
|
2023-12-12 04:05:54 +08:00
|
|
|
|
2024-05-28 08:30:16 +08:00
|
|
|
func (cg *ConsumerGroup) OnPartitionListChange(assignments []*mq_pb.BrokerPartitionAssignment) {
|
|
|
|
}
|
2023-12-29 12:35:15 +08:00
|
|
|
|
2024-05-28 08:30:16 +08:00
|
|
|
func (cg *ConsumerGroup) Shutdown() {
|
|
|
|
close(cg.stopCh)
|
2023-12-12 04:05:54 +08:00
|
|
|
}
|