FileSystem.java
// 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.doris.fs;
import org.apache.doris.fs.io.DorisInputFile;
import org.apache.doris.fs.io.DorisOutputFile;
import java.io.Closeable;
import java.io.IOException;
import java.util.Collection;
import java.util.Set;
/**
* Core filesystem abstraction for Apache Doris.
* <p>
* All methods use {@link Location} for path arguments and throw {@link IOException}
* on failure rather than returning a {@link org.apache.doris.backup.Status} object.
* <p>
* Implementations must be thread-safe. Instances may be shared and cached.
*
* @see LegacyFileSystemAdapter for adapting existing Status-based implementations
* @see MemoryFileSystem for in-memory testing
* @see LegacyFileSystemApi for the legacy Status-based interface (deprecated)
*/
public interface FileSystem extends Closeable {
// ─────────────────────────── I/O FILE ACCESS ───────────────────────────
/**
* Creates a new {@link DorisInputFile} for reading from the given location.
* Does not check existence; the file is opened lazily when
* {@link DorisInputFile#newInput()} or {@link DorisInputFile#newStream()} is called.
*/
DorisInputFile newInputFile(Location location);
/**
* Creates a new {@link DorisInputFile} with a known file length.
* The {@code length} hint may be used to skip a remote {@code stat()} call.
*/
DorisInputFile newInputFile(Location location, long length);
/**
* Creates a new {@link DorisOutputFile} for writing to the given location.
*/
DorisOutputFile newOutputFile(Location location);
// ─────────────────────────── METADATA OPERATIONS ───────────────────────────
/**
* Returns {@code true} if the location exists (file or directory).
*
* @throws IOException if the existence check fails for a reason other than "not found"
*/
boolean exists(Location location) throws IOException;
// ─────────────────────────── MUTATION OPERATIONS ───────────────────────────
/**
* Deletes the file at the given location.
*
* @throws IOException if deletion fails or the location is a directory
*/
void deleteFile(Location location) throws IOException;
/**
* Deletes multiple files. Default implementation calls {@link #deleteFile} in a loop;
* implementations may override for batch efficiency.
*/
default void deleteFiles(Collection<Location> locations) throws IOException {
for (Location location : locations) {
deleteFile(location);
}
}
/**
* Atomically renames (moves) a file from {@code source} to {@code target}.
*
* @throws IOException if the rename fails
*/
void renameFile(Location source, Location target) throws IOException;
/**
* Recursively deletes a directory and all its contents.
*
* @throws IOException if deletion fails
*/
void deleteDirectory(Location location) throws IOException;
/**
* Creates a directory (and any missing parent directories).
*
* @throws IOException if creation fails
*/
void createDirectory(Location location) throws IOException;
/**
* Renames (moves) a directory from {@code source} to {@code target}.
*
* @throws IOException if the rename fails
*/
void renameDirectory(Location source, Location target) throws IOException;
// ─────────────────────────── LISTING OPERATIONS ───────────────────────────
/**
* Returns a lazy iterator over files under {@code location}.
* <p>
* If {@code recursive} is {@code false}, only direct children are listed.
* If {@code recursive} is {@code true}, the entire subtree is traversed.
* The iterator must be closed after use (use try-with-resources).
*
* @throws IOException if the listing request fails
*/
FileIterator listFiles(Location location, boolean recursive) throws IOException;
/**
* Returns the set of direct child directory locations under {@code location}.
*
* @throws IOException if the listing request fails
*/
Set<Location> listDirectories(Location location) throws IOException;
/**
* Returns a lazy iterator of files matching the glob {@code pattern}.
* Default implementation throws {@link UnsupportedOperationException}.
* Override for native glob support (e.g., HDFS glob).
*/
default FileIterator globFiles(Location pattern) throws IOException {
throw new UnsupportedOperationException(
"globFiles not supported by " + getClass().getSimpleName());
}
/**
* Releases resources held by this filesystem (connections, thread pools, etc.).
* Idempotent — safe to call multiple times.
*/
@Override
void close() throws IOException;
}