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

org.apache.flink.runtime.state.SnapshotDirectory 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.state;

import org.apache.flink.core.fs.FileStatus;
import org.apache.flink.core.fs.FileSystem;
import org.apache.flink.core.fs.Path;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicReference;

/**
 * This class represents a directory that is the target for a state snapshot. This class provides some method that
 * simplify resource management when dealing with such directories, e.g. it can produce a {@link DirectoryStateHandle}
 * when the snapshot is completed and disposal considers whether or not a snapshot was already completed. For a
 * completed snapshot, the ownership for cleanup is transferred to the created directory state handle. For incomplete
 * snapshots, calling {@link #cleanup()} will delete the underlying directory resource.
 */
public abstract class SnapshotDirectory {

	/**
	 * Lifecycle stages of a snapshot directory.
	 */
	enum State {
		ONGOING, COMPLETED, DELETED
	}

	/** This path describes the underlying directory for the snapshot. */
	@Nonnull
	protected final Path directory;

	/** The filesystem that contains the snapshot directory. */
	@Nonnull
	protected final FileSystem fileSystem;

	/** This reference tracks the lifecycle state of the snapshot directory. */
	@Nonnull
	protected AtomicReference state;

	private SnapshotDirectory(@Nonnull Path directory, @Nonnull FileSystem fileSystem) {
		this.directory = directory;
		this.fileSystem = fileSystem;
		this.state = new AtomicReference<>(State.ONGOING);
	}

	private SnapshotDirectory(@Nonnull Path directory) throws IOException {
		this(directory, directory.getFileSystem());
	}

	@Nonnull
	public Path getDirectory() {
		return directory;
	}

	public boolean mkdirs() throws IOException {
		return fileSystem.mkdirs(directory);
	}

	@Nonnull
	public FileSystem getFileSystem() {
		return fileSystem;
	}

	public boolean exists() throws IOException {
		return fileSystem.exists(directory);
	}

	/**
	 * List the statuses of the files/directories in the snapshot directory.
	 *
	 * @return the statuses of the files/directories in the given path.
	 * @throws IOException if there is a problem creating the file statuses.
	 */
	public FileStatus[] listStatus() throws IOException {
		return fileSystem.listStatus(directory);
	}

	/**
	 * Calling this method will attempt delete the underlying snapshot directory recursively, if the state is
	 * "ongoing". In this case, the state will be set to "deleted" as a result of this call.
	 *
	 * @return true if delete is successful, false otherwise.
	 * @throws IOException if an exception happens during the delete.
	 */
	public boolean cleanup() throws IOException {
		return !state.compareAndSet(State.ONGOING, State.DELETED) || fileSystem.delete(directory, true);
	}

	/**
	 * Returns true if the snapshot is marked as completed.
	 */
	public boolean isSnapshotCompleted() {
		return State.COMPLETED == state.get();
	}

	/**
	 * Calling this method completes the snapshot for this snapshot directory, if possible, and creates a corresponding
	 * {@link DirectoryStateHandle} that points to the snapshot directory. Calling this method can change the
	 * lifecycle state from ONGOING to COMPLETED if the directory should no longer deleted in {@link #cleanup()}. This
	 * method can return Can return true if the directory is temporary and should therefore not be
	 * referenced in a handle.
	 *
	 * @return A directory state handle that points to the snapshot directory. Can return true if the
	 * directory is temporary and should therefore not be referenced in a handle.
	 * @throws IOException if the state of this snapshot directory object is different from "ongoing".
	 */
	@Nullable
	public abstract DirectoryStateHandle completeSnapshotAndGetHandle() throws IOException;

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (o == null || getClass() != o.getClass()) {
			return false;
		}

		SnapshotDirectory that = (SnapshotDirectory) o;

		return directory.equals(that.directory);
	}

	@Override
	public int hashCode() {
		return directory.hashCode();
	}

	@Override
	public String toString() {
		return "SnapshotDirectory{" +
			"directory=" + directory +
			", state=" + state +
			'}';
	}

	/**
	 * Creates a local temporary snapshot directory for the given path. This will always return "null" as result of
	 * {@link #completeSnapshotAndGetHandle()} and always attempt to delete the underlying directory in
	 * {@link #cleanup()}.
	 */
	public static SnapshotDirectory temporary(@Nonnull File directory) throws IOException {
		return new TemporarySnapshotDirectory(directory);
	}

	/**
	 * Creates a permanent snapshot directory for the given path, which will not delete the underlying directory in
	 * {@link #cleanup()} after {@link #completeSnapshotAndGetHandle()} was called.
	 */
	public static SnapshotDirectory permanent(@Nonnull Path directory) throws IOException {
		return new PermanentSnapshotDirectory(directory);
	}

	private static class TemporarySnapshotDirectory extends SnapshotDirectory {

		TemporarySnapshotDirectory(@Nonnull File directory) throws IOException {
			super(new Path(directory.toURI()), FileSystem.getLocalFileSystem());
		}

		@Override
		public DirectoryStateHandle completeSnapshotAndGetHandle() {
			return null; // We return null so that directory it is not referenced by a state handle.
		}
	}

	private static class PermanentSnapshotDirectory extends SnapshotDirectory {

		PermanentSnapshotDirectory(@Nonnull Path directory) throws IOException {
			super(directory);
		}

		@Override
		public DirectoryStateHandle completeSnapshotAndGetHandle() throws IOException {
			if (State.COMPLETED == state.get() || state.compareAndSet(State.ONGOING, State.COMPLETED)) {
				return new DirectoryStateHandle(directory);
			} else {
				throw new IOException("Expected state " + State.ONGOING + " but found state " + state.get());
			}
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy