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

org.apache.flink.runtime.taskexecutor.slot.TimerService Maven / Gradle / Ivy

There is a newer version: 1.5.1
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.taskexecutor.slot;

import org.apache.flink.util.Preconditions;

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

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 * Service to register timeouts for a given key. The timeouts are identified by a ticket so that
 * newly registered timeouts for the same key can be distinguished from older timeouts.
 *
 * @param  Type of the key
 */
public class TimerService {

	private static final Logger LOG = LoggerFactory.getLogger(TimerService.class);

	/** Executor service for the scheduled timeouts. */
	private final ScheduledExecutorService scheduledExecutorService;

	/** Timeout for the shutdown of the service. */
	private final long shutdownTimeout;

	/** Map of currently active timeouts. */
	private final Map> timeouts;

	/** Listener which is notified about occurring timeouts. */
	private TimeoutListener timeoutListener;

	public TimerService(
			final ScheduledExecutorService scheduledExecutorService,
			final long shutdownTimeout) {
		this.scheduledExecutorService = Preconditions.checkNotNull(scheduledExecutorService);

		Preconditions.checkArgument(shutdownTimeout >= 0L, "The shut down timeout must be larger than or equal than 0.");
		this.shutdownTimeout = shutdownTimeout;

		this.timeouts = new HashMap<>(16);
		this.timeoutListener = null;
	}

	public void start(TimeoutListener initialTimeoutListener) {
		// sanity check; We only allow to assign a timeout listener once
		Preconditions.checkState(!scheduledExecutorService.isShutdown());
		Preconditions.checkState(timeoutListener == null);

		this.timeoutListener = Preconditions.checkNotNull(initialTimeoutListener);
	}

	public void stop() {
		unregisterAllTimeouts();

		timeoutListener = null;

		scheduledExecutorService.shutdown();

		try {
			if (!scheduledExecutorService.awaitTermination(shutdownTimeout, TimeUnit.MILLISECONDS)) {
				LOG.debug("The scheduled executor service did not properly terminate. Shutting " +
					"it down now.");
				scheduledExecutorService.shutdownNow();
			}
		} catch (InterruptedException e) {
			LOG.debug("Could not properly await the termination of the scheduled executor service.", e);
			scheduledExecutorService.shutdownNow();
		}
	}

	/**
	 * Register a timeout for the given key which shall occur in the given delay.
	 *
	 * @param key for which to register the timeout
	 * @param delay until the timeout
	 * @param unit of the timeout delay
	 */
	public void registerTimeout(final K key, final long delay, final TimeUnit unit) {
		Preconditions.checkState(timeoutListener != null, "The " + getClass().getSimpleName() +
			" has not been started.");

		if (timeouts.containsKey(key)) {
			unregisterTimeout(key);
		}

		timeouts.put(key, new Timeout<>(timeoutListener, key, delay, unit, scheduledExecutorService));
	}

	/**
	 * Unregister the timeout for the given key.
	 *
	 * @param key for which to unregister the timeout
	 */
	public void unregisterTimeout(K key) {
		Timeout timeout = timeouts.remove(key);

		if (timeout != null) {
			timeout.cancel();
		}
	}

	/**
	 * Unregister all timeouts.
	 */
	protected void unregisterAllTimeouts() {
		for (Timeout timeout : timeouts.values()) {
			timeout.cancel();
		}
		timeouts.clear();
	}

	/**
	 * Check whether the timeout for the given key and ticket is still valid (not yet unregistered
	 * and not yet overwritten).
	 *
	 * @param key for which to check the timeout
	 * @param ticket of the timeout
	 * @return True if the timeout ticket is still valid; otherwise false
	 */
	public boolean isValid(K key, UUID ticket) {
		if (timeouts.containsKey(key)) {
			Timeout timeout = timeouts.get(key);

			return timeout.getTicket().equals(ticket);
		} else {
			return false;
		}
	}

	// ---------------------------------------------------------------------
	// Static utility classes
	// ---------------------------------------------------------------------

	private static final class Timeout implements Runnable {

		private final TimeoutListener timeoutListener;
		private final K key;
		private final ScheduledFuture scheduledTimeout;
		private final UUID ticket;

		Timeout(
			final TimeoutListener timeoutListener,
			final K key,
			final long delay,
			final TimeUnit unit,
			final ScheduledExecutorService scheduledExecutorService) {

			Preconditions.checkNotNull(scheduledExecutorService);

			this.timeoutListener = Preconditions.checkNotNull(timeoutListener);
			this.key = Preconditions.checkNotNull(key);
			this.scheduledTimeout = scheduledExecutorService.schedule(this, delay, unit);
			this.ticket = UUID.randomUUID();
		}

		UUID getTicket() {
			return ticket;
		}

		void cancel() {
			scheduledTimeout.cancel(true);
		}

		@Override
		public void run() {
			timeoutListener.notifyTimeout(key, ticket);
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy