Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -551,14 +551,81 @@ public void deleteSnapshot(String volumeName,

/**
* List snapshots in a volume/bucket.
* @param volumeName volume name
* @param bucketName bucket name
* @return list of snapshots for volume/bucket snapshotpath.
* @param volumeName volume name
* @param bucketName bucket name
* @param snapshotPrefix snapshot prefix to match
* @param prevSnapshot snapshots will be listed after this snapshot name
* @throws IOException
*/
public List<OzoneSnapshot> listSnapshot(String volumeName, String bucketName)
throws IOException {
return proxy.listSnapshot(volumeName, bucketName);
public Iterator<? extends OzoneSnapshot> listSnapshot(
String volumeName, String bucketName, String snapshotPrefix,
String prevSnapshot) throws IOException {
return new SnapshotIterator(
volumeName, bucketName, snapshotPrefix, prevSnapshot);
}

/**
* An Iterator to iterate over {@link OzoneSnapshot} list.
*/
private class SnapshotIterator implements Iterator<OzoneSnapshot> {

private String volumeName = null;
private String bucketName = null;
private String snapshotPrefix = null;

private Iterator<OzoneSnapshot> currentIterator;
private OzoneSnapshot currentValue;

/**
* Creates an Iterator to iterate over all snapshots after
* prevSnapshot of specified bucket. If prevSnapshot is null it iterates
* from the first snapshot. The returned snapshots match snapshot prefix.
* @param snapshotPrefix snapshot prefix to match
* @param prevSnapshot snapshots will be listed after this snapshot name
*/
SnapshotIterator(String volumeName, String bucketName,
String snapshotPrefix, String prevSnapshot) {
this.volumeName = volumeName;
this.bucketName = bucketName;
this.snapshotPrefix = snapshotPrefix;
this.currentValue = null;
this.currentIterator = getNextListOfSnapshots(prevSnapshot).iterator();
}

@Override
public boolean hasNext() {
// IMPORTANT: Without this logic, remote iteration will not work.
// Removing this will break the listSnapshot call if we try to
// list more than 1000 (ozone.client.list.cache ) snapshots.
if (!currentIterator.hasNext() && currentValue != null) {
currentIterator = getNextListOfSnapshots(currentValue.getName())
.iterator();
}
return currentIterator.hasNext();
}

@Override
public OzoneSnapshot next() {
if (hasNext()) {
currentValue = currentIterator.next();
return currentValue;
}
throw new NoSuchElementException();
}

/**
* Returns the next set of snapshot list using proxy.
* @param prevSnapshot previous snapshot, this will be excluded from result
* @return {@code List<OzoneSnapshot>}
*/
private List<OzoneSnapshot> getNextListOfSnapshots(String prevSnapshot) {
try {
return proxy.listSnapshot(volumeName, bucketName, snapshotPrefix,
prevSnapshot, listCacheSize);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

public SnapshotDiffReport snapshotDiff(String volumeName, String bucketName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1042,13 +1042,17 @@ void deleteSnapshot(String volumeName,

/**
* List snapshots in a volume/bucket.
* @param volumeName volume name
* @param bucketName bucket name
* @param volumeName volume name
* @param bucketName bucket name
* @param snapshotPrefix snapshot prefix to match
* @param prevSnapshot start of the list, this snapshot is excluded
* @param maxListResult max numbet of snapshots to return
* @return list of snapshots for volume/bucket snapshotpath.
* @throws IOException
*/
List<OzoneSnapshot> listSnapshot(String volumeName, String bucketName)
throws IOException;
List<OzoneSnapshot> listSnapshot(
String volumeName, String bucketName, String snapshotPrefix,
String prevSnapshot, int maxListResult) throws IOException;


/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -985,19 +985,24 @@ public SnapshotDiffReport snapshotDiff(String volumeName, String bucketName,

/**
* List snapshots in a volume/bucket.
* @param volumeName volume name
* @param bucketName bucket name
* @param volumeName volume name
* @param bucketName bucket name
* @param snapshotPrefix snapshot prefix to match
* @param prevSnapshot start of the list, this snapshot is excluded
* @param maxListResult max numbet of snapshots to return
* @return list of snapshots for volume/bucket snapshotpath.
* @throws IOException
*/
@Override
public List<OzoneSnapshot> listSnapshot(String volumeName, String bucketName)
throws IOException {
public List<OzoneSnapshot> listSnapshot(
String volumeName, String bucketName, String snapshotPrefix,
String prevSnapshot, int maxListResult) throws IOException {
Preconditions.checkArgument(Strings.isNotBlank(volumeName),
"volume can't be null or empty.");
Preconditions.checkArgument(Strings.isNotBlank(bucketName),
"bucket can't be null or empty.");
return ozoneManagerClient.listSnapshot(volumeName, bucketName).stream()
return ozoneManagerClient.listSnapshot(volumeName, bucketName,
snapshotPrefix, prevSnapshot, maxListResult).stream()
.map(snapshotInfo -> OzoneSnapshot.fromSnapshotInfo(snapshotInfo))
.collect(Collectors.toList());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -664,13 +664,17 @@ default void deleteSnapshot(String volumeName,

/**
* List snapshots in a volume/bucket.
* @param volumeName volume name
* @param bucketName bucket name
* @param volumeName volume name
* @param bucketName bucket name
* @param snapshotPrefix snapshot prefix to match
* @param prevSnapshot start of the list, this snapshot is excluded
* @param maxListResult max numbet of snapshots to return
* @return list of snapshots for volume/bucket snapshotpath.
* @throws IOException
*/
default List<SnapshotInfo> listSnapshot(String volumeName, String bucketName)
throws IOException {
default List<SnapshotInfo> listSnapshot(
String volumeName, String bucketName, String snapshotPrefix,
String prevSnapshot, int maxListResult) throws IOException {
throw new UnsupportedOperationException("OzoneManager does not require " +
"this to be implemented");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1153,13 +1153,23 @@ public void deleteSnapshot(String volumeName,
* {@inheritDoc}
*/
@Override
public List<SnapshotInfo> listSnapshot(String volumeName, String bucketName)
throws IOException {
public List<SnapshotInfo> listSnapshot(
String volumeName, String bucketName, String snapshotPrefix,
String prevSnapshot, int maxListResult) throws IOException {
final OzoneManagerProtocolProtos.ListSnapshotRequest.Builder
requestBuilder =
OzoneManagerProtocolProtos.ListSnapshotRequest.newBuilder()
.setVolumeName(volumeName)
.setBucketName(bucketName);
.setBucketName(bucketName)
.setMaxListResult(maxListResult);

if (prevSnapshot != null) {
requestBuilder.setPrevSnapshot(prevSnapshot);
}

if (snapshotPrefix != null) {
requestBuilder.setPrefix(snapshotPrefix);
}

final OMRequest omRequest = createOMRequest(Type.ListSnapshot)
.setListSnapshotRequest(requestBuilder)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
import org.apache.hadoop.ozone.client.OzoneKeyDetails;
import org.apache.hadoop.ozone.client.OzoneKeyLocation;
import org.apache.hadoop.ozone.client.OzoneMultipartUploadPartListParts;
import org.apache.hadoop.ozone.client.OzoneSnapshot;
import org.apache.hadoop.ozone.client.OzoneVolume;
import org.apache.hadoop.ozone.client.VolumeArgs;
import org.apache.hadoop.ozone.client.io.OzoneInputStream;
Expand Down Expand Up @@ -4117,4 +4118,86 @@ private OzoneBucket getBucket(OzoneVolume volume) throws IOException {
private static ReplicationConfig anyReplication() {
return RatisReplicationConfig.getInstance(HddsProtos.ReplicationFactor.ONE);
}

@Test
public void testListSnapshot() throws IOException {
String volumeA = "vol-a-" + RandomStringUtils.randomNumeric(5);
String volumeB = "vol-b-" + RandomStringUtils.randomNumeric(5);
String bucketA = "buc-a-" + RandomStringUtils.randomNumeric(5);
String bucketB = "buc-b-" + RandomStringUtils.randomNumeric(5);
store.createVolume(volumeA);
store.createVolume(volumeB);
OzoneVolume volA = store.getVolume(volumeA);
OzoneVolume volB = store.getVolume(volumeB);
volA.createBucket(bucketA);
volA.createBucket(bucketB);
volB.createBucket(bucketA);
volB.createBucket(bucketB);
String snapshotPrefixA = "snapshot-a-";
String snapshotPrefixB = "snapshot-b-";
for (int i = 0; i < 10; i++) {
store.createSnapshot(volumeA, bucketA,
snapshotPrefixA + i + "-" + RandomStringUtils.randomNumeric(5));
store.createSnapshot(volumeA, bucketB,
snapshotPrefixA + i + "-" + RandomStringUtils.randomNumeric(5));
store.createSnapshot(volumeB, bucketA,
snapshotPrefixA + i + "-" + RandomStringUtils.randomNumeric(5));
store.createSnapshot(volumeB, bucketB,
snapshotPrefixA + i + "-" + RandomStringUtils.randomNumeric(5));
}
for (int i = 0; i < 10; i++) {
store.createSnapshot(volumeA, bucketA,
snapshotPrefixB + i + "-" + RandomStringUtils.randomNumeric(5));
store.createSnapshot(volumeA, bucketB,
snapshotPrefixB + i + "-" + RandomStringUtils.randomNumeric(5));
store.createSnapshot(volumeB, bucketA,
snapshotPrefixB + i + "-" + RandomStringUtils.randomNumeric(5));
store.createSnapshot(volumeB, bucketB,
snapshotPrefixB + i + "-" + RandomStringUtils.randomNumeric(5));
}

Iterator<? extends OzoneSnapshot> snapshotIter =
store.listSnapshot(volumeA, bucketA, null, null);
int volABucketASnapshotCount = 0;
while (snapshotIter.hasNext()) {
OzoneSnapshot snapshot = snapshotIter.next();
volABucketASnapshotCount++;
}
Assert.assertEquals(20, volABucketASnapshotCount);

snapshotIter = store.listSnapshot(volumeA, bucketB, null, null);
int volABucketBSnapshotCount = 0;
while (snapshotIter.hasNext()) {
OzoneSnapshot snapshot = snapshotIter.next();
volABucketBSnapshotCount++;
}
Assert.assertEquals(20, volABucketASnapshotCount);

snapshotIter = store.listSnapshot(volumeB, bucketA, null, null);
int volBBucketASnapshotCount = 0;
while (snapshotIter.hasNext()) {
OzoneSnapshot snapshot = snapshotIter.next();
volBBucketASnapshotCount++;
}
Assert.assertEquals(20, volABucketASnapshotCount);

snapshotIter = store.listSnapshot(volumeB, bucketB, null, null);
int volBBucketBSnapshotCount = 0;
while (snapshotIter.hasNext()) {
OzoneSnapshot snapshot = snapshotIter.next();
volBBucketBSnapshotCount++;
}
Assert.assertEquals(20, volABucketASnapshotCount);

int volABucketASnapshotACount = 0;
snapshotIter = store.listSnapshot(volumeA, bucketA, snapshotPrefixA, null);
while (snapshotIter.hasNext()) {
OzoneSnapshot snapshot = snapshotIter.next();
Assert.assertTrue(snapshot.getName().startsWith(snapshotPrefixA));
volABucketASnapshotACount++;
}
Assert.assertEquals(10, volABucketASnapshotACount);
Assert.assertFalse(snapshotIter.hasNext());

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,8 @@ public void testSnapshotOps() throws Exception {
writeClient.createSnapshot(volumeName, bucketName, snapshot2);

// List snapshots
writeClient.listSnapshot(volumeName, bucketName);
writeClient.listSnapshot(
volumeName, bucketName, null, null, Integer.MAX_VALUE);

omMetrics = getMetrics("OMMetrics");
assertCounter("NumSnapshotActive", 2L, omMetrics);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1674,6 +1674,9 @@ message CreateSnapshotRequest {
message ListSnapshotRequest {
optional string volumeName = 1;
optional string bucketName = 2;
optional string prefix = 3;
optional string prevSnapshot = 4;
optional uint32 maxListResult = 5;
}

message SnapshotDiffRequest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,12 +224,16 @@ List<RepeatedOmKeyInfo> listTrash(String volumeName, String bucketName,

/**
* List snapshots in a volume/bucket.
* @param volumeName volume name
* @param bucketName bucket name
* @param volumeName volume name
* @param bucketName bucket name
* @param snapshotPrefix snapshot prefix to match
* @param prevSnapshot start of the list, this snapshot is excluded
* @param maxListResult max numbet of snapshots to return
* @return list of snapshot
*/
List<SnapshotInfo> listSnapshot(String volumeName, String bucketName)
throws IOException;
List<SnapshotInfo> listSnapshot(
String volumeName, String bucketName, String snapshotPrefix,
String prevSnapshot, int maxListResult) throws IOException;

/**
* Recover trash allows the user to recover the keys
Expand Down
Loading