HADOOP-15106. FileSystem::open(PathHandle) should throw a specific exception on validation failure

This commit is contained in:
Chris Douglas 2017-12-16 10:53:10 -08:00
parent fc7ec80d85
commit 5e81f32d11
6 changed files with 67 additions and 13 deletions

View File

@ -957,6 +957,8 @@ public abstract class FileSystem extends Configured implements Closeable {
* resource directly and verify that the resource referenced * resource directly and verify that the resource referenced
* satisfies constraints specified at its construciton. * satisfies constraints specified at its construciton.
* @param fd PathHandle object returned by the FS authority. * @param fd PathHandle object returned by the FS authority.
* @throws InvalidPathHandleException If {@link PathHandle} constraints are
* not satisfied
* @throws IOException IO failure * @throws IOException IO failure
* @throws UnsupportedOperationException If {@link #open(PathHandle, int)} * @throws UnsupportedOperationException If {@link #open(PathHandle, int)}
* not overridden by subclass * not overridden by subclass
@ -973,6 +975,8 @@ public abstract class FileSystem extends Configured implements Closeable {
* satisfies constraints specified at its construciton. * satisfies constraints specified at its construciton.
* @param fd PathHandle object returned by the FS authority. * @param fd PathHandle object returned by the FS authority.
* @param bufferSize the size of the buffer to use * @param bufferSize the size of the buffer to use
* @throws InvalidPathHandleException If {@link PathHandle} constraints are
* not satisfied
* @throws IOException IO failure * @throws IOException IO failure
* @throws UnsupportedOperationException If not overridden by subclass * @throws UnsupportedOperationException If not overridden by subclass
*/ */
@ -994,6 +998,8 @@ public abstract class FileSystem extends Configured implements Closeable {
* the specified constraints. * the specified constraints.
*/ */
public final PathHandle getPathHandle(FileStatus stat, HandleOpt... opt) { public final PathHandle getPathHandle(FileStatus stat, HandleOpt... opt) {
// method is final with a default so clients calling getPathHandle(stat)
// get the same semantics for all FileSystem implementations
if (null == opt || 0 == opt.length) { if (null == opt || 0 == opt.length) {
return createPathHandle(stat, HandleOpt.path()); return createPathHandle(stat, HandleOpt.path());
} }

View File

@ -0,0 +1,46 @@
/**
* 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.hadoop.fs;
import java.io.IOException;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
/**
* Thrown when the constraints enoded in a {@link PathHandle} do not hold.
* For example, if a handle were created with the default
* {@link Options.HandleOpt#path()} constraints, a call to
* {@link FileSystem#open(PathHandle)} would succeed if the file were
* modified, but if a different file was at that location then it would throw
* this exception.
*/
@InterfaceAudience.Public
@InterfaceStability.Stable
public class InvalidPathHandleException extends IOException {
private static final long serialVersionUID = 0xcd8ac329L;
public InvalidPathHandleException(String str) {
super(str);
}
public InvalidPathHandleException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -790,7 +790,7 @@ Implementaions without a compliant call MUST throw `UnsupportedOperationExceptio
(FS.Directories', FS.Files', FS.Symlinks') (FS.Directories', FS.Files', FS.Symlinks')
p' in FS.Files' where: p' in FS.Files' where:
FS.Files'[p'] = fd FS.Files'[p'] = fd
if not exists(FS', p') : raise FileNotFoundException if not exists(FS', p') : raise InvalidPathHandleException
The implementation MUST resolve the referent of the `PathHandle` following The implementation MUST resolve the referent of the `PathHandle` following
the constraints specified at its creation by `getPathHandle(FileStatus)`. the constraints specified at its creation by `getPathHandle(FileStatus)`.

View File

@ -26,6 +26,7 @@ import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.CommonConfigurationKeysPublic; import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.InvalidPathHandleException;
import org.apache.hadoop.fs.Options.HandleOpt; import org.apache.hadoop.fs.Options.HandleOpt;
import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.PathHandle; import org.apache.hadoop.fs.PathHandle;
@ -241,7 +242,7 @@ public abstract class AbstractContractOpenTest
// fail to resolve if path1 had been modified // fail to resolve if path1 had been modified
instream = getFileSystem().open(fd1); instream = getFileSystem().open(fd1);
fail("Expected an exception"); fail("Expected an exception");
} catch (IOException e) { } catch (InvalidPathHandleException e) {
// expected // expected
} }
@ -290,7 +291,7 @@ public abstract class AbstractContractOpenTest
// handle should not resolve when content changed // handle should not resolve when content changed
instream = getFileSystem().open(fd); instream = getFileSystem().open(fd);
fail("Failed to detect change to content"); fail("Failed to detect change to content");
} catch (IOException e) { } catch (InvalidPathHandleException e) {
// expected // expected
} }
} }
@ -330,7 +331,7 @@ public abstract class AbstractContractOpenTest
// verify attempt to resolve the handle fails // verify attempt to resolve the handle fails
instream = getFileSystem().open(fd1); instream = getFileSystem().open(fd1);
fail("Expected an exception"); fail("Expected an exception");
} catch (IOException e) { } catch (InvalidPathHandleException e) {
// expected // expected
} }

View File

@ -46,6 +46,7 @@ import org.apache.hadoop.fs.FsServerDefaults;
import org.apache.hadoop.fs.FsStatus; import org.apache.hadoop.fs.FsStatus;
import org.apache.hadoop.fs.GlobalStorageStatistics; import org.apache.hadoop.fs.GlobalStorageStatistics;
import org.apache.hadoop.fs.GlobalStorageStatistics.StorageStatisticsProvider; import org.apache.hadoop.fs.GlobalStorageStatistics.StorageStatisticsProvider;
import org.apache.hadoop.fs.InvalidPathHandleException;
import org.apache.hadoop.fs.PathHandle; import org.apache.hadoop.fs.PathHandle;
import org.apache.hadoop.fs.LocatedFileStatus; import org.apache.hadoop.fs.LocatedFileStatus;
import org.apache.hadoop.fs.Options; import org.apache.hadoop.fs.Options;
@ -336,6 +337,8 @@ public class DistributedFileSystem extends FileSystem
* the {@link PathHandle}. * the {@link PathHandle}.
* @param fd Reference to entity in this FileSystem. * @param fd Reference to entity in this FileSystem.
* @param bufferSize the size of the buffer to be used. * @param bufferSize the size of the buffer to be used.
* @throws InvalidPathHandleException If PathHandle constraints do not hold
* @throws IOException On I/O errors
*/ */
@Override @Override
public FSDataInputStream open(PathHandle fd, int bufferSize) public FSDataInputStream open(PathHandle fd, int bufferSize)

View File

@ -23,6 +23,7 @@ import java.util.Optional;
import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.fs.InvalidPathHandleException;
import org.apache.hadoop.fs.PathHandle; import org.apache.hadoop.fs.PathHandle;
import org.apache.hadoop.hdfs.protocol.proto.HdfsProtos.HdfsPathHandleProto; import org.apache.hadoop.hdfs.protocol.proto.HdfsProtos.HdfsPathHandleProto;
@ -55,24 +56,21 @@ public final class HdfsPathHandle implements PathHandle {
HdfsPathHandleProto p = HdfsPathHandleProto p =
HdfsPathHandleProto.parseFrom(ByteString.copyFrom(bytes)); HdfsPathHandleProto.parseFrom(ByteString.copyFrom(bytes));
path = p.getPath(); path = p.getPath();
mtime = p.hasMtime() mtime = p.hasMtime() ? p.getMtime() : null;
? p.getMtime() inodeId = p.hasInodeId() ? p.getInodeId() : null;
: null;
inodeId = p.hasInodeId()
? p.getInodeId()
: null;
} }
public String getPath() { public String getPath() {
return path; return path;
} }
public void verify(HdfsLocatedFileStatus stat) throws IOException { public void verify(HdfsLocatedFileStatus stat)
throws InvalidPathHandleException {
if (mtime != null && mtime != stat.getModificationTime()) { if (mtime != null && mtime != stat.getModificationTime()) {
throw new IOException("Content changed"); throw new InvalidPathHandleException("Content changed");
} }
if (inodeId != null && inodeId != stat.getFileId()) { if (inodeId != null && inodeId != stat.getFileId()) {
throw new IOException("Wrong file"); throw new InvalidPathHandleException("Wrong file");
} }
} }