All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.flink.runtime.io.network.partition.ResultPartition Maven / Gradle / Ivy

There is a newer version: 1.13.6
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.flink.runtime.io.network.partition;

import org.apache.flink.runtime.executiongraph.IntermediateResultPartition;
import org.apache.flink.runtime.io.network.api.writer.ResultPartitionWriter;
import org.apache.flink.runtime.io.network.buffer.Buffer;
import org.apache.flink.runtime.io.network.buffer.BufferBuilder;
import org.apache.flink.runtime.io.network.buffer.BufferCompressor;
import org.apache.flink.runtime.io.network.buffer.BufferConsumer;
import org.apache.flink.runtime.io.network.buffer.BufferPool;
import org.apache.flink.runtime.io.network.buffer.BufferPoolOwner;
import org.apache.flink.runtime.io.network.partition.consumer.LocalInputChannel;
import org.apache.flink.runtime.io.network.partition.consumer.RemoteInputChannel;
import org.apache.flink.runtime.jobgraph.DistributionPattern;
import org.apache.flink.runtime.taskexecutor.TaskExecutor;
import org.apache.flink.util.function.FunctionWithException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;

import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;

import static org.apache.flink.util.Preconditions.checkArgument;
import static org.apache.flink.util.Preconditions.checkElementIndex;
import static org.apache.flink.util.Preconditions.checkNotNull;
import static org.apache.flink.util.Preconditions.checkState;

/**
 * A result partition for data produced by a single task.
 *
 * 

This class is the runtime part of a logical {@link IntermediateResultPartition}. Essentially, * a result partition is a collection of {@link Buffer} instances. The buffers are organized in one * or more {@link ResultSubpartition} instances, which further partition the data depending on the * number of consuming tasks and the data {@link DistributionPattern}. * *

Tasks, which consume a result partition have to request one of its subpartitions. The request * happens either remotely (see {@link RemoteInputChannel}) or locally (see {@link LocalInputChannel}) * *

Life-cycle

* *

The life-cycle of each result partition has three (possibly overlapping) phases: *

    *
  1. Produce:
  2. *
  3. Consume:
  4. *
  5. Release:
  6. *
* *

Buffer management

* *

State management

*/ public class ResultPartition implements ResultPartitionWriter, BufferPoolOwner { protected static final Logger LOG = LoggerFactory.getLogger(ResultPartition.class); private final String owningTaskName; protected final ResultPartitionID partitionId; /** Type of this partition. Defines the concrete subpartition implementation to use. */ protected final ResultPartitionType partitionType; /** The subpartitions of this partition. At least one. */ protected final ResultSubpartition[] subpartitions; protected final ResultPartitionManager partitionManager; public final int numTargetKeyGroups; // - Runtime state -------------------------------------------------------- private final AtomicBoolean isReleased = new AtomicBoolean(); private BufferPool bufferPool; private boolean isFinished; private volatile Throwable cause; private final FunctionWithException bufferPoolFactory; /** Used to compress buffer to reduce IO. */ @Nullable protected final BufferCompressor bufferCompressor; public ResultPartition( String owningTaskName, ResultPartitionID partitionId, ResultPartitionType partitionType, ResultSubpartition[] subpartitions, int numTargetKeyGroups, ResultPartitionManager partitionManager, @Nullable BufferCompressor bufferCompressor, FunctionWithException bufferPoolFactory) { this.owningTaskName = checkNotNull(owningTaskName); this.partitionId = checkNotNull(partitionId); this.partitionType = checkNotNull(partitionType); this.subpartitions = checkNotNull(subpartitions); this.numTargetKeyGroups = numTargetKeyGroups; this.partitionManager = checkNotNull(partitionManager); this.bufferCompressor = bufferCompressor; this.bufferPoolFactory = bufferPoolFactory; } /** * Registers a buffer pool with this result partition. * *

There is one pool for each result partition, which is shared by all its sub partitions. * *

The pool is registered with the partition *after* it as been constructed in order to conform * to the life-cycle of task registrations in the {@link TaskExecutor}. */ @Override public void setup() throws IOException { checkState(this.bufferPool == null, "Bug in result partition setup logic: Already registered buffer pool."); BufferPool bufferPool = checkNotNull(bufferPoolFactory.apply(this)); checkArgument(bufferPool.getNumberOfRequiredMemorySegments() >= getNumberOfSubpartitions(), "Bug in result partition setup logic: Buffer pool has not enough guaranteed buffers for this result partition."); this.bufferPool = bufferPool; partitionManager.registerResultPartition(this); } public String getOwningTaskName() { return owningTaskName; } public ResultPartitionID getPartitionId() { return partitionId; } @Override public int getNumberOfSubpartitions() { return subpartitions.length; } public BufferPool getBufferPool() { return bufferPool; } public int getNumberOfQueuedBuffers() { int totalBuffers = 0; for (ResultSubpartition subpartition : subpartitions) { totalBuffers += subpartition.unsynchronizedGetNumberOfQueuedBuffers(); } return totalBuffers; } /** * Returns the type of this result partition. * * @return result partition type */ public ResultPartitionType getPartitionType() { return partitionType; } // ------------------------------------------------------------------------ @Override public BufferBuilder getBufferBuilder() throws IOException, InterruptedException { checkInProduceState(); return bufferPool.requestBufferBuilderBlocking(); } @Override public boolean addBufferConsumer(BufferConsumer bufferConsumer, int subpartitionIndex) throws IOException { checkNotNull(bufferConsumer); ResultSubpartition subpartition; try { checkInProduceState(); subpartition = subpartitions[subpartitionIndex]; } catch (Exception ex) { bufferConsumer.close(); throw ex; } return subpartition.add(bufferConsumer); } @Override public void flushAll() { for (ResultSubpartition subpartition : subpartitions) { subpartition.flush(); } } @Override public void flush(int subpartitionIndex) { subpartitions[subpartitionIndex].flush(); } /** * Finishes the result partition. * *

After this operation, it is not possible to add further data to the result partition. * *

For BLOCKING results, this will trigger the deployment of consuming tasks. */ @Override public void finish() throws IOException { checkInProduceState(); for (ResultSubpartition subpartition : subpartitions) { subpartition.finish(); } isFinished = true; } public void release() { release(null); } /** * Releases the result partition. */ public void release(Throwable cause) { if (isReleased.compareAndSet(false, true)) { LOG.debug("{}: Releasing {}.", owningTaskName, this); // Set the error cause if (cause != null) { this.cause = cause; } // Release all subpartitions for (ResultSubpartition subpartition : subpartitions) { try { subpartition.release(); } // Catch this in order to ensure that release is called on all subpartitions catch (Throwable t) { LOG.error("Error during release of result subpartition: " + t.getMessage(), t); } } } } @Override public void close() { if (bufferPool != null) { bufferPool.lazyDestroy(); } } @Override public void fail(@Nullable Throwable throwable) { partitionManager.releasePartition(partitionId, throwable); } /** * Returns the requested subpartition. */ public ResultSubpartitionView createSubpartitionView(int index, BufferAvailabilityListener availabilityListener) throws IOException { checkElementIndex(index, subpartitions.length, "Subpartition not found."); checkState(!isReleased.get(), "Partition released."); ResultSubpartitionView readView = subpartitions[index].createReadView(availabilityListener); LOG.debug("Created {}", readView); return readView; } public Throwable getFailureCause() { return cause; } @Override public int getNumTargetKeyGroups() { return numTargetKeyGroups; } /** * Releases buffers held by this result partition. * *

This is a callback from the buffer pool, which is registered for result partitions, which * are back pressure-free. */ @Override public void releaseMemory(int toRelease) throws IOException { checkArgument(toRelease > 0); for (ResultSubpartition subpartition : subpartitions) { toRelease -= subpartition.releaseMemory(); // Only release as much memory as needed if (toRelease <= 0) { break; } } } /** * Whether this partition is released. * *

A partition is released when each subpartition is either consumed and communication is closed by consumer * or failed. A partition is also released if task is cancelled. */ public boolean isReleased() { return isReleased.get(); } @Override public CompletableFuture getAvailableFuture() { return bufferPool.getAvailableFuture(); } @Override public String toString() { return "ResultPartition " + partitionId.toString() + " [" + partitionType + ", " + subpartitions.length + " subpartitions]"; } // ------------------------------------------------------------------------ /** * Notification when a subpartition is released. */ void onConsumedSubpartition(int subpartitionIndex) { if (isReleased.get()) { return; } LOG.debug("{}: Received release notification for subpartition {}.", this, subpartitionIndex); } public ResultSubpartition[] getAllPartitions() { return subpartitions; } // ------------------------------------------------------------------------ private void checkInProduceState() throws IllegalStateException { checkState(!isFinished, "Partition already finished."); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy