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

org.apache.flink.streaming.runtime.tasks.SourceStreamTask Maven / Gradle / Ivy

There is a newer version: 2.0-preview1
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.streaming.runtime.tasks;

import org.apache.flink.annotation.Internal;
import org.apache.flink.runtime.checkpoint.CheckpointMetaData;
import org.apache.flink.runtime.checkpoint.CheckpointOptions;
import org.apache.flink.runtime.checkpoint.CheckpointType;
import org.apache.flink.runtime.checkpoint.SavepointType;
import org.apache.flink.runtime.checkpoint.SnapshotType;
import org.apache.flink.runtime.execution.CancelTaskException;
import org.apache.flink.runtime.execution.Environment;
import org.apache.flink.runtime.io.network.api.StopMode;
import org.apache.flink.runtime.metrics.MetricNames;
import org.apache.flink.runtime.state.CheckpointStorageLocationReference;
import org.apache.flink.streaming.api.checkpoint.ExternallyInducedSource;
import org.apache.flink.streaming.api.functions.source.SourceFunction;
import org.apache.flink.streaming.api.operators.StreamSource;
import org.apache.flink.streaming.api.watermark.Watermark;
import org.apache.flink.streaming.runtime.tasks.mailbox.MailboxDefaultAction;
import org.apache.flink.util.ExceptionUtils;
import org.apache.flink.util.FatalExitExceptionHandler;
import org.apache.flink.util.FlinkException;
import org.apache.flink.util.Preconditions;

import javax.annotation.Nullable;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * {@link StreamTask} for executing a {@link StreamSource}.
 *
 * 

One important aspect of this is that the checkpointing and the emission of elements must never * occur at the same time. The execution must be serial. This is achieved by having the contract * with the {@link SourceFunction} that it must only modify its state or emit elements in a * synchronized block that locks on the lock Object. Also, the modification of the state and the * emission of elements must happen in the same block of code that is protected by the synchronized * block. * * @param Type of the output elements of this source. * @param Type of the source function for the stream source operator * @param Type of the stream source operator * @deprecated This class is based on the {@link * org.apache.flink.streaming.api.functions.source.SourceFunction} API, which is due to be * removed. Use the new {@link org.apache.flink.api.connector.source.Source} API instead. */ @Deprecated @Internal public class SourceStreamTask< OUT, SRC extends SourceFunction, OP extends StreamSource> extends StreamTask { private final LegacySourceFunctionThread sourceThread; private final Object lock; private volatile boolean externallyInducedCheckpoints; private final AtomicBoolean stopped = new AtomicBoolean(false); private enum FinishingReason { END_OF_DATA(StopMode.DRAIN), STOP_WITH_SAVEPOINT_DRAIN(StopMode.DRAIN), STOP_WITH_SAVEPOINT_NO_DRAIN(StopMode.NO_DRAIN); private final StopMode stopMode; FinishingReason(StopMode stopMode) { this.stopMode = stopMode; } StopMode toStopMode() { return this.stopMode; } } /** * Indicates whether this Task was purposefully finished, in this case we want to ignore * exceptions thrown after finishing, to ensure shutdown works smoothly. * *

Moreover we differentiate drain and no drain cases to see if we need to call finish() on * the operators. */ private volatile FinishingReason finishingReason = FinishingReason.END_OF_DATA; public SourceStreamTask(Environment env) throws Exception { this(env, new Object()); } private SourceStreamTask(Environment env, Object lock) throws Exception { super( env, null, FatalExitExceptionHandler.INSTANCE, StreamTaskActionExecutor.synchronizedExecutor(lock)); this.lock = Preconditions.checkNotNull(lock); this.sourceThread = new LegacySourceFunctionThread(); getEnvironment().getMetricGroup().getIOMetricGroup().setEnableBusyTime(false); } @Override protected void init() { // we check if the source is actually inducing the checkpoints, rather // than the trigger SourceFunction source = mainOperator.getUserFunction(); if (source instanceof ExternallyInducedSource) { externallyInducedCheckpoints = true; ExternallyInducedSource.CheckpointTrigger triggerHook = new ExternallyInducedSource.CheckpointTrigger() { @Override public void triggerCheckpoint(long checkpointId) throws FlinkException { // TODO - we need to see how to derive those. We should probably not // encode this in the // TODO - source's trigger message, but do a handshake in this task // between the trigger // TODO - message from the master, and the source's trigger // notification final CheckpointOptions checkpointOptions = CheckpointOptions.forConfig( CheckpointType.CHECKPOINT, CheckpointStorageLocationReference.getDefault(), configuration.isExactlyOnceCheckpointMode(), configuration.isUnalignedCheckpointsEnabled(), configuration.getAlignedCheckpointTimeout().toMillis()); final long timestamp = System.currentTimeMillis(); final CheckpointMetaData checkpointMetaData = new CheckpointMetaData(checkpointId, timestamp, timestamp); try { SourceStreamTask.super .triggerCheckpointAsync( checkpointMetaData, checkpointOptions) .get(); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new FlinkException(e.getMessage(), e); } } }; ((ExternallyInducedSource) source).setCheckpointTrigger(triggerHook); } getEnvironment() .getMetricGroup() .getIOMetricGroup() .gauge( MetricNames.CHECKPOINT_START_DELAY_TIME, this::getAsyncCheckpointStartDelayNanos); recordWriter.setMaxOverdraftBuffersPerGate(0); } @Override protected void advanceToEndOfEventTime() throws Exception { operatorChain.getMainOperatorOutput().emitWatermark(Watermark.MAX_WATERMARK); } @Override protected void cleanUpInternal() { // does not hold any resources, so no cleanup needed } @Override protected void processInput(MailboxDefaultAction.Controller controller) throws Exception { controller.suspendDefaultAction(); // Against the usual contract of this method, this implementation is not step-wise but // blocking instead for // compatibility reasons with the current source interface (source functions run as a loop, // not in steps). sourceThread.setTaskDescription(getName()); sourceThread.start(); sourceThread .getCompletionFuture() .whenComplete( (Void ignore, Throwable sourceThreadThrowable) -> { if (sourceThreadThrowable != null) { mailboxProcessor.reportThrowable(sourceThreadThrowable); } else { notifyEndOfData(); mailboxProcessor.suspend(); } }); } @Override protected void cancelTask() { if (stopped.compareAndSet(false, true)) { cancelOperator(); } } private void cancelOperator() { try { if (mainOperator != null) { mainOperator.cancel(); } } finally { if (sourceThread.isAlive()) { interruptSourceThread(); } else if (!sourceThread.getCompletionFuture().isDone()) { // sourceThread not alive and completion future not done means source thread // didn't start and we need to manually complete the future sourceThread.getCompletionFuture().complete(null); } } } @Override public void maybeInterruptOnCancel( Thread toInterrupt, @Nullable String taskName, @Nullable Long timeout) { super.maybeInterruptOnCancel(toInterrupt, taskName, timeout); interruptSourceThread(); } private void interruptSourceThread() { // Nothing need to do if the source is finished on restore if (operatorChain != null && operatorChain.isTaskDeployedAsFinished()) { return; } if (sourceThread.isAlive()) { sourceThread.interrupt(); } } @Override protected CompletableFuture getCompletionFuture() { return sourceThread.getCompletionFuture(); } // ------------------------------------------------------------------------ // Checkpointing // ------------------------------------------------------------------------ @Override public CompletableFuture triggerCheckpointAsync( CheckpointMetaData checkpointMetaData, CheckpointOptions checkpointOptions) { if (!externallyInducedCheckpoints) { if (isSynchronousSavepoint(checkpointOptions.getCheckpointType())) { return triggerStopWithSavepointAsync(checkpointMetaData, checkpointOptions); } else { return super.triggerCheckpointAsync(checkpointMetaData, checkpointOptions); } } else if (checkpointOptions.getCheckpointType().equals(CheckpointType.FULL_CHECKPOINT)) { // see FLINK-25256 throw new IllegalStateException( "Using externally induced sources, we can not enforce taking a full checkpoint." + "If you are restoring from a snapshot in NO_CLAIM mode, please use" + " CLAIM mode."); } else { // we do not trigger checkpoints here, we simply state whether we can trigger them synchronized (lock) { return CompletableFuture.completedFuture(isRunning()); } } } private boolean isSynchronousSavepoint(SnapshotType snapshotType) { return snapshotType.isSavepoint() && ((SavepointType) snapshotType).isSynchronous(); } private CompletableFuture triggerStopWithSavepointAsync( CheckpointMetaData checkpointMetaData, CheckpointOptions checkpointOptions) { mainMailboxExecutor.execute( () -> stopOperatorForStopWithSavepoint( checkpointMetaData.getCheckpointId(), ((SavepointType) checkpointOptions.getCheckpointType()) .shouldDrain()), "stop legacy source for stop-with-savepoint --drain"); return sourceThread .getCompletionFuture() .thenCompose( ignore -> super.triggerCheckpointAsync( checkpointMetaData, checkpointOptions)); } private void stopOperatorForStopWithSavepoint(long checkpointId, boolean drain) { setSynchronousSavepoint(checkpointId); finishingReason = drain ? FinishingReason.STOP_WITH_SAVEPOINT_DRAIN : FinishingReason.STOP_WITH_SAVEPOINT_NO_DRAIN; if (mainOperator != null) { mainOperator.stop(); } } @Override protected void declineCheckpoint(long checkpointId) { if (!externallyInducedCheckpoints) { super.declineCheckpoint(checkpointId); } } /** Runnable that executes the source function in the head operator. */ private class LegacySourceFunctionThread extends Thread { private final CompletableFuture completionFuture; LegacySourceFunctionThread() { this.completionFuture = new CompletableFuture<>(); } @Override public void run() { try { if (!operatorChain.isTaskDeployedAsFinished()) { LOG.debug( "Legacy source {} skip execution since the task is finished on restore", getTaskNameWithSubtaskAndId()); mainOperator.run(lock, operatorChain); } completeProcessing(); completionFuture.complete(null); } catch (Throwable t) { // Note, t can be also an InterruptedException if (isCanceled() && ExceptionUtils.findThrowable(t, InterruptedException.class) .isPresent()) { completionFuture.completeExceptionally(new CancelTaskException(t)); } else { completionFuture.completeExceptionally(t); } } } private void completeProcessing() throws InterruptedException, ExecutionException { if (!isCanceled() && !isFailing()) { mainMailboxExecutor .submit( () -> { // theoretically the StreamSource can implement BoundedOneInput, // so we need to call it here final StopMode stopMode = finishingReason.toStopMode(); if (stopMode == StopMode.DRAIN) { operatorChain.endInput(1); } endData(stopMode); }, "SourceStreamTask finished processing data.") .get(); } } public void setTaskDescription(final String taskDescription) { setName("Legacy Source Thread - " + taskDescription); } /** * @return future that is completed once this thread completes. If this task {@link * #isFailing()} and this thread is not alive (e.g. not started) returns a normally * completed future. */ CompletableFuture getCompletionFuture() { return isFailing() && !isAlive() ? CompletableFuture.completedFuture(null) : completionFuture; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy