Search in sources :

Example 11 with InternalNode

use of io.trino.metadata.InternalNode in project trino by trinodb.

the class ClusterMemoryManager method updateNodes.

private synchronized void updateNodes() {
    ImmutableSet.Builder<InternalNode> builder = ImmutableSet.builder();
    Set<InternalNode> aliveNodes = builder.addAll(nodeManager.getNodes(ACTIVE)).addAll(nodeManager.getNodes(SHUTTING_DOWN)).build();
    ImmutableSet<String> aliveNodeIds = aliveNodes.stream().map(InternalNode::getNodeIdentifier).collect(toImmutableSet());
    // Remove nodes that don't exist anymore
    // Make a copy to materialize the set difference
    Set<String> deadNodes = ImmutableSet.copyOf(difference(nodes.keySet(), aliveNodeIds));
    nodes.keySet().removeAll(deadNodes);
    // Add new nodes
    for (InternalNode node : aliveNodes) {
        if (!nodes.containsKey(node.getNodeIdentifier())) {
            nodes.put(node.getNodeIdentifier(), new RemoteNodeMemory(node, httpClient, memoryInfoCodec, locationFactory.createMemoryInfoLocation(node)));
        }
    }
    // in polling or updating its memory pools
    if (!isWorkScheduledOnCoordinator) {
        nodes.remove(nodeManager.getCurrentNode().getNodeIdentifier());
    }
    // Schedule refresh
    for (RemoteNodeMemory node : nodes.values()) {
        node.asyncRefresh();
    }
}
Also used : ImmutableSet(com.google.common.collect.ImmutableSet) ImmutableSet.toImmutableSet(com.google.common.collect.ImmutableSet.toImmutableSet) InternalNode(io.trino.metadata.InternalNode)

Example 12 with InternalNode

use of io.trino.metadata.InternalNode in project trino by trinodb.

the class SourcePartitionedScheduler method createTaskOnRandomNode.

private void createTaskOnRandomNode() {
    checkState(scheduledTasks.isEmpty(), "Stage task is already scheduled on node");
    List<InternalNode> allNodes = splitPlacementPolicy.allNodes();
    checkState(allNodes.size() > 0, "No nodes available");
    InternalNode node = allNodes.get(ThreadLocalRandom.current().nextInt(0, allNodes.size()));
    scheduleTask(node, ImmutableMultimap.of(), ImmutableMultimap.of());
}
Also used : InternalNode(io.trino.metadata.InternalNode)

Example 13 with InternalNode

use of io.trino.metadata.InternalNode in project trino by trinodb.

the class SourcePartitionedScheduler method schedule.

@Override
public synchronized ScheduleResult schedule() {
    dropListenersFromWhenFinishedOrNewLifespansAdded();
    int overallSplitAssignmentCount = 0;
    ImmutableSet.Builder<RemoteTask> overallNewTasks = ImmutableSet.builder();
    List<ListenableFuture<?>> overallBlockedFutures = new ArrayList<>();
    boolean anyBlockedOnPlacements = false;
    boolean anyBlockedOnNextSplitBatch = false;
    boolean anyNotBlocked = false;
    for (Entry<Lifespan, ScheduleGroup> entry : scheduleGroups.entrySet()) {
        Lifespan lifespan = entry.getKey();
        ScheduleGroup scheduleGroup = entry.getValue();
        Set<Split> pendingSplits = scheduleGroup.pendingSplits;
        if (scheduleGroup.state == ScheduleGroupState.NO_MORE_SPLITS || scheduleGroup.state == ScheduleGroupState.DONE) {
            verify(scheduleGroup.nextSplitBatchFuture == null);
        } else if (pendingSplits.isEmpty()) {
            // try to get the next batch
            if (scheduleGroup.nextSplitBatchFuture == null) {
                scheduleGroup.nextSplitBatchFuture = splitSource.getNextBatch(scheduleGroup.partitionHandle, lifespan, splitBatchSize - pendingSplits.size());
                long start = System.nanoTime();
                addSuccessCallback(scheduleGroup.nextSplitBatchFuture, () -> stageExecution.recordGetSplitTime(start));
            }
            if (scheduleGroup.nextSplitBatchFuture.isDone()) {
                SplitBatch nextSplits = getFutureValue(scheduleGroup.nextSplitBatchFuture);
                scheduleGroup.nextSplitBatchFuture = null;
                pendingSplits.addAll(nextSplits.getSplits());
                if (nextSplits.isLastBatch()) {
                    if (scheduleGroup.state == ScheduleGroupState.INITIALIZED && pendingSplits.isEmpty()) {
                        // Add an empty split in case no splits have been produced for the source.
                        // For source operators, they never take input, but they may produce output.
                        // This is well handled by the execution engine.
                        // However, there are certain non-source operators that may produce output without any input,
                        // for example, 1) an AggregationOperator, 2) a HashAggregationOperator where one of the grouping sets is ().
                        // Scheduling an empty split kicks off necessary driver instantiation to make this work.
                        pendingSplits.add(new Split(splitSource.getCatalogName(), new EmptySplit(splitSource.getCatalogName()), lifespan));
                    }
                    scheduleGroup.state = ScheduleGroupState.NO_MORE_SPLITS;
                }
            } else {
                overallBlockedFutures.add(scheduleGroup.nextSplitBatchFuture);
                anyBlockedOnNextSplitBatch = true;
                continue;
            }
        }
        Multimap<InternalNode, Split> splitAssignment = ImmutableMultimap.of();
        if (!pendingSplits.isEmpty()) {
            if (!scheduleGroup.placementFuture.isDone()) {
                anyBlockedOnPlacements = true;
                continue;
            }
            if (scheduleGroup.state == ScheduleGroupState.INITIALIZED) {
                scheduleGroup.state = ScheduleGroupState.SPLITS_ADDED;
            }
            if (state == State.INITIALIZED) {
                state = State.SPLITS_ADDED;
            }
            // calculate placements for splits
            SplitPlacementResult splitPlacementResult = splitPlacementPolicy.computeAssignments(pendingSplits);
            splitAssignment = splitPlacementResult.getAssignments();
            // remove splits with successful placements
            // AbstractSet.removeAll performs terribly here.
            splitAssignment.values().forEach(pendingSplits::remove);
            overallSplitAssignmentCount += splitAssignment.size();
            // if not completed placed, mark scheduleGroup as blocked on placement
            if (!pendingSplits.isEmpty()) {
                scheduleGroup.placementFuture = splitPlacementResult.getBlocked();
                overallBlockedFutures.add(scheduleGroup.placementFuture);
                anyBlockedOnPlacements = true;
            }
        }
        // if no new splits will be assigned, update state and attach completion event
        Multimap<InternalNode, Lifespan> noMoreSplitsNotification = ImmutableMultimap.of();
        if (pendingSplits.isEmpty() && scheduleGroup.state == ScheduleGroupState.NO_MORE_SPLITS) {
            scheduleGroup.state = ScheduleGroupState.DONE;
            if (!lifespan.isTaskWide()) {
                InternalNode node = ((BucketedSplitPlacementPolicy) splitPlacementPolicy).getNodeForBucket(lifespan.getId());
                noMoreSplitsNotification = ImmutableMultimap.of(node, lifespan);
            }
        }
        // assign the splits with successful placements
        overallNewTasks.addAll(assignSplits(splitAssignment, noMoreSplitsNotification));
        // As a result, to avoid busy loops caused by 1, we check pendingSplits.isEmpty() instead of placementFuture.isDone() here.
        if (scheduleGroup.nextSplitBatchFuture == null && scheduleGroup.pendingSplits.isEmpty() && scheduleGroup.state != ScheduleGroupState.DONE) {
            anyNotBlocked = true;
        }
    }
    // Next time it invokes getNextBatch, it will realize that. However, the invocation will fail we tear down splitSource now.
    if ((state == State.NO_MORE_SPLITS || state == State.FINISHED) || (noMoreScheduleGroups && scheduleGroups.isEmpty() && splitSource.isFinished())) {
        switch(state) {
            case INITIALIZED:
                // But this shouldn't be possible. See usage of EmptySplit in this method.
                throw new IllegalStateException("At least 1 split should have been scheduled for this plan node");
            case SPLITS_ADDED:
                state = State.NO_MORE_SPLITS;
                Optional<List<Object>> tableExecuteSplitsInfo = splitSource.getTableExecuteSplitsInfo();
                // Here we assume that we can get non-empty tableExecuteSplitsInfo only for queries which facilitate single split source.
                // TODO support grouped execution
                tableExecuteSplitsInfo.ifPresent(info -> {
                    TableExecuteContext tableExecuteContext = tableExecuteContextManager.getTableExecuteContextForQuery(stageExecution.getStageId().getQueryId());
                    tableExecuteContext.setSplitsInfo(info);
                });
                splitSource.close();
            // fall through
            case NO_MORE_SPLITS:
                state = State.FINISHED;
                whenFinishedOrNewLifespanAdded.set(null);
            // fall through
            case FINISHED:
                return new ScheduleResult(true, overallNewTasks.build(), overallSplitAssignmentCount);
        }
        throw new IllegalStateException("Unknown state");
    }
    if (anyNotBlocked) {
        return new ScheduleResult(false, overallNewTasks.build(), overallSplitAssignmentCount);
    }
    boolean anySourceTaskBlocked = this.anySourceTaskBlocked.getAsBoolean();
    if (anySourceTaskBlocked) {
        // Dynamic filters might not be collected due to build side source tasks being blocked on full buffer.
        // In such case probe split generation that is waiting for dynamic filters should be unblocked to prevent deadlock.
        dynamicFilterService.unblockStageDynamicFilters(stageExecution.getStageId().getQueryId(), stageExecution.getAttemptId(), stageExecution.getFragment());
    }
    if (groupedExecution) {
        overallNewTasks.addAll(finalizeTaskCreationIfNecessary());
    } else if (anyBlockedOnPlacements && anySourceTaskBlocked) {
        // In a broadcast join, output buffers of the tasks in build source stage have to
        // hold onto all data produced before probe side task scheduling finishes,
        // even if the data is acknowledged by all known consumers. This is because
        // new consumers may be added until the probe side task scheduling finishes.
        // 
        // As a result, the following line is necessary to prevent deadlock
        // due to neither build nor probe can make any progress.
        // The build side blocks due to a full output buffer.
        // In the meantime the probe side split cannot be consumed since
        // builder side hash table construction has not finished.
        overallNewTasks.addAll(finalizeTaskCreationIfNecessary());
    }
    ScheduleResult.BlockedReason blockedReason;
    if (anyBlockedOnNextSplitBatch) {
        blockedReason = anyBlockedOnPlacements ? MIXED_SPLIT_QUEUES_FULL_AND_WAITING_FOR_SOURCE : WAITING_FOR_SOURCE;
    } else {
        blockedReason = anyBlockedOnPlacements ? SPLIT_QUEUES_FULL : NO_ACTIVE_DRIVER_GROUP;
    }
    overallBlockedFutures.add(whenFinishedOrNewLifespanAdded);
    return new ScheduleResult(false, overallNewTasks.build(), nonCancellationPropagating(asVoid(whenAnyComplete(overallBlockedFutures))), blockedReason, overallSplitAssignmentCount);
}
Also used : ArrayList(java.util.ArrayList) SplitBatch(io.trino.split.SplitSource.SplitBatch) ImmutableSet.toImmutableSet(com.google.common.collect.ImmutableSet.toImmutableSet) ImmutableSet(com.google.common.collect.ImmutableSet) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) List(java.util.List) EmptySplit(io.trino.split.EmptySplit) RemoteTask(io.trino.execution.RemoteTask) TableExecuteContext(io.trino.execution.TableExecuteContext) ListenableFuture(com.google.common.util.concurrent.ListenableFuture) InternalNode(io.trino.metadata.InternalNode) EmptySplit(io.trino.split.EmptySplit) Split(io.trino.metadata.Split) Lifespan(io.trino.execution.Lifespan) BucketedSplitPlacementPolicy(io.trino.execution.scheduler.FixedSourcePartitionedScheduler.BucketedSplitPlacementPolicy)

Example 14 with InternalNode

use of io.trino.metadata.InternalNode in project trino by trinodb.

the class SourcePartitionedScheduler method assignSplits.

private Set<RemoteTask> assignSplits(Multimap<InternalNode, Split> splitAssignment, Multimap<InternalNode, Lifespan> noMoreSplitsNotification) {
    ImmutableSet.Builder<RemoteTask> newTasks = ImmutableSet.builder();
    ImmutableSet<InternalNode> nodes = ImmutableSet.<InternalNode>builder().addAll(splitAssignment.keySet()).addAll(noMoreSplitsNotification.keySet()).build();
    for (InternalNode node : nodes) {
        // source partitioned tasks can only receive broadcast data; otherwise it would have a different distribution
        ImmutableMultimap<PlanNodeId, Split> splits = ImmutableMultimap.<PlanNodeId, Split>builder().putAll(partitionedNode, splitAssignment.get(node)).build();
        ImmutableMultimap.Builder<PlanNodeId, Lifespan> noMoreSplits = ImmutableMultimap.builder();
        if (noMoreSplitsNotification.containsKey(node)) {
            noMoreSplits.putAll(partitionedNode, noMoreSplitsNotification.get(node));
        }
        RemoteTask task = scheduledTasks.get(node);
        if (task != null) {
            task.addSplits(splits);
            noMoreSplits.build().forEach(task::noMoreSplits);
        } else {
            scheduleTask(node, splits, noMoreSplits.build()).ifPresent(newTasks::add);
        }
    }
    return newTasks.build();
}
Also used : RemoteTask(io.trino.execution.RemoteTask) PlanNodeId(io.trino.sql.planner.plan.PlanNodeId) ImmutableSet.toImmutableSet(com.google.common.collect.ImmutableSet.toImmutableSet) ImmutableSet(com.google.common.collect.ImmutableSet) InternalNode(io.trino.metadata.InternalNode) ImmutableMultimap(com.google.common.collect.ImmutableMultimap) EmptySplit(io.trino.split.EmptySplit) Split(io.trino.metadata.Split) Lifespan(io.trino.execution.Lifespan)

Example 15 with InternalNode

use of io.trino.metadata.InternalNode in project trino by trinodb.

the class SystemPartitioningHandle method getNodePartitionMap.

public NodePartitionMap getNodePartitionMap(Session session, NodeScheduler nodeScheduler) {
    NodeSelector nodeSelector = nodeScheduler.createNodeSelector(session, Optional.empty());
    List<InternalNode> nodes;
    switch(partitioning) {
        case COORDINATOR_ONLY:
            nodes = ImmutableList.of(nodeSelector.selectCurrentNode());
            break;
        case SINGLE:
            nodes = nodeSelector.selectRandomNodes(1);
            break;
        case FIXED:
            nodes = nodeSelector.selectRandomNodes(getHashPartitionCount(session));
            break;
        default:
            throw new IllegalArgumentException("Unsupported plan distribution " + partitioning);
    }
    checkCondition(!nodes.isEmpty(), NO_NODES_AVAILABLE, "No worker nodes available");
    return new NodePartitionMap(nodes, split -> {
        throw new UnsupportedOperationException("System distribution does not support source splits");
    });
}
Also used : NodeSelector(io.trino.execution.scheduler.NodeSelector) InternalNode(io.trino.metadata.InternalNode)

Aggregations

InternalNode (io.trino.metadata.InternalNode)57 Split (io.trino.metadata.Split)27 Test (org.testng.annotations.Test)25 ConnectorSplit (io.trino.spi.connector.ConnectorSplit)21 LinkedHashSet (java.util.LinkedHashSet)17 ImmutableList (com.google.common.collect.ImmutableList)16 HashSet (java.util.HashSet)16 RemoteTask (io.trino.execution.RemoteTask)12 ImmutableSet (com.google.common.collect.ImmutableSet)9 HostAddress (io.trino.spi.HostAddress)9 List (java.util.List)9 NodeTaskMap (io.trino.execution.NodeTaskMap)8 ListenableFuture (com.google.common.util.concurrent.ListenableFuture)7 InMemoryNodeManager (io.trino.metadata.InMemoryNodeManager)7 InetAddress (java.net.InetAddress)7 UnknownHostException (java.net.UnknownHostException)7 ArrayList (java.util.ArrayList)7 Objects.requireNonNull (java.util.Objects.requireNonNull)7 ImmutableList.toImmutableList (com.google.common.collect.ImmutableList.toImmutableList)6 SplitWeight (io.trino.spi.SplitWeight)6