/* * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0 * (the "License"). You may not use this work except in compliance with the License, which is * available at www.apache.org/licenses/LICENSE-2.0 * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied, as more fully set forth in the License. * * See the NOTICE file distributed with this work for information regarding copyright ownership. */ package alluxio.underfs; import alluxio.AlluxioURI; import alluxio.underfs.options.CreateOptions; import alluxio.underfs.options.DeleteOptions; import alluxio.underfs.options.FileLocationOptions; import alluxio.underfs.options.ListOptions; import alluxio.underfs.options.MkdirsOptions; import alluxio.underfs.options.OpenOptions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.List; import java.util.Map; /** * This class forwards all calls to the {@link UnderFileSystem} interface to an internal * implementation. For methods which throw an {@link IOException}, it is implied that an * interaction with the underlying storage is possible. This class logs the enter/exit of all * such methods. Methods which do not throw exceptions will not be logged. */ public class UnderFileSystemWithLogging implements UnderFileSystem { private static final Logger LOG = LoggerFactory.getLogger(UnderFileSystemWithLogging.class); private final UnderFileSystem mUnderFileSystem; /** * Creates a new {@link UnderFileSystemWithLogging} which forwards all calls to the provided * {@link UnderFileSystem} implementation. * * @param ufs the implementation which will handle all the calls */ // TODO(adit): Remove this method. ALLUXIO-2643. UnderFileSystemWithLogging(UnderFileSystem ufs) { mUnderFileSystem = ufs; } @Override public void close() throws IOException { call(new UfsCallable<Void>() { @Override public Void call() throws IOException { mUnderFileSystem.close(); return null; } @Override public String toString() { return "Close"; } }); } @Override public void configureProperties() throws IOException { call(new UfsCallable<Void>() { @Override public Void call() throws IOException { mUnderFileSystem.configureProperties(); return null; } @Override public String toString() { return "ConfigureProperties"; } }); } @Override public void connectFromMaster(final String hostname) throws IOException { call(new UfsCallable<Void>() { @Override public Void call() throws IOException { mUnderFileSystem.connectFromMaster(hostname); return null; } @Override public String toString() { return String.format("ConnectFromMaster: hostname=%s", hostname); } }); } @Override public void connectFromWorker(final String hostname) throws IOException { call(new UfsCallable<Void>() { @Override public Void call() throws IOException { mUnderFileSystem.connectFromWorker(hostname); return null; } @Override public String toString() { return String.format("ConnectFromWorker: hostname=%s", hostname); } }); } @Override public OutputStream create(final String path) throws IOException { return call(new UfsCallable<OutputStream>() { @Override public OutputStream call() throws IOException { return mUnderFileSystem.create(path); } @Override public String toString() { return String.format("Create: path=%s", path); } }); } @Override public OutputStream create(final String path, final CreateOptions options) throws IOException { return call(new UfsCallable<OutputStream>() { @Override public OutputStream call() throws IOException { return mUnderFileSystem.create(path, options); } @Override public String toString() { return String.format("Create: path=%s, options=%s", path, options); } }); } @Override public boolean deleteDirectory(final String path) throws IOException { return call(new UfsCallable<Boolean>() { @Override public Boolean call() throws IOException { return mUnderFileSystem.deleteDirectory(path); } @Override public String toString() { return String.format("DeleteDirectory: path=%s", path); } }); } @Override public boolean deleteDirectory(final String path, final DeleteOptions options) throws IOException { return call(new UfsCallable<Boolean>() { @Override public Boolean call() throws IOException { return mUnderFileSystem.deleteDirectory(path, options); } @Override public String toString() { return String.format("DeleteDirectory: path=%s, options=%s", path, options); } }); } @Override public boolean deleteFile(final String path) throws IOException { return call(new UfsCallable<Boolean>() { @Override public Boolean call() throws IOException { return mUnderFileSystem.deleteFile(path); } @Override public String toString() { return String.format("DeleteFile: path=%s", path); } }); } @Override public boolean exists(final String path) throws IOException { return call(new UfsCallable<Boolean>() { @Override public Boolean call() throws IOException { return mUnderFileSystem.exists(path); } @Override public String toString() { return String.format("Exists: path=%s", path); } }); } @Override public long getBlockSizeByte(final String path) throws IOException { return call(new UfsCallable<Long>() { @Override public Long call() throws IOException { return mUnderFileSystem.getBlockSizeByte(path); } @Override public String toString() { return String.format("GetBlockSizeByte: path=%s", path); } }); } @Override public UfsDirectoryStatus getDirectoryStatus(final String path) throws IOException { return call(new UfsCallable<UfsDirectoryStatus>() { @Override public UfsDirectoryStatus call() throws IOException { return mUnderFileSystem.getDirectoryStatus(path); } @Override public String toString() { return String.format("GetDirectoryStatus: path=%s", path); } }); } @Override public List<String> getFileLocations(final String path) throws IOException { return call(new UfsCallable<List<String>>() { @Override public List<String> call() throws IOException { return mUnderFileSystem.getFileLocations(path); } @Override public String toString() { return String.format("GetFileLocations: path=%s", path); } }); } @Override public List<String> getFileLocations(final String path, final FileLocationOptions options) throws IOException { return call(new UfsCallable<List<String>>() { @Override public List<String> call() throws IOException { return mUnderFileSystem.getFileLocations(path, options); } @Override public String toString() { return String.format("GetFileLocations: path=%s, options=%s", path, options); } }); } @Override public UfsFileStatus getFileStatus(final String path) throws IOException { return call(new UfsCallable<UfsFileStatus>() { @Override public UfsFileStatus call() throws IOException { return mUnderFileSystem.getFileStatus(path); } @Override public String toString() { return String.format("GetFileStatus: path=%s", path); } }); } @Override public Map<String, String> getProperties() { return mUnderFileSystem.getProperties(); } @Override public long getSpace(final String path, final SpaceType type) throws IOException { return call(new UfsCallable<Long>() { @Override public Long call() throws IOException { return mUnderFileSystem.getSpace(path, type); } @Override public String toString() { return String.format("GetSpace: path=%s, type=%s", path, type); } }); } @Override public String getUnderFSType() { return mUnderFileSystem.getUnderFSType(); } @Override public boolean isDirectory(final String path) throws IOException { return call(new UfsCallable<Boolean>() { @Override public Boolean call() throws IOException { return mUnderFileSystem.isDirectory(path); } @Override public String toString() { return String.format("IsDirectory: path=%s", path); } }); } @Override public boolean isFile(final String path) throws IOException { return call(new UfsCallable<Boolean>() { @Override public Boolean call() throws IOException { return mUnderFileSystem.isFile(path); } @Override public String toString() { return String.format("IsFile: path=%s", path); } }); } @Override public UfsStatus[] listStatus(final String path) throws IOException { return call(new UfsCallable<UfsStatus[]>() { @Override public UfsStatus[] call() throws IOException { return mUnderFileSystem.listStatus(path); } @Override public String toString() { return String.format("ListStatus: path=%s", path); } }); } @Override public UfsStatus[] listStatus(final String path, final ListOptions options) throws IOException { return call(new UfsCallable<UfsStatus[]>() { @Override public UfsStatus[] call() throws IOException { return mUnderFileSystem.listStatus(path, options); } @Override public String toString() { return String.format("ListStatus: path=%s, options=%s", path, options); } }); } @Override public boolean mkdirs(final String path) throws IOException { return call(new UfsCallable<Boolean>() { @Override public Boolean call() throws IOException { return mUnderFileSystem.mkdirs(path); } @Override public String toString() { return String.format("Mkdirs: path=%s", path); } }); } @Override public boolean mkdirs(final String path, final MkdirsOptions options) throws IOException { return call(new UfsCallable<Boolean>() { @Override public Boolean call() throws IOException { return mUnderFileSystem.mkdirs(path, options); } @Override public String toString() { return String.format("Mkdirs: path=%s, options=%s", path, options); } }); } @Override public InputStream open(final String path) throws IOException { return call(new UfsCallable<InputStream>() { @Override public InputStream call() throws IOException { return mUnderFileSystem.open(path); } @Override public String toString() { return String.format("Open: path=%s", path); } }); } @Override public InputStream open(final String path, final OpenOptions options) throws IOException { return call(new UfsCallable<InputStream>() { @Override public InputStream call() throws IOException { return mUnderFileSystem.open(path, options); } @Override public String toString() { return String.format("Open: path=%s, options=%s", path, options); } }); } @Override public boolean renameDirectory(final String src, final String dst) throws IOException { return call(new UfsCallable<Boolean>() { @Override public Boolean call() throws IOException { return mUnderFileSystem.renameDirectory(src, dst); } @Override public String toString() { return String.format("RenameDirectory: src=%s, dst=%s", src, dst); } }); } @Override public boolean renameFile(final String src, final String dst) throws IOException { return call(new UfsCallable<Boolean>() { @Override public Boolean call() throws IOException { return mUnderFileSystem.renameFile(src, dst); } @Override public String toString() { return String.format("RenameFile: src=%s, dst=%s", src, dst); } }); } @Override public AlluxioURI resolveUri(AlluxioURI ufsBaseUri, String alluxioPath) { return mUnderFileSystem.resolveUri(ufsBaseUri, alluxioPath); } @Override public void setOwner(final String path, final String owner, final String group) throws IOException { call(new UfsCallable<Void>() { @Override public Void call() throws IOException { mUnderFileSystem.setOwner(path, owner, group); return null; } @Override public String toString() { return String.format("SetOwner: path=%s, owner=%s, group=%s", path, owner, group); } }); } @Override public void setProperties(Map<String, String> properties) { mUnderFileSystem.setProperties(properties); } @Override public void setMode(final String path, final short mode) throws IOException { call(new UfsCallable<Void>() { @Override public Void call() throws IOException { mUnderFileSystem.setMode(path, mode); return null; } @Override public String toString() { return String.format("SetMode: path=%s, mode=%s", path, mode); } }); } @Override public boolean supportsFlush() { return mUnderFileSystem.supportsFlush(); } /** * This is only used in the test. * * @return the underlying {@link UnderFileSystem} */ public UnderFileSystem getUnderFileSystem() { return mUnderFileSystem; } /** * Interface representing a callable to the under storage system which throws an * {@link IOException} if an error occurs during the external communication. * * @param <T> the return type of the callable */ public interface UfsCallable<T> { /** * Executes the call. * * @return the result of the call */ T call() throws IOException; } /** * A wrapper for invoking an {@link UfsCallable} with enter/exit point logging. * * @param callable the callable to invoke * @param <T> the return type * @return the result of the callable */ private <T> T call(UfsCallable<T> callable) throws IOException { LOG.debug("Enter: {}", callable); try { T ret = callable.call(); LOG.debug("Exit (OK): {}", callable); return ret; } catch (IOException e) { LOG.debug("Exit (Error): {}, Error={}", callable, e.getMessage()); throw e; } } }