Skip to content

Commit 348d4f4

Browse files
authored
HDDS-14467. Expose pending delete bytes/namespace in OzoneBucket (#9708)
1 parent 94a4014 commit 348d4f4

3 files changed

Lines changed: 102 additions & 0 deletions

File tree

hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/OzoneBucket.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,14 @@ public class OzoneBucket extends WithMetadata {
151151
* Bucket Owner.
152152
*/
153153
private String owner;
154+
/**
155+
* Pending deletion bytes (Includes bytes retained by snapshots).
156+
*/
157+
private long pendingDeleteBytes;
158+
/**
159+
* Pending deletion namespace (Includes keys retained by snapshots).
160+
*/
161+
private long pendingDeleteNamespace;
154162

155163
protected OzoneBucket(Builder builder) {
156164
super(builder);
@@ -167,6 +175,8 @@ protected OzoneBucket(Builder builder) {
167175
}
168176
this.usedBytes = builder.usedBytes;
169177
this.usedNamespace = builder.usedNamespace;
178+
this.pendingDeleteBytes = builder.pendingDeleteBytes;
179+
this.pendingDeleteNamespace = builder.pendingDeleteNamespace;
170180
this.creationTime = Instant.ofEpochMilli(builder.creationTime);
171181
if (builder.modificationTime != 0) {
172182
this.modificationTime = Instant.ofEpochMilli(builder.modificationTime);
@@ -610,6 +620,14 @@ public long getUsedNamespace() {
610620
return usedNamespace;
611621
}
612622

623+
public long getPendingDeleteBytes() {
624+
return pendingDeleteBytes;
625+
}
626+
627+
public long getPendingDeleteNamespace() {
628+
return pendingDeleteNamespace;
629+
}
630+
613631
/**
614632
* Returns Iterator to iterate over all keys in the bucket.
615633
* The result can be restricted using key prefix, will return all
@@ -1127,6 +1145,8 @@ public static class Builder extends WithMetadata.Builder {
11271145
private long quotaInNamespace;
11281146
private BucketLayout bucketLayout;
11291147
private String owner;
1148+
private long pendingDeleteBytes;
1149+
private long pendingDeleteNamespace;
11301150

11311151
protected Builder() {
11321152
}
@@ -1223,6 +1243,16 @@ public Builder setOwner(String owner) {
12231243
return this;
12241244
}
12251245

1246+
public Builder setPendingDeleteBytes(long pendingDeleteBytes) {
1247+
this.pendingDeleteBytes = pendingDeleteBytes;
1248+
return this;
1249+
}
1250+
1251+
public Builder setPendingDeleteNamespace(long pendingDeleteNamespace) {
1252+
this.pendingDeleteNamespace = pendingDeleteNamespace;
1253+
return this;
1254+
}
1255+
12261256
public OzoneBucket build() {
12271257
return new OzoneBucket(this);
12281258
}

hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rpc/RpcClient.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,6 +1299,8 @@ public OzoneBucket getBucketDetails(
12991299
.setSourceBucket(bucketInfo.getSourceBucket())
13001300
.setUsedBytes(bucketInfo.getTotalBucketSpace())
13011301
.setUsedNamespace(bucketInfo.getTotalBucketNamespace())
1302+
.setPendingDeleteBytes(bucketInfo.getSnapshotUsedBytes())
1303+
.setPendingDeleteNamespace(bucketInfo.getSnapshotUsedNamespace())
13021304
.setQuotaInBytes(bucketInfo.getQuotaInBytes())
13031305
.setQuotaInNamespace(bucketInfo.getQuotaInNamespace())
13041306
.setBucketLayout(bucketInfo.getBucketLayout())
@@ -1330,6 +1332,8 @@ public List<OzoneBucket> listBuckets(String volumeName, String bucketPrefix,
13301332
.setSourceBucket(bucket.getSourceBucket())
13311333
.setUsedBytes(bucket.getTotalBucketSpace())
13321334
.setUsedNamespace(bucket.getTotalBucketNamespace())
1335+
.setPendingDeleteBytes(bucket.getSnapshotUsedBytes())
1336+
.setPendingDeleteNamespace(bucket.getSnapshotUsedNamespace())
13331337
.setQuotaInBytes(bucket.getQuotaInBytes())
13341338
.setQuotaInNamespace(bucket.getQuotaInNamespace())
13351339
.setBucketLayout(bucket.getBucketLayout())

hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/OzoneRpcClientTests.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_BLOCK_DELETING_SERVICE_INTERVAL;
3434
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_SCM_BLOCK_SIZE;
3535
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_SCM_BLOCK_SIZE_DEFAULT;
36+
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_SNAPSHOT_DELETING_SERVICE_INTERVAL;
3637
import static org.apache.hadoop.ozone.OzoneConsts.DEFAULT_OM_UPDATE_ID;
3738
import static org.apache.hadoop.ozone.OzoneConsts.ETAG;
3839
import static org.apache.hadoop.ozone.OzoneConsts.GB;
@@ -211,6 +212,7 @@
211212
import org.junit.jupiter.params.provider.CsvSource;
212213
import org.junit.jupiter.params.provider.EnumSource;
213214
import org.junit.jupiter.params.provider.MethodSource;
215+
import org.junit.jupiter.params.provider.ValueSource;
214216
import org.slf4j.Logger;
215217
import org.slf4j.LoggerFactory;
216218

@@ -263,6 +265,7 @@ static void startCluster(OzoneConfiguration conf, MiniOzoneCluster.Builder build
263265
conf.setInt(OZONE_SCM_RATIS_PIPELINE_LIMIT, 10);
264266
conf.setTimeDuration(OZONE_BLOCK_DELETING_SERVICE_INTERVAL, 1, TimeUnit.SECONDS);
265267
conf.setTimeDuration(OZONE_DIR_DELETING_SERVICE_INTERVAL, 1, TimeUnit.SECONDS);
268+
conf.setTimeDuration(OZONE_SNAPSHOT_DELETING_SERVICE_INTERVAL, 1, TimeUnit.SECONDS);
266269

267270
ClientConfigForTesting.newBuilder(StorageUnit.MB)
268271
.setDataStreamMinPacketSize(1)
@@ -1151,6 +1154,71 @@ public void testDeleteAuditLog() throws Exception {
11511154
", replicationConfig=EC{rs-3-2-1024k}}\",\"unDeletedKeysList\"");
11521155
}
11531156

1157+
/**
1158+
* Verifies pendingDelete* fields are populated after key delete,
1159+
* with/without snapshot retention.
1160+
*
1161+
* @param withSnapshot whether to create a snapshot before deleting the key
1162+
* @throws Exception on failure
1163+
*/
1164+
@ParameterizedTest
1165+
@ValueSource(booleans = {false, true})
1166+
public void testBucketPendingDeleteBytes(boolean withSnapshot) throws Exception {
1167+
String volumeName = UUID.randomUUID().toString();
1168+
String bucketName = UUID.randomUUID().toString();
1169+
String keyName = UUID.randomUUID().toString();
1170+
String snapshotName = "snap-" + UUID.randomUUID();
1171+
String value = "sample value";
1172+
int valueLength = value.getBytes(UTF_8).length;
1173+
1174+
store.createVolume(volumeName);
1175+
OzoneVolume volume = store.getVolume(volumeName);
1176+
volume.createBucket(bucketName);
1177+
OzoneBucket bucket = volume.getBucket(bucketName);
1178+
1179+
writeKey(bucket, keyName, ONE, value, valueLength);
1180+
1181+
OzoneBucket bucketAfterKeyWrite = store.getVolume(volumeName)
1182+
.getBucket(bucketName);
1183+
assertThat(bucketAfterKeyWrite.getUsedBytes()).isEqualTo(valueLength);
1184+
assertThat(bucketAfterKeyWrite.getUsedNamespace()).isEqualTo(1);
1185+
assertThat(bucketAfterKeyWrite.getPendingDeleteBytes()).isEqualTo(0);
1186+
assertThat(bucketAfterKeyWrite.getPendingDeleteNamespace()).isEqualTo(0);
1187+
1188+
if (withSnapshot) {
1189+
store.createSnapshot(volumeName, bucketName, snapshotName);
1190+
}
1191+
bucket.deleteKey(keyName);
1192+
// After delete: usedBytes should still be totalBucketSpace.
1193+
OzoneBucket bucketAfterKeyDelete = store.getVolume(volumeName)
1194+
.getBucket(bucketName);
1195+
assertThat(bucketAfterKeyDelete.getUsedBytes()).isEqualTo(valueLength);
1196+
assertThat(bucketAfterKeyDelete.getUsedNamespace()).isEqualTo(1);
1197+
assertThat(bucketAfterKeyDelete.getPendingDeleteBytes()).isEqualTo(valueLength);
1198+
assertThat(bucketAfterKeyDelete.getPendingDeleteNamespace()).isEqualTo(1);
1199+
1200+
if (withSnapshot) {
1201+
// if snapshot is present bytes won't be released until snapshot is deleted.
1202+
store.deleteSnapshot(volumeName, bucketName, snapshotName);
1203+
}
1204+
1205+
GenericTestUtils.waitFor(() -> {
1206+
OzoneBucket buck = null;
1207+
try {
1208+
buck = store.getVolume(volumeName).getBucket(bucketName);
1209+
} catch (IOException e) {
1210+
fail("Failed to get bucket details", e);
1211+
}
1212+
return buck.getUsedBytes() == 0 && buck.getUsedNamespace() == 0;
1213+
}, 1000, 30000);
1214+
OzoneBucket bucketAfterKeyPurge = store.getVolume(volumeName)
1215+
.getBucket(bucketName);
1216+
assertThat(bucketAfterKeyPurge.getUsedBytes()).isEqualTo(0);
1217+
assertThat(bucketAfterKeyPurge.getUsedNamespace()).isEqualTo(0);
1218+
assertThat(bucketAfterKeyPurge.getPendingDeleteBytes()).isEqualTo(0);
1219+
assertThat(bucketAfterKeyPurge.getPendingDeleteNamespace()).isEqualTo(0);
1220+
}
1221+
11541222
protected void verifyReplication(String volumeName, String bucketName,
11551223
String keyName, ReplicationConfig replication)
11561224
throws IOException {

0 commit comments

Comments
 (0)