|
@@ -1,6 +1,7 @@
|
|
|
package sarama
|
|
|
|
|
|
import (
|
|
|
+ "container/heap"
|
|
|
"math"
|
|
|
"sort"
|
|
|
)
|
|
@@ -507,22 +508,14 @@ func canTopicPartitionParticipateInReassignment(partition topicPartitionAssignme
|
|
|
|
|
|
|
|
|
func assignPartition(partition topicPartitionAssignment, sortedCurrentSubscriptions []string, currentAssignment map[string][]topicPartitionAssignment, consumer2AllPotentialPartitions map[string][]topicPartitionAssignment, currentPartitionConsumer map[topicPartitionAssignment]string) []string {
|
|
|
- updatedSubscriptions := make([]string, len(sortedCurrentSubscriptions))
|
|
|
- for i, s := range sortedCurrentSubscriptions {
|
|
|
- updatedSubscriptions[i] = s
|
|
|
- }
|
|
|
- i := 0
|
|
|
for _, memberID := range sortedCurrentSubscriptions {
|
|
|
if memberAssignmentsIncludeTopicPartition(consumer2AllPotentialPartitions[memberID], partition) {
|
|
|
- updatedSubscriptions = removeIndexFromStringSlice(updatedSubscriptions, i)
|
|
|
currentAssignment[memberID] = append(currentAssignment[memberID], partition)
|
|
|
currentPartitionConsumer[partition] = memberID
|
|
|
- updatedSubscriptions = append(updatedSubscriptions, memberID)
|
|
|
break
|
|
|
}
|
|
|
- i++
|
|
|
}
|
|
|
- return updatedSubscriptions
|
|
|
+ return sortMemberIDsByPartitionAssignments(currentAssignment)
|
|
|
}
|
|
|
|
|
|
|
|
@@ -599,44 +592,52 @@ func sortPartitions(currentAssignment map[string][]topicPartitionAssignment, par
|
|
|
|
|
|
assignments := filterAssignedPartitions(currentAssignment, partition2AllPotentialConsumers)
|
|
|
|
|
|
-
|
|
|
- sortedMemberIDs := sortMemberIDsByPartitionAssignments(assignments)
|
|
|
- for i := len(sortedMemberIDs)/2 - 1; i >= 0; i-- {
|
|
|
- opp := len(sortedMemberIDs) - 1 - i
|
|
|
- sortedMemberIDs[i], sortedMemberIDs[opp] = sortedMemberIDs[opp], sortedMemberIDs[i]
|
|
|
+
|
|
|
+
|
|
|
+ pq := make(assignmentPriorityQueue, len(assignments))
|
|
|
+ i := 0
|
|
|
+ for consumerID, consumerAssignments := range assignments {
|
|
|
+ pq[i] = &consumerGroupMember{
|
|
|
+ id: consumerID,
|
|
|
+ assignments: consumerAssignments,
|
|
|
+ index: i,
|
|
|
+ }
|
|
|
+ i++
|
|
|
}
|
|
|
+ heap.Init(&pq)
|
|
|
+
|
|
|
for {
|
|
|
|
|
|
- if len(sortedMemberIDs) == 0 {
|
|
|
+ if pq.Len() == 0 {
|
|
|
break
|
|
|
}
|
|
|
- updatedMemberIDs := make([]string, 0)
|
|
|
- for _, memberID := range sortedMemberIDs {
|
|
|
-
|
|
|
- prevPartitions := make([]topicPartitionAssignment, 0)
|
|
|
- for partition := range partitionsWithADifferentPreviousAssignment {
|
|
|
-
|
|
|
- if memberAssignmentsIncludeTopicPartition(assignments[memberID], partition) {
|
|
|
- prevPartitions = append(prevPartitions, partition)
|
|
|
- }
|
|
|
+ member := pq[0]
|
|
|
+
|
|
|
+
|
|
|
+ prevPartitions := make([]topicPartitionAssignment, 0)
|
|
|
+ for partition := range partitionsWithADifferentPreviousAssignment {
|
|
|
+
|
|
|
+ if memberAssignmentsIncludeTopicPartition(member.assignments, partition) {
|
|
|
+ prevPartitions = append(prevPartitions, partition)
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- if len(prevPartitions) > 0 {
|
|
|
-
|
|
|
- partition := prevPartitions[0]
|
|
|
- prevPartitions = append(prevPartitions[:0], prevPartitions[1:]...)
|
|
|
- assignments[memberID] = removeTopicPartitionFromMemberAssignments(assignments[memberID], partition)
|
|
|
- sortedPartitions = append(sortedPartitions, partition)
|
|
|
- updatedMemberIDs = append(updatedMemberIDs, memberID)
|
|
|
- } else if len(assignments[memberID]) > 0 {
|
|
|
-
|
|
|
- partition := assignments[memberID][0]
|
|
|
- assignments[memberID] = append(assignments[memberID][:0], assignments[memberID][1:]...)
|
|
|
- sortedPartitions = append(sortedPartitions, partition)
|
|
|
- updatedMemberIDs = append(updatedMemberIDs, memberID)
|
|
|
- }
|
|
|
+ if len(prevPartitions) > 0 {
|
|
|
+
|
|
|
+ partition := prevPartitions[0]
|
|
|
+ prevPartitions = append(prevPartitions[:0], prevPartitions[1:]...)
|
|
|
+ member.assignments = removeTopicPartitionFromMemberAssignments(member.assignments, partition)
|
|
|
+ sortedPartitions = append(sortedPartitions, partition)
|
|
|
+ heap.Fix(&pq, member.index)
|
|
|
+ } else if len(member.assignments) > 0 {
|
|
|
+
|
|
|
+ partition := member.assignments[0]
|
|
|
+ member.assignments = append(member.assignments[:0], member.assignments[1:]...)
|
|
|
+ sortedPartitions = append(sortedPartitions, partition)
|
|
|
+ heap.Fix(&pq, member.index)
|
|
|
+ } else {
|
|
|
+ heap.Remove(&pq, 0)
|
|
|
}
|
|
|
- sortedMemberIDs = updatedMemberIDs
|
|
|
}
|
|
|
|
|
|
for partition := range partition2AllPotentialConsumers {
|
|
@@ -1034,3 +1035,41 @@ nextCand:
|
|
|
}
|
|
|
return -1
|
|
|
}
|
|
|
+
|
|
|
+type consumerGroupMember struct {
|
|
|
+ index int
|
|
|
+ id string
|
|
|
+ assignments []topicPartitionAssignment
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+type assignmentPriorityQueue []*consumerGroupMember
|
|
|
+
|
|
|
+func (pq assignmentPriorityQueue) Len() int { return len(pq) }
|
|
|
+
|
|
|
+func (pq assignmentPriorityQueue) Less(i, j int) bool {
|
|
|
+
|
|
|
+ return len(pq[i].assignments) > len(pq[j].assignments)
|
|
|
+}
|
|
|
+
|
|
|
+func (pq assignmentPriorityQueue) Swap(i, j int) {
|
|
|
+ pq[i], pq[j] = pq[j], pq[i]
|
|
|
+ pq[i].index = i
|
|
|
+ pq[j].index = j
|
|
|
+}
|
|
|
+
|
|
|
+func (pq *assignmentPriorityQueue) Push(x interface{}) {
|
|
|
+ n := len(*pq)
|
|
|
+ member := x.(*consumerGroupMember)
|
|
|
+ member.index = n
|
|
|
+ *pq = append(*pq, member)
|
|
|
+}
|
|
|
+
|
|
|
+func (pq *assignmentPriorityQueue) Pop() interface{} {
|
|
|
+ old := *pq
|
|
|
+ n := len(old)
|
|
|
+ member := old[n-1]
|
|
|
+ member.index = -1
|
|
|
+ *pq = old[0 : n-1]
|
|
|
+ return member
|
|
|
+}
|