You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
85 lines
2.7 KiB
85 lines
2.7 KiB
'use strict';
|
|
|
|
const logger = require('../logging')('kafka-node:Range');
|
|
const VERSION = 0;
|
|
const _ = require('lodash');
|
|
const groupPartitionsByTopic = require('../utils').groupPartitionsByTopic;
|
|
|
|
function assignRange (topicPartition, groupMembers, callback) {
|
|
logger.debug('topicPartition: %j', topicPartition);
|
|
var assignment = _(groupMembers).map('id').reduce(function (obj, id) {
|
|
obj[id] = [];
|
|
return obj;
|
|
}, {});
|
|
|
|
const topicMemberMap = topicToMemberMap(groupMembers);
|
|
for (var topic in topicMemberMap) {
|
|
if (!topicMemberMap.hasOwnProperty(topic)) {
|
|
continue;
|
|
}
|
|
logger.debug('For topic %s', topic);
|
|
topicMemberMap[topic].sort();
|
|
logger.debug(' members: ', topicMemberMap[topic]);
|
|
|
|
var numberOfPartitionsForTopic = topicPartition[topic].length;
|
|
logger.debug(' numberOfPartitionsForTopic', numberOfPartitionsForTopic);
|
|
|
|
var numberOfMembersForTopic = topicMemberMap[topic].length;
|
|
logger.debug(' numberOfMembersForTopic', numberOfMembersForTopic);
|
|
|
|
var numberPartitionsPerMember = Math.floor(numberOfPartitionsForTopic / numberOfMembersForTopic);
|
|
logger.debug(' numberPartitionsPerMember', numberPartitionsPerMember);
|
|
|
|
var membersWithExtraPartition = numberOfPartitionsForTopic % numberOfMembersForTopic;
|
|
var topicPartitionList = createTopicPartitionArray(topic, numberOfPartitionsForTopic);
|
|
|
|
for (var i = 0, n = numberOfMembersForTopic; i < n; i++) {
|
|
var start = numberPartitionsPerMember * i + Math.min(i, membersWithExtraPartition);
|
|
var length = numberPartitionsPerMember + (i + 1 > membersWithExtraPartition ? 0 : 1);
|
|
var assignedTopicPartitions = assignment[topicMemberMap[topic][i]];
|
|
assignedTopicPartitions.push.apply(assignedTopicPartitions, topicPartitionList.slice(start, start + length));
|
|
}
|
|
}
|
|
|
|
logger.debug(assignment);
|
|
|
|
callback(null, convertToAssignmentList(assignment, VERSION));
|
|
}
|
|
|
|
function convertToAssignmentList (assignment, version) {
|
|
return _.map(assignment, function (value, key) {
|
|
return {
|
|
memberId: key,
|
|
topicPartitions: groupPartitionsByTopic(value),
|
|
version: version
|
|
};
|
|
});
|
|
}
|
|
|
|
function createTopicPartitionArray (topic, numberOfPartitions) {
|
|
return _.times(numberOfPartitions, function (n) {
|
|
return {
|
|
topic: topic,
|
|
partition: n
|
|
};
|
|
});
|
|
}
|
|
|
|
function topicToMemberMap (groupMembers) {
|
|
return groupMembers.reduce(function (result, member) {
|
|
member.subscription.forEach(function (topic) {
|
|
if (topic in result) {
|
|
result[topic].push(member.id);
|
|
} else {
|
|
result[topic] = [member.id];
|
|
}
|
|
});
|
|
return result;
|
|
}, {});
|
|
}
|
|
|
|
module.exports = {
|
|
assign: assignRange,
|
|
name: 'range',
|
|
version: VERSION
|
|
};
|
|
|