|
@@ -50,6 +50,7 @@ import java.util.NoSuchElementException;
|
|
import java.util.concurrent.CompletableFuture;
|
|
import java.util.concurrent.CompletableFuture;
|
|
import java.util.StringJoiner;
|
|
import java.util.StringJoiner;
|
|
|
|
|
|
|
|
+import static org.apache.hadoop.fs.s3a.Constants.S3N_FOLDER_SUFFIX;
|
|
import static org.apache.hadoop.fs.s3a.Invoker.onceInTheFuture;
|
|
import static org.apache.hadoop.fs.s3a.Invoker.onceInTheFuture;
|
|
import static org.apache.hadoop.fs.s3a.S3AUtils.createFileStatus;
|
|
import static org.apache.hadoop.fs.s3a.S3AUtils.createFileStatus;
|
|
import static org.apache.hadoop.fs.s3a.S3AUtils.maybeAddTrailingSlash;
|
|
import static org.apache.hadoop.fs.s3a.S3AUtils.maybeAddTrailingSlash;
|
|
@@ -74,6 +75,9 @@ public class Listing extends AbstractStoreOperation {
|
|
|
|
|
|
private static final Logger LOG = S3AFileSystem.LOG;
|
|
private static final Logger LOG = S3AFileSystem.LOG;
|
|
|
|
|
|
|
|
+ static final FileStatusAcceptor ACCEPT_ALL_BUT_S3N =
|
|
|
|
+ new AcceptAllButS3nDirs();
|
|
|
|
+
|
|
static final FileStatusAcceptor ACCEPT_ALL_OBJECTS =
|
|
static final FileStatusAcceptor ACCEPT_ALL_OBJECTS =
|
|
new AcceptAllObjects();
|
|
new AcceptAllObjects();
|
|
|
|
|
|
@@ -114,7 +118,7 @@ public class Listing extends AbstractStoreOperation {
|
|
S3AFileStatus[] fileStatuses) {
|
|
S3AFileStatus[] fileStatuses) {
|
|
return filteringRemoteIterator(
|
|
return filteringRemoteIterator(
|
|
remoteIteratorFromArray(fileStatuses),
|
|
remoteIteratorFromArray(fileStatuses),
|
|
- Listing.ACCEPT_ALL_OBJECTS::accept);
|
|
|
|
|
|
+ Listing.ACCEPT_ALL_BUT_S3N::accept);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -233,7 +237,7 @@ public class Listing extends AbstractStoreOperation {
|
|
listingOperationCallbacks
|
|
listingOperationCallbacks
|
|
.createListObjectsRequest(key, "/", span),
|
|
.createListObjectsRequest(key, "/", span),
|
|
filter,
|
|
filter,
|
|
- new AcceptAllButSelf(dir),
|
|
|
|
|
|
+ new AcceptAllButSelfAndS3nDirs(dir),
|
|
span));
|
|
span));
|
|
}
|
|
}
|
|
|
|
|
|
@@ -262,7 +266,7 @@ public class Listing extends AbstractStoreOperation {
|
|
path,
|
|
path,
|
|
request,
|
|
request,
|
|
S3AUtils.ACCEPT_ALL,
|
|
S3AUtils.ACCEPT_ALL,
|
|
- new AcceptAllButSelf(path),
|
|
|
|
|
|
+ new AcceptAllButSelfAndS3nDirs(path),
|
|
span);
|
|
span);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -460,7 +464,7 @@ public class Listing extends AbstractStoreOperation {
|
|
if (LOG.isDebugEnabled()) {
|
|
if (LOG.isDebugEnabled()) {
|
|
LOG.debug("{}: {}", keyPath, stringify(s3Object));
|
|
LOG.debug("{}: {}", keyPath, stringify(s3Object));
|
|
}
|
|
}
|
|
- // Skip over keys that are ourselves
|
|
|
|
|
|
+ // Skip over keys that are ourselves and old S3N _$folder$ files
|
|
if (acceptor.accept(keyPath, s3Object) && filter.accept(keyPath)) {
|
|
if (acceptor.accept(keyPath, s3Object) && filter.accept(keyPath)) {
|
|
S3AFileStatus status = createFileStatus(keyPath, s3Object,
|
|
S3AFileStatus status = createFileStatus(keyPath, s3Object,
|
|
blockSize, userName, s3Object.eTag(),
|
|
blockSize, userName, s3Object.eTag(),
|
|
@@ -720,7 +724,8 @@ public class Listing extends AbstractStoreOperation {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Accept all entries except the base path.
|
|
|
|
|
|
+ * Accept all entries except the base path and those which map to S3N
|
|
|
|
+ * pseudo directory markers.
|
|
*/
|
|
*/
|
|
static class AcceptFilesOnly implements FileStatusAcceptor {
|
|
static class AcceptFilesOnly implements FileStatusAcceptor {
|
|
private final Path qualifiedPath;
|
|
private final Path qualifiedPath;
|
|
@@ -740,6 +745,7 @@ public class Listing extends AbstractStoreOperation {
|
|
@Override
|
|
@Override
|
|
public boolean accept(Path keyPath, S3Object s3Object) {
|
|
public boolean accept(Path keyPath, S3Object s3Object) {
|
|
return !keyPath.equals(qualifiedPath)
|
|
return !keyPath.equals(qualifiedPath)
|
|
|
|
+ && !s3Object.key().endsWith(S3N_FOLDER_SUFFIX)
|
|
&& !objectRepresentsDirectory(s3Object.key());
|
|
&& !objectRepresentsDirectory(s3Object.key());
|
|
}
|
|
}
|
|
|
|
|
|
@@ -760,6 +766,25 @@ public class Listing extends AbstractStoreOperation {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Accept all entries except those which map to S3N pseudo directory markers.
|
|
|
|
+ */
|
|
|
|
+ static class AcceptAllButS3nDirs implements FileStatusAcceptor {
|
|
|
|
+
|
|
|
|
+ public boolean accept(Path keyPath, S3Object s3Object) {
|
|
|
|
+ return !s3Object.key().endsWith(S3N_FOLDER_SUFFIX);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public boolean accept(Path keyPath, String prefix) {
|
|
|
|
+ return !keyPath.toString().endsWith(S3N_FOLDER_SUFFIX);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public boolean accept(FileStatus status) {
|
|
|
|
+ return !status.getPath().toString().endsWith(S3N_FOLDER_SUFFIX);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Accept all entries.
|
|
* Accept all entries.
|
|
*/
|
|
*/
|
|
@@ -779,6 +804,55 @@ public class Listing extends AbstractStoreOperation {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Accept all entries except the base path and those which map to S3N
|
|
|
|
+ * pseudo directory markers.
|
|
|
|
+ */
|
|
|
|
+ public static class AcceptAllButSelfAndS3nDirs implements FileStatusAcceptor {
|
|
|
|
+
|
|
|
|
+ /** Base path. */
|
|
|
|
+ private final Path qualifiedPath;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Constructor.
|
|
|
|
+ * @param qualifiedPath an already-qualified path.
|
|
|
|
+ */
|
|
|
|
+ public AcceptAllButSelfAndS3nDirs(Path qualifiedPath) {
|
|
|
|
+ this.qualifiedPath = qualifiedPath;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Reject a s3Object entry if the key path is the qualified Path, or
|
|
|
|
+ * it ends with {@code "_$folder$"}.
|
|
|
|
+ * @param keyPath key path of the entry
|
|
|
|
+ * @param s3Object s3Object entry
|
|
|
|
+ * @return true if the entry is accepted (i.e. that a status entry
|
|
|
|
+ * should be generated.)
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public boolean accept(Path keyPath, S3Object s3Object) {
|
|
|
|
+ return !keyPath.equals(qualifiedPath) &&
|
|
|
|
+ !s3Object.key().endsWith(S3N_FOLDER_SUFFIX);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Accept all prefixes except the one for the base path, "self".
|
|
|
|
+ * @param keyPath qualified path to the entry
|
|
|
|
+ * @param prefix common prefix in listing.
|
|
|
|
+ * @return true if the entry is accepted (i.e. that a status entry
|
|
|
|
+ * should be generated.
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public boolean accept(Path keyPath, String prefix) {
|
|
|
|
+ return !keyPath.equals(qualifiedPath);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean accept(FileStatus status) {
|
|
|
|
+ return (status != null) && !status.getPath().equals(qualifiedPath);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Accept all entries except the base path.
|
|
* Accept all entries except the base path.
|
|
*/
|
|
*/
|