/* * 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.ignite.internal.processors.hadoop.impl.fs; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FileAlreadyExistsException; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.FsConstants; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.PositionedReadable; import org.apache.hadoop.fs.Seekable; import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.util.Progressable; import org.apache.ignite.internal.util.typedef.internal.U; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.URI; import java.nio.file.Files; /** * Local file system implementation for Hadoop. */ public class HadoopRawLocalFileSystem extends FileSystem { /** Working directory for each thread. */ private final ThreadLocal<Path> workDir = new ThreadLocal<Path>() { @Override protected Path initialValue() { return getInitialWorkingDirectory(); } }; /** * Converts Hadoop path to local path. * * @param path Hadoop path. * @return Local path. */ File convert(Path path) { checkPath(path); if (path.isAbsolute()) return new File(path.toUri().getPath()); return new File(getWorkingDirectory().toUri().getPath(), path.toUri().getPath()); } /** {@inheritDoc} */ @Override public Path getHomeDirectory() { return makeQualified(new Path(System.getProperty("user.home"))); } /** {@inheritDoc} */ @Override public Path getInitialWorkingDirectory() { File f = new File(System.getProperty("user.dir")); return new Path(f.getAbsoluteFile().toURI()).makeQualified(getUri(), null); } /** {@inheritDoc} */ @Override public void initialize(URI uri, Configuration conf) throws IOException { super.initialize(uri, conf); setConf(conf); String initWorkDir = conf.get(HadoopFileSystemsUtils.LOC_FS_WORK_DIR_PROP); if (initWorkDir != null) setWorkingDirectory(new Path(initWorkDir)); } /** {@inheritDoc} */ @Override public URI getUri() { return FsConstants.LOCAL_FS_URI; } /** {@inheritDoc} */ @Override public FSDataInputStream open(Path f, int bufferSize) throws IOException { return new FSDataInputStream(new InStream(checkExists(convert(f)))); } /** {@inheritDoc} */ @Override public FSDataOutputStream create(Path f, FsPermission permission, boolean overwrite, int bufSize, short replication, long blockSize, Progressable progress) throws IOException { File file = convert(f); if (!overwrite && !file.createNewFile()) throw new IOException("Failed to create new file: " + f.toUri()); return out(file, false, bufSize); } /** * @param file File. * @param append Append flag. * @return Output stream. * @throws IOException If failed. */ private FSDataOutputStream out(File file, boolean append, int bufSize) throws IOException { return new FSDataOutputStream(new BufferedOutputStream(new FileOutputStream(file, append), bufSize < 32 * 1024 ? 32 * 1024 : bufSize), new Statistics(getUri().getScheme())); } /** {@inheritDoc} */ @Override public FSDataOutputStream append(Path f, int bufSize, Progressable progress) throws IOException { return out(convert(f), true, bufSize); } /** {@inheritDoc} */ @Override public boolean rename(Path src, Path dst) throws IOException { return convert(src).renameTo(convert(dst)); } /** {@inheritDoc} */ @Override public boolean delete(Path f, boolean recursive) throws IOException { File file = convert(f); if (file.isDirectory() && !recursive) throw new IOException("Failed to remove directory in non recursive mode: " + f.toUri()); return U.delete(file); } /** {@inheritDoc} */ @Override public void setWorkingDirectory(Path dir) { workDir.set(fixRelativePart(dir)); checkPath(dir); } /** {@inheritDoc} */ @Override public Path getWorkingDirectory() { return workDir.get(); } /** {@inheritDoc} */ @Override public boolean mkdirs(Path f, FsPermission permission) throws IOException { if(f == null) throw new IllegalArgumentException("mkdirs path arg is null"); Path parent = f.getParent(); File p2f = convert(f); if(parent != null) { File parent2f = convert(parent); if(parent2f != null && parent2f.exists() && !parent2f.isDirectory()) throw new FileAlreadyExistsException("Parent path is not a directory: " + parent); } return (parent == null || mkdirs(parent)) && (p2f.mkdir() || p2f.isDirectory()); } /** {@inheritDoc} */ @Override public FileStatus getFileStatus(Path f) throws IOException { return fileStatus(checkExists(convert(f))); } /** * @return File status. */ private FileStatus fileStatus(File file) throws IOException { boolean dir = file.isDirectory(); java.nio.file.Path path = dir ? null : file.toPath(); return new FileStatus(dir ? 0 : file.length(), dir, 1, 4 * 1024, file.lastModified(), file.lastModified(), /*permission*/null, /*owner*/null, /*group*/null, dir ? null : Files.isSymbolicLink(path) ? new Path(Files.readSymbolicLink(path).toUri()) : null, new Path(file.toURI())); } /** * @param file File. * @return Same file. * @throws FileNotFoundException If does not exist. */ private static File checkExists(File file) throws FileNotFoundException { if (!file.exists()) throw new FileNotFoundException("File " + file.getAbsolutePath() + " does not exist."); return file; } /** {@inheritDoc} */ @Override public FileStatus[] listStatus(Path f) throws IOException { File file = convert(f); if (checkExists(file).isFile()) return new FileStatus[] {fileStatus(file)}; File[] files = file.listFiles(); FileStatus[] res = new FileStatus[files.length]; for (int i = 0; i < res.length; i++) res[i] = fileStatus(files[i]); return res; } /** {@inheritDoc} */ @Override public boolean supportsSymlinks() { return true; } /** {@inheritDoc} */ @Override public void createSymlink(Path target, Path link, boolean createParent) throws IOException { Files.createSymbolicLink(convert(link).toPath(), convert(target).toPath()); } /** {@inheritDoc} */ @Override public FileStatus getFileLinkStatus(Path f) throws IOException { return getFileStatus(getLinkTarget(f)); } /** {@inheritDoc} */ @Override public Path getLinkTarget(Path f) throws IOException { File file = Files.readSymbolicLink(convert(f).toPath()).toFile(); return new Path(file.toURI()); } /** * Input stream. */ private static class InStream extends InputStream implements Seekable, PositionedReadable { /** */ private final RandomAccessFile file; /** * @param f File. * @throws IOException If failed. */ public InStream(File f) throws IOException { file = new RandomAccessFile(f, "r"); } /** {@inheritDoc} */ @Override public synchronized int read() throws IOException { return file.read(); } /** {@inheritDoc} */ @Override public synchronized int read(byte[] b, int off, int len) throws IOException { return file.read(b, off, len); } /** {@inheritDoc} */ @Override public synchronized void close() throws IOException { file.close(); } /** {@inheritDoc} */ @Override public synchronized int read(long pos, byte[] buf, int off, int len) throws IOException { long pos0 = file.getFilePointer(); file.seek(pos); int res = file.read(buf, off, len); file.seek(pos0); return res; } /** {@inheritDoc} */ @Override public void readFully(long pos, byte[] buf, int off, int len) throws IOException { if (read(pos, buf, off, len) != len) throw new IOException(); } /** {@inheritDoc} */ @Override public void readFully(long pos, byte[] buf) throws IOException { readFully(pos, buf, 0, buf.length); } /** {@inheritDoc} */ @Override public synchronized void seek(long pos) throws IOException { file.seek(pos); } /** {@inheritDoc} */ @Override public synchronized long getPos() throws IOException { return file.getFilePointer(); } /** {@inheritDoc} */ @Override public boolean seekToNewSource(long targetPos) throws IOException { return false; } } }