Copilot commented on code in PR #11118:
URL: https://github.com/apache/ozone/pull/11118#discussion_r3864750898
##########
hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMDirectoriesPurgeRequestWithFSO.java:
##########
@@ -255,57 +170,421 @@ public OMClientResponse
validateAndUpdateCache(OzoneManager ozoneManager, Execut
}
throw new IllegalStateException(ex);
} finally {
+ if (lockAcquired) {
+
mergeOmLockDetails(omMetadataManager.getLock().releaseWriteLocks(BUCKET_LOCK,
bucketLockKeys));
+ }
+ // Snapshot the mutated bucket infos for the response after releasing
the lock. The single apply thread is the
+ // only writer, so no other transaction can mutate them between release
and copy.
for (Map.Entry<Pair<String, String>, OmBucketInfo> entry :
- volBucketInfoMap.entrySet()) {
+ result.volBucketInfoMap.entrySet()) {
entry.setValue(entry.getValue().copyObject());
}
- if (lockAcquired) {
-
mergeOmLockDetails(omMetadataManager.getLock().releaseWriteLocks(BUCKET_LOCK,
bucketLockKeys));
- }
}
return new OMDirectoriesPurgeResponseWithFSO(
omResponse.build(), purgeRequests,
- getBucketLayout(), volBucketInfoMap, fromSnapshotInfo, openKeyInfoMap);
+ getBucketLayout(), result.volBucketInfoMap, fromSnapshotInfo,
result.openKeyInfoMap);
+ }
+
+ /**
+ * De-duplicates purged directories from the moved sub-directory set and
updates the deletion service metrics for
+ * this transaction, returning the resulting number of sub-directories moved
(used for the success audit).
+ */
+ private int recordDeletionMetrics(DeletingServiceMetrics
deletingServiceMetrics, OMMetrics omMetrics,
+ long numKeysProcessed, PurgeApplyResult result) {
+ // Apply the per-entry global OM metric mutations in bulk (one increment
each instead of once per entry) to
+ // minimize work done while holding the bucket write lock.
+ omMetrics.decNumKeys(numKeysProcessed);
+ omMetrics.incNumKeyDeletesInternal(numKeysProcessed);
+ // Remove deletedDirNames from subDirNames to avoid duplication
+ result.subDirNames.removeAll(result.deletedDirNames);
+ int numSubDirMoved = result.subDirNames.size();
+ deletingServiceMetrics.incrNumSubDirectoriesMoved(numSubDirMoved);
+ deletingServiceMetrics.incrNumSubFilesMoved(result.numSubFilesMoved);
+ deletingServiceMetrics.incrNumDirPurged(result.numDirsDeleted);
+ return numSubDirMoved;
+ }
+
+ /**
+ * Builds and emits the success audit message for a directory purge. Kept
separate so the per-entry parameter map is
+ * only assembled when debug audit logging is enabled.
+ */
+ private void logDirectoryDeletionAuditSuccess(OzoneManager ozoneManager,
SnapshotInfo fromSnapshotInfo,
+ int numSubDirMoved, PurgeApplyResult result) {
+ Map<String, String> auditParams = new LinkedHashMap<>();
+ if (fromSnapshotInfo != null) {
+ auditParams.put(AUDIT_PARAM_SNAPSHOT_ID,
fromSnapshotInfo.getSnapshotId().toString());
+ }
+ auditParams.put(AUDIT_PARAM_DIRS_DELETED,
String.valueOf(result.numDirsDeleted));
+ auditParams.put(AUDIT_PARAM_SUBDIRS_MOVED, String.valueOf(numSubDirMoved));
+ auditParams.put(AUDIT_PARAM_SUBFILES_MOVED,
String.valueOf(result.numSubFilesMoved));
+ auditParams.put(AUDIT_PARAM_DIRS_DELETED_LIST, String.join(",",
result.deletedDirNames));
+ auditParams.put(AUDIT_PARAM_SUBDIRS_MOVED_LIST, String.join(",",
result.subDirNames));
+ auditParams.put(AUDIT_PARAM_SUBFILES_MOVED_LIST, String.join(",",
result.subFileNames));
+
AUDIT.logWriteSuccess(ozoneManager.buildAuditMessageForSuccess(OMSystemAction.DIRECTORY_DELETION,
auditParams));
+ }
+
+ /**
+ * Logs, audits and builds the error response for a failure while resolving
the {@code fromSnapshot}. Extracted so
+ * the {@link #validateAndUpdateCache} catch block reads as a single call.
+ */
+ private OMClientResponse directoryPurgeFailure(OzoneManager ozoneManager,
OMResponse.Builder omResponse,
+ IOException e) {
+ LOG.error("Error occurred while performing OMDirectoriesPurge. ", e);
+ if (LOG.isDebugEnabled()) {
+
AUDIT.logWriteFailure(ozoneManager.buildAuditMessageForFailure(OMSystemAction.DIRECTORY_DELETION,
null, e));
+ }
+ return new
OMDirectoriesPurgeResponseWithFSO(createErrorOMResponse(omResponse, e));
+ }
+
+ /**
+ * Resolves the {@code fromSnapshot} this purge runs against and, for
new-format requests, validates that the
+ * previous snapshot chain has not changed. Extracted so {@link
#validateAndUpdateCache} reads as setup → per-path
+ * apply → bookkeeping.
+ */
+ private SnapshotInfo resolveFromSnapshotInfo(OzoneManager ozoneManager,
OmMetadataManagerImpl omMetadataManager,
+ PurgeDirectoriesRequest purgeDirsRequest, String fromSnapshot) throws
IOException {
+ SnapshotInfo fromSnapshotInfo = fromSnapshot != null
+ ? SnapshotUtils.getSnapshotInfo(ozoneManager, fromSnapshot) : null;
+ // Checking if this request is an old request or new one.
+ if (purgeDirsRequest.hasExpectedPreviousSnapshotID()) {
+ // Validating previous snapshot since while purging deletes, a snapshot
create request could make this purge
+ // directory request invalid on AOS since the deletedDirectory would be
in the newly created snapshot. Adding
+ // subdirectories could lead to not being able to reclaim sub-files and
subdirectories since the
+ // file/directory would be present in the newly created snapshot.
+ // Validating previous snapshot can ensure the chain hasn't changed.
+ UUID expectedPreviousSnapshotId =
purgeDirsRequest.getExpectedPreviousSnapshotID().hasUuid()
+ ?
fromProtobuf(purgeDirsRequest.getExpectedPreviousSnapshotID().getUuid()) : null;
+ validatePreviousSnapshotId(fromSnapshotInfo,
omMetadataManager.getSnapshotChainManager(),
+ expectedPreviousSnapshotId);
+ }
+ return fromSnapshotInfo;
+ }
+
+ /**
+ * Phase 1 (no lock): parses a path's sub-directories into prepared entries,
precomputing each delete/path key. The
+ * directory-table tombstones and bucket namespace decrements are applied
later under the lock in
+ * {@link #applyPreparedEntries}.
+ */
+ private List<PreparedEntry>
prepareMarkDeletedSubDirs(OzoneManagerProtocolProtos.PurgePathRequest path,
+ OmMetadataManagerImpl omMetadataManager) {
+ List<PreparedEntry> preparedSubDirs = new ArrayList<>();
+ for (OzoneManagerProtocolProtos.KeyInfo key :
path.getMarkDeletedSubDirsList()) {
+ ProcessedKeyInfo processed = processDeleteKey(key, path,
omMetadataManager);
+ preparedSubDirs.add(new PreparedEntry(processed, path.getBucketId(), 0L,
null));
+ }
+ return preparedSubDirs;
+ }
+
+ /**
+ * Phase 1 (no lock): parses a path's sub-files into prepared entries,
precomputing each delete/path key, its
+ * replicated size and, for hsync files, the open-key name to clean up. The
file-table tombstones, hsync open-key
+ * cleanup and bucket quota decrements are applied later under the lock in
{@link #applyPreparedEntries}.
+ */
+ private List<PreparedEntry>
prepareMoveDeletedSubFiles(OzoneManagerProtocolProtos.PurgePathRequest path,
+ OmMetadataManagerImpl omMetadataManager) {
+ List<PreparedEntry> preparedSubFiles = new ArrayList<>();
+ for (OzoneManagerProtocolProtos.KeyInfo key :
path.getDeletedSubFilesList()) {
+ ProcessedKeyInfo processed = processDeleteKey(key, path,
omMetadataManager);
+ long replicatedSize = sumBlockLengths(key);
+ // If omKeyInfo has hsync metadata, its corresponding open key is
cleaned up under the lock.
+ String hsyncClientId = getHsyncClientId(key);
+ String dbOpenKey = hsyncClientId == null ? null
+ : omMetadataManager.getOpenFileName(path.getVolumeId(),
path.getBucketId(),
+ processed.parentObjectID, processed.fileName, hsyncClientId);
+ preparedSubFiles.add(new PreparedEntry(processed, path.getBucketId(),
replicatedSize, dbOpenKey));
+ }
+ return preparedSubFiles;
+ }
+
+ /**
+ * Phase 1 (no lock): records a path's deleted directory for later purge
under the lock in
+ * {@link #applyPreparedEntries}.
+ */
+ private PreparedDirPurge
prepareDeletedDir(OzoneManagerProtocolProtos.PurgePathRequest path,
+ BucketNameInfo bucketNameInfo) {
+ return new PreparedDirPurge(bucketNameInfo.getVolumeName(),
bucketNameInfo.getBucketName(),
+ path.getBucketId(), path.getDeletedDir());
+ }
+
+ /**
+ * Phase 2 (under the bucket write lock): applies the prepared
directory/file tombstones, hsync open-key cleanup and
+ * per-bucket quota changes. Quota deltas are accumulated per bucket and
applied once, instead of once per entry, to
+ * minimize the mutations done while holding the write lock.
+ */
+ private void applyPreparedEntries(List<PreparedEntry> preparedSubDirs,
List<PreparedEntry> preparedSubFiles,
+ List<PreparedDirPurge> preparedDirPurges, OmMetadataManagerImpl
omMetadataManager, long trxnLogIndex,
+ PurgeApplyResult result) throws IOException {
+ // Memoizes getBucketInfo lookups within this apply so that a purge
transaction touching many keys of the same
+ // bucket resolves the bucket cache entry once instead of per key.
+ Map<Pair<String, String>, OmBucketInfo> bucketInfoCache = new HashMap<>();
+ // Quota deltas are accumulated per bucket across all three entry loops
and applied once at the end.
+ Map<Pair<String, String>, QuotaDelta> quotaDeltas = new HashMap<>();
+
+ applyMarkedSubDirs(preparedSubDirs, omMetadataManager, trxnLogIndex,
result, bucketInfoCache, quotaDeltas);
+ applyMovedSubFiles(preparedSubFiles, omMetadataManager, trxnLogIndex,
result, bucketInfoCache, quotaDeltas);
+ applyDirPurges(preparedDirPurges, omMetadataManager, result,
bucketInfoCache, quotaDeltas);
+ applyQuotaDeltas(quotaDeltas);
+ }
+
+ /**
+ * Phase 2 (under the bucket write lock): tombstones each prepared
sub-directory in the directory table and
+ * accumulates its namespace quota decrement, when its bucket still matches
the prepared bucket id.
+ */
+ private void applyMarkedSubDirs(List<PreparedEntry> preparedSubDirs,
OmMetadataManagerImpl omMetadataManager,
+ long trxnLogIndex, PurgeApplyResult result, Map<Pair<String, String>,
OmBucketInfo> bucketInfoCache,
+ Map<Pair<String, String>, QuotaDelta> quotaDeltas) {
+ for (PreparedEntry entry : preparedSubDirs) {
+ ProcessedKeyInfo processed = entry.processed;
+ result.subDirNames.add(processed.deleteKey);
+ OmBucketInfo omBucketInfo = getBucketInfoCached(omMetadataManager,
+ bucketInfoCache, processed.volumeName, processed.bucketName);
+ // bucketInfo can be null in case of delete volume or bucket
+ // or key does not belong to bucket as bucket is recreated
+ if (null != omBucketInfo && omBucketInfo.getObjectID() ==
entry.bucketId) {
+ omMetadataManager.getDirectoryTable().addCacheEntry(new
CacheKey<>(processed.pathKey),
+ CacheValue.get(trxnLogIndex));
+ result.volBucketInfoMap.putIfAbsent(processed.volBucketPair,
omBucketInfo);
+ quotaDeltas.computeIfAbsent(processed.volBucketPair, k -> new
QuotaDelta(omBucketInfo)).usedNamespace += 1L;
+ }
+ }
+ }
+
+ /**
+ * Phase 2 (under the bucket write lock): tombstones each prepared sub-file
in the file table, cleans up its hsync
+ * open key when present, and accumulates its byte and namespace quota
decrements, when its bucket still matches the
+ * prepared bucket id.
+ */
+ private void applyMovedSubFiles(List<PreparedEntry> preparedSubFiles,
OmMetadataManagerImpl omMetadataManager,
+ long trxnLogIndex, PurgeApplyResult result, Map<Pair<String, String>,
OmBucketInfo> bucketInfoCache,
+ Map<Pair<String, String>, QuotaDelta> quotaDeltas) throws IOException {
+ for (PreparedEntry entry : preparedSubFiles) {
+ ProcessedKeyInfo processed = entry.processed;
+ result.subFileNames.add(processed.deleteKey);
+
+ // If omKeyInfo has hsync metadata, delete its corresponding open key as
well
+ if (entry.dbOpenKey != null) {
+ OmKeyInfo openKeyInfo =
omMetadataManager.getOpenKeyTable(getBucketLayout()).get(entry.dbOpenKey);
+ if (openKeyInfo != null) {
+ openKeyInfo = openKeyInfo.withMetadataMutations(
+ metadata -> metadata.put(DELETED_HSYNC_KEY, "true"));
+ result.openKeyInfoMap.put(entry.dbOpenKey, openKeyInfo);
+ }
+ }
+
+ result.numSubFilesMoved++;
+ OmBucketInfo omBucketInfo = getBucketInfoCached(omMetadataManager,
+ bucketInfoCache, processed.volumeName, processed.bucketName);
+ // bucketInfo can be null in case of delete volume or bucket
+ // or key does not belong to bucket as bucket is recreated
+ if (null != omBucketInfo && omBucketInfo.getObjectID() ==
entry.bucketId) {
+ omMetadataManager.getFileTable().addCacheEntry(new
CacheKey<>(processed.pathKey),
+ CacheValue.get(trxnLogIndex));
+ result.volBucketInfoMap.putIfAbsent(processed.volBucketPair,
omBucketInfo);
+ QuotaDelta quotaDelta =
quotaDeltas.computeIfAbsent(processed.volBucketPair, k -> new
QuotaDelta(omBucketInfo));
+ quotaDelta.usedBytes += entry.replicatedSize;
+ quotaDelta.usedNamespace += 1L;
+ }
+ }
+ }
+
+ /**
+ * Phase 2 (under the bucket write lock): records each purged directory and
accumulates its snapshot-namespace purge,
+ * when its bucket still matches the prepared bucket id.
+ */
+ private void applyDirPurges(List<PreparedDirPurge> preparedDirPurges,
OmMetadataManagerImpl omMetadataManager,
+ PurgeApplyResult result, Map<Pair<String, String>, OmBucketInfo>
bucketInfoCache,
+ Map<Pair<String, String>, QuotaDelta> quotaDeltas) {
+ for (PreparedDirPurge dirPurge : preparedDirPurges) {
+ result.deletedDirNames.add(dirPurge.deletedDir);
+ OmBucketInfo omBucketInfo = getBucketInfoCached(omMetadataManager,
+ bucketInfoCache, dirPurge.volumeName, dirPurge.bucketName);
+ if (omBucketInfo != null && omBucketInfo.getObjectID() ==
dirPurge.bucketId) {
+ Pair<String, String> volBucketPair =
Pair.of(omBucketInfo.getVolumeName(), omBucketInfo.getBucketName());
+ result.volBucketInfoMap.put(volBucketPair, omBucketInfo);
+ quotaDeltas.computeIfAbsent(volBucketPair, k -> new
QuotaDelta(omBucketInfo)).snapshotNamespacePurge += 1L;
+ }
+ result.numDirsDeleted++;
+ }
+ }
+
+ /**
+ * Phase 2 (under the bucket write lock): applies the per-bucket accumulated
quota changes once each, instead of once
+ * per entry, to minimize the mutations done while holding the bucket write
lock.
+ */
+ private void applyQuotaDeltas(Map<Pair<String, String>, QuotaDelta>
quotaDeltas) {
+ for (QuotaDelta quotaDelta : quotaDeltas.values()) {
+ if (quotaDelta.usedBytes != 0L) {
+ quotaDelta.bucketInfo.decrUsedBytes(quotaDelta.usedBytes, true);
+ }
+ if (quotaDelta.usedNamespace != 0L) {
+ quotaDelta.bucketInfo.decrUsedNamespace(quotaDelta.usedNamespace,
true);
+ }
+ if (quotaDelta.snapshotNamespacePurge != 0L) {
+
quotaDelta.bucketInfo.purgeSnapshotUsedNamespace(quotaDelta.snapshotNamespacePurge);
+ }
+ }
+ }
+
+ /**
+ * Phase 2 output accumulated by {@link #applyPreparedEntries} under the
bucket write lock: the mutated bucket infos
+ * and hsync open keys used to build the response, plus the moved
sub-dir/sub-file/deleted-dir names and counts used
+ * for the deletion metrics and the success audit.
+ */
+ private static final class PurgeApplyResult {
+ private final Map<Pair<String, String>, OmBucketInfo> volBucketInfoMap =
new HashMap<>();
+ private final Map<String, OmKeyInfo> openKeyInfoMap = new HashMap<>();
+ private final Set<String> subDirNames = new HashSet<>();
+ private final Set<String> subFileNames = new HashSet<>();
+ private final Set<String> deletedDirNames = new HashSet<>();
+ private int numSubFilesMoved;
+ private int numDirsDeleted;
}
/**
* Helper class to hold processed key information.
*/
private static class ProcessedKeyInfo {
- private final OmKeyInfo keyInfo;
private final String deleteKey;
+ private final String pathKey;
private final String volumeName;
private final String bucketName;
+ private final long parentObjectID;
+ private final String fileName;
private final Pair<String, String> volBucketPair;
- ProcessedKeyInfo(OmKeyInfo keyInfo, String deleteKey, String volumeName,
String bucketName) {
- this.keyInfo = keyInfo;
+ ProcessedKeyInfo(String deleteKey, String pathKey, String volumeName,
+ String bucketName, long parentObjectID, String fileName) {
this.deleteKey = deleteKey;
+ this.pathKey = pathKey;
this.volumeName = volumeName;
this.bucketName = bucketName;
+ this.parentObjectID = parentObjectID;
+ this.fileName = fileName;
this.volBucketPair = Pair.of(volumeName, bucketName);
}
}
+ /**
+ * A sub-directory or sub-file prepared (lock-free) in phase 1 for
application under the bucket write lock in phase
+ * 2. {@code replicatedSize} is the file's replicated byte usage (0 for
directories) and {@code dbOpenKey} is the
+ * hsync open-key to clean up, or {@code null} when the entry is not an
hsync file.
+ */
+ private static final class PreparedEntry {
+ private final ProcessedKeyInfo processed;
+ private final long bucketId;
+ private final long replicatedSize;
+ private final String dbOpenKey;
+
+ PreparedEntry(ProcessedKeyInfo processed, long bucketId, long
replicatedSize, String dbOpenKey) {
+ this.processed = processed;
+ this.bucketId = bucketId;
+ this.replicatedSize = replicatedSize;
+ this.dbOpenKey = dbOpenKey;
+ }
+ }
+
+ /**
+ * A deleted directory prepared (lock-free) in phase 1 for its
snapshot-namespace purge under the bucket write lock
+ * in phase 2.
+ */
+ private static final class PreparedDirPurge {
+ private final String volumeName;
+ private final String bucketName;
+ private final long bucketId;
+ private final String deletedDir;
+
+ PreparedDirPurge(String volumeName, String bucketName, long bucketId,
String deletedDir) {
+ this.volumeName = volumeName;
+ this.bucketName = bucketName;
+ this.bucketId = bucketId;
+ this.deletedDir = deletedDir;
+ }
+ }
+
+ /**
+ * Accumulates a single bucket's quota changes across all entries in a purge
so they can be applied once under the
+ * write lock instead of once per entry.
+ */
+ private static final class QuotaDelta {
+ private final OmBucketInfo bucketInfo;
+ private long usedBytes;
+ private long usedNamespace;
+ private long snapshotNamespacePurge;
+
+ QuotaDelta(OmBucketInfo bucketInfo) {
+ this.bucketInfo = bucketInfo;
+ }
+ }
+
/**
* Process delete key info.
- * Returns ProcessedKeyInfo containing all the processed information.
+ * Reads only the fields the purge apply path needs directly from the
protobuf, instead of building a full
+ * {@link OmKeyInfo} (with its key-location, ACL, tag, encryption and
checksum objects) for every entry on the
+ * single-threaded apply path.
*/
private ProcessedKeyInfo processDeleteKey(OzoneManagerProtocolProtos.KeyInfo
key,
OzoneManagerProtocolProtos.PurgePathRequest path,
OmMetadataManagerImpl
omMetadataManager) {
- OmKeyInfo keyInfo = OmKeyInfo.getFromProtobuf(key);
+ long objectID = key.hasObjectID() ? key.getObjectID() : 0L;
+ long parentObjectID = key.hasParentID() ? key.getParentID() : 0L;
+ String fileName = OzoneFSUtils.getFileName(key.getKeyName());
String pathKey = omMetadataManager.getOzonePathKey(path.getVolumeId(),
- path.getBucketId(), keyInfo.getParentObjectID(),
keyInfo.getFileName());
- String deleteKey = omMetadataManager.getOzoneDeletePathKey(
- keyInfo.getObjectID(), pathKey);
+ path.getBucketId(), parentObjectID, fileName);
+ String deleteKey = omMetadataManager.getOzoneDeletePathKey(objectID,
pathKey);
- String volumeName = keyInfo.getVolumeName();
- String bucketName = keyInfo.getBucketName();
+ return new ProcessedKeyInfo(deleteKey, pathKey, key.getVolumeName(),
key.getBucketName(),
+ parentObjectID, fileName);
+ }
- return new ProcessedKeyInfo(keyInfo, deleteKey, volumeName, bucketName);
+ /**
+ * Returns the cached bucket info for the given volume/bucket, memoizing the
lookup within a single apply so that a
+ * purge transaction touching many keys of the same bucket does the {@link
#getBucketInfo} cache lookup once. The
+ * returned instance is the same cached reference {@link #getBucketInfo}
returns, so in-place quota mutations behave
+ * identically. {@code null} results (deleted bucket) are memoized too.
+ */
+ private static OmBucketInfo getBucketInfoCached(OmMetadataManagerImpl
omMetadataManager,
+ Map<Pair<String, String>, OmBucketInfo> cache, String volumeName, String
bucketName) {
+ Pair<String, String> cacheKey = Pair.of(volumeName, bucketName);
+ if (cache.containsKey(cacheKey)) {
+ return cache.get(cacheKey);
+ }
+ OmBucketInfo omBucketInfo = getBucketInfo(omMetadataManager, volumeName,
bucketName);
+ cache.put(cacheKey, omBucketInfo);
+ return omBucketInfo;
+ }
+
+ /**
+ * Reads the HSYNC client id directly from the key's protobuf metadata,
mirroring
+ * {@code KeyValueUtil.getFromProtobuf(...).get(HSYNC_CLIENT_ID)} without
building the full metadata map.
+ */
+ private static String getHsyncClientId(OzoneManagerProtocolProtos.KeyInfo
key) {
+ String hsyncClientId = null;
+ for (HddsProtos.KeyValue kv : key.getMetadataList()) {
+ if (OzoneConsts.HSYNC_CLIENT_ID.equals(kv.getKey())) {
+ hsyncClientId = kv.getValue();
+ }
+ }
Review Comment:
getHsyncClientId scans the full metadata list even after finding
HSYNC_CLIENT_ID. Since this method is called for every deleted sub-file during
purge, breaking early avoids unnecessary iteration on the apply path.
##########
hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/service/TestDirectoryDeletingService.java:
##########
@@ -331,4 +331,63 @@ void testPurgeDirectoriesBatching() throws Exception {
org.apache.commons.io.FileUtils.deleteDirectory(testDir);
}
+ @Test
+ @DisplayName("DirectoryDeletingService submits one bucket per
PurgeDirectories transaction")
+ void testPurgeDirectoriesGroupedByBucketPerTransaction() throws Exception {
+ OzoneConfiguration conf = new OzoneConfiguration();
+ File testDir = Files.createTempDirectory("TestDDS-BucketGroup").toFile();
+ ServerUtils.setOzoneMetaDirPath(conf, testDir.toString());
+ conf.setTimeDuration(OMConfigKeys.OZONE_DIR_DELETING_SERVICE_INTERVAL,
100, TimeUnit.MILLISECONDS);
+ conf.setQuietMode(false);
Review Comment:
This test creates a temp directory and deletes it at the end of the method,
but not in a finally block. If an assertion fails (or an exception is thrown)
before the final deleteDirectory call, the temporary directory will be leaked
on the test machine.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]