-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Support limiting the number of unacknowledged source splits per task #15761
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,43 +20,98 @@ | |
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.function.Function; | ||
|
|
||
| import static com.google.common.base.Preconditions.checkArgument; | ||
| import static java.util.Objects.requireNonNull; | ||
|
|
||
| public final class NodeAssignmentStats | ||
| { | ||
| private final NodeTaskMap nodeTaskMap; | ||
| private final Map<InternalNode, Integer> assignmentCount = new HashMap<>(); | ||
| private final Map<InternalNode, Integer> splitCountByNode = new HashMap<>(); | ||
| private final Map<String, Integer> queuedSplitCountByNode = new HashMap<>(); | ||
| private final Map<InternalNode, Integer> nodeTotalSplitCount; | ||
| private final Map<String, PendingSplitInfo> stageQueuedSplitInfo; | ||
|
|
||
| public NodeAssignmentStats(NodeTaskMap nodeTaskMap, NodeMap nodeMap, List<RemoteTask> existingTasks) | ||
| { | ||
| this.nodeTaskMap = requireNonNull(nodeTaskMap, "nodeTaskMap is null"); | ||
| int nodeMapSize = requireNonNull(nodeMap, "nodeMap is null").getNodesByHostAndPort().size(); | ||
| this.nodeTotalSplitCount = new HashMap<>(nodeMapSize); | ||
| this.stageQueuedSplitInfo = new HashMap<>(nodeMapSize); | ||
|
|
||
| // pre-populate the assignment counts with zeros. This makes getOrDefault() faster | ||
| for (InternalNode node : nodeMap.getNodesByHostAndPort().values()) { | ||
| assignmentCount.put(node, 0); | ||
| for (RemoteTask task : existingTasks) { | ||
| checkArgument(stageQueuedSplitInfo.put(task.getNodeId(), new PendingSplitInfo(task.getQueuedPartitionedSplitCount(), task.getUnacknowledgedPartitionedSplitCount())) == null, "A single stage may not have multiple tasks running on the same node"); | ||
| } | ||
|
|
||
| for (RemoteTask task : existingTasks) { | ||
| checkArgument(queuedSplitCountByNode.put(task.getNodeId(), task.getQueuedPartitionedSplitCount()) == null, "A single stage may not have multiple tasks running on the same node"); | ||
| // pre-populate the assignment counts with zeros | ||
| if (existingTasks.size() < nodeMapSize) { | ||
| Function<String, PendingSplitInfo> createEmptySplitInfo = (ignored) -> new PendingSplitInfo(0, 0); | ||
| for (InternalNode node : nodeMap.getNodesByHostAndPort().values()) { | ||
| stageQueuedSplitInfo.computeIfAbsent(node.getNodeIdentifier(), createEmptySplitInfo); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public int getTotalSplitCount(InternalNode node) | ||
| { | ||
| return assignmentCount.getOrDefault(node, 0) + splitCountByNode.computeIfAbsent(node, nodeTaskMap::getPartitionedSplitsOnNode); | ||
| int nodeTotalSplits = nodeTotalSplitCount.computeIfAbsent(node, nodeTaskMap::getPartitionedSplitsOnNode); | ||
| PendingSplitInfo stageInfo = stageQueuedSplitInfo.get(node.getNodeIdentifier()); | ||
| return nodeTotalSplits + (stageInfo == null ? 0 : stageInfo.getAssignedSplitCount()); | ||
| } | ||
|
|
||
| public int getQueuedSplitCountForStage(InternalNode node) | ||
| { | ||
| return queuedSplitCountByNode.getOrDefault(node.getNodeIdentifier(), 0) + assignmentCount.getOrDefault(node, 0); | ||
| PendingSplitInfo stageInfo = stageQueuedSplitInfo.get(node.getNodeIdentifier()); | ||
| return stageInfo == null ? 0 : stageInfo.getQueuedSplitCount(); | ||
| } | ||
|
|
||
| public int getUnacknowledgedSplitCountForStage(InternalNode node) | ||
| { | ||
| PendingSplitInfo stageInfo = stageQueuedSplitInfo.get(node.getNodeIdentifier()); | ||
| return stageInfo == null ? 0 : stageInfo.getUnacknowledgedSplitCount(); | ||
| } | ||
|
|
||
| public void addAssignedSplit(InternalNode node) | ||
| { | ||
| assignmentCount.merge(node, 1, (x, y) -> x + y); | ||
| String nodeId = node.getNodeIdentifier(); | ||
| // Avoids the extra per-invocation lambda allocation of computeIfAbsent since assigning a split to an existing task more common than creating a new task | ||
| PendingSplitInfo stageInfo = stageQueuedSplitInfo.get(nodeId); | ||
| if (stageInfo == null) { | ||
| stageInfo = new PendingSplitInfo(0, 0); | ||
| stageQueuedSplitInfo.put(nodeId, stageInfo); | ||
| } | ||
| stageInfo.addAssignedSplit(); | ||
| } | ||
|
|
||
| private static final class PendingSplitInfo | ||
| { | ||
| private final int queuedSplitCount; | ||
| private final int unacknowledgedSplitCount; | ||
| private int assignedSplits; | ||
|
|
||
| private PendingSplitInfo(int queuedSplitCount, int unacknowledgedSplitCount) | ||
| { | ||
| this.queuedSplitCount = queuedSplitCount; | ||
| this.unacknowledgedSplitCount = unacknowledgedSplitCount; | ||
| } | ||
|
|
||
| public int getAssignedSplitCount() | ||
| { | ||
| return assignedSplits; | ||
| } | ||
|
|
||
| public int getQueuedSplitCount() | ||
| { | ||
| return queuedSplitCount + assignedSplits; | ||
|
||
| } | ||
|
|
||
| public int getUnacknowledgedSplitCount() | ||
| { | ||
| return unacknowledgedSplitCount + assignedSplits; | ||
| } | ||
|
|
||
| public void addAssignedSplit() | ||
| { | ||
| assignedSplits++; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,7 @@ | |
| package com.facebook.presto.execution.scheduler; | ||
|
|
||
| import com.facebook.airlift.configuration.Config; | ||
| import com.facebook.airlift.configuration.ConfigDescription; | ||
| import com.facebook.airlift.configuration.DefunctConfig; | ||
| import com.facebook.airlift.configuration.LegacyConfig; | ||
|
|
||
|
|
@@ -34,6 +35,7 @@ public static class NetworkTopologyType | |
| private boolean includeCoordinator = true; | ||
| private int maxSplitsPerNode = 100; | ||
| private int maxPendingSplitsPerTask = 10; | ||
| private int maxUnacknowledgedSplitsPerTask = 500; | ||
|
||
| private String networkTopology = NetworkTopologyType.LEGACY; | ||
|
|
||
| @NotNull | ||
|
|
@@ -98,4 +100,18 @@ public NodeSchedulerConfig setMaxSplitsPerNode(int maxSplitsPerNode) | |
| this.maxSplitsPerNode = maxSplitsPerNode; | ||
| return this; | ||
| } | ||
|
|
||
| @Min(1) | ||
| public int getMaxUnacknowledgedSplitsPerTask() | ||
| { | ||
| return maxUnacknowledgedSplitsPerTask; | ||
| } | ||
|
|
||
| @Config("node-scheduler.max-unacknowledged-splits-per-task") | ||
| @ConfigDescription("Maximum number of leaf splits not yet delivered to a given task") | ||
| public NodeSchedulerConfig setMaxUnacknowledgedSplitsPerTask(int maxUnacknowledgedSplitsPerTask) | ||
| { | ||
| this.maxUnacknowledgedSplitsPerTask = maxUnacknowledgedSplitsPerTask; | ||
| return this; | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.