This is an automated email from the ASF dual-hosted git repository.
sumitagrawal pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new feed38e736 HDDS-7366. Coordinate on demand and background container
scanners. (#4726)
feed38e736 is described below
commit feed38e73690952e8073a5e5986d8c89e50eb6a0
Author: Ethan Rose <[email protected]>
AuthorDate: Thu May 25 01:41:13 2023 -0700
HDDS-7366. Coordinate on demand and background container scanners. (#4726)
* Use timestamps to throttle scans
* Updated unit test for on demand scanner support of timestamps
* Unit tests pass after refactor and additions
* Revert findbugs
* Change variable to static final
* Combine log messages to helper methods
* Checkstyle
* Restore findbugs exclude from master and include renames
---
.../dev-support/findbugsExcludeFile.xml | 6 +-
.../container/common/helpers/ContainerUtils.java | 27 +++
.../container/common/impl/HddsDispatcher.java | 4 +-
.../container/keyvalue/KeyValueContainer.java | 12 +-
...ava => AbstractBackgroundContainerScanner.java} | 7 +-
...er.java => BackgroundContainerDataScanner.java} | 35 ++--
...ava => BackgroundContainerMetadataScanner.java} | 20 +-
.../ozoneimpl/ContainerScannerConfiguration.java | 28 +++
...nner.java => OnDemandContainerDataScanner.java} | 46 +++--
.../ozone/container/ozoneimpl/OzoneContainer.java | 17 +-
.../ozone/container/common/ContainerTestUtils.java | 2 +-
.../TestBackgroundContainerDataScanner.java | 134 +++++++++++++
.../TestBackgroundContainerMetadataScanner.java | 114 +++++++++++
.../TestContainerScannerConfiguration.java | 9 +
.../ozoneimpl/TestContainerScannerMetrics.java | 199 -------------------
.../ozoneimpl/TestContainerScannersAbstract.java | 155 +++++++++++++++
.../TestOnDemandContainerDataScanner.java | 212 +++++++++++++++++++++
.../ozoneimpl/TestOnDemandContainerScanner.java | 157 ---------------
...Scanner.java => TestContainerDataScanners.java} | 8 +-
19 files changed, 781 insertions(+), 411 deletions(-)
diff --git a/hadoop-hdds/container-service/dev-support/findbugsExcludeFile.xml
b/hadoop-hdds/container-service/dev-support/findbugsExcludeFile.xml
index bf72793b9a..2cca8b90e2 100644
--- a/hadoop-hdds/container-service/dev-support/findbugsExcludeFile.xml
+++ b/hadoop-hdds/container-service/dev-support/findbugsExcludeFile.xml
@@ -82,7 +82,11 @@
<Bug pattern="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE" />
</Match>
<Match>
- <Class
name="org.apache.hadoop.ozone.container.ozoneimpl.TestContainerScannerMetrics"/>
+ <Class
name="org.apache.hadoop.ozone.container.ozoneimpl.TestBackgroundContainerDataScanner"/>
+ <Bug pattern="RU_INVOKE_RUN" />
+ </Match>
+ <Match>
+ <Class
name="org.apache.hadoop.ozone.container.ozoneimpl.TestBackgroundContainerMetadataScanner"/>
<Bug pattern="RU_INVOKE_RUN" />
</Match>
</FindBugsFilter>
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/helpers/ContainerUtils.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/helpers/ContainerUtils.java
index 45a38c1618..ff974b9cf4 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/helpers/ContainerUtils.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/helpers/ContainerUtils.java
@@ -33,6 +33,9 @@ import java.io.IOException;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -49,6 +52,7 @@ import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.ozone.container.common.impl.ContainerData;
import org.apache.hadoop.ozone.container.common.impl.ContainerDataYaml;
import org.apache.hadoop.ozone.container.common.impl.ContainerSet;
+import org.apache.hadoop.ozone.container.common.interfaces.Container;
import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainerData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -232,6 +236,29 @@ public final class ContainerUtils {
}
}
+ public static boolean recentlyScanned(Container<?> container,
+ long minScanGap, Logger log) {
+ Optional<Instant> lastScanTime =
+ container.getContainerData().lastDataScanTime();
+ Instant now = Instant.now();
+ // Container is considered recently scanned if it was scanned within the
+ // configured time frame. If the optional is empty, the container was
+ // never scanned.
+ boolean recentlyScanned = lastScanTime.map(scanInstant ->
+ Duration.between(now, scanInstant).abs()
+ .compareTo(Duration.ofMillis(minScanGap)) < 0)
+ .orElse(false);
+
+ if (recentlyScanned && log.isDebugEnabled()) {
+ log.debug("Skipping scan for container {} which was last " +
+ "scanned at {}. Current time is {}.",
+ container.getContainerData().getContainerID(), lastScanTime.get(),
+ now);
+ }
+
+ return recentlyScanned;
+ }
+
/**
* Get the .container file from the containerBaseDir.
* @param containerBaseDir container base directory. The name of this
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/impl/HddsDispatcher.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/impl/HddsDispatcher.java
index ef5bae7999..3a11dccf47 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/impl/HddsDispatcher.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/impl/HddsDispatcher.java
@@ -57,8 +57,8 @@ import
org.apache.hadoop.ozone.container.common.statemachine.StateContext;
import
org.apache.hadoop.ozone.container.common.transport.server.ratis.DispatcherContext;
import org.apache.hadoop.ozone.container.common.volume.HddsVolume;
import org.apache.hadoop.ozone.container.common.volume.VolumeSet;
+import
org.apache.hadoop.ozone.container.ozoneimpl.OnDemandContainerDataScanner;
import org.apache.hadoop.ozone.container.common.volume.VolumeUsage;
-import org.apache.hadoop.ozone.container.ozoneimpl.OnDemandContainerScanner;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.util.Time;
import org.apache.ratis.statemachine.StateMachine;
@@ -386,7 +386,7 @@ public class HddsDispatcher implements ContainerDispatcher,
Auditor {
// Create a specific exception that signals for on demand scanning
// and move this general scan to where it is more appropriate.
// Add integration tests to test the full functionality.
- OnDemandContainerScanner.scanContainer(container);
+ OnDemandContainerDataScanner.scanContainer(container);
audit(action, eventType, params, AuditEventStatus.FAILURE,
new Exception(responseProto.getMessage()));
}
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueContainer.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueContainer.java
index 3253fa3588..1900d28b29 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueContainer.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueContainer.java
@@ -859,8 +859,14 @@ public class KeyValueContainer implements
Container<KeyValueContainerData> {
@Override
public boolean shouldScanData() {
- return containerData.getState() == ContainerDataProto.State.CLOSED
+ boolean shouldScan =
+ containerData.getState() == ContainerDataProto.State.CLOSED
|| containerData.getState() == ContainerDataProto.State.QUASI_CLOSED;
+ if (!shouldScan && LOG.isDebugEnabled()) {
+ LOG.debug("Container {} in state {} should not have its data scanned.",
+ containerData.getContainerID(), containerData.getState());
+ }
+ return shouldScan;
}
@Override
@@ -879,10 +885,6 @@ public class KeyValueContainer implements
Container<KeyValueContainerData> {
return checker.fullCheck(throttler, canceler);
}
- private enum ContainerCheckLevel {
- NO_CHECK, FAST_CHECK, FULL_CHECK
- }
-
/**
* Creates a temporary file.
* @param file
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/AbstractContainerScanner.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/AbstractBackgroundContainerScanner.java
similarity index 94%
rename from
hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/AbstractContainerScanner.java
rename to
hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/AbstractBackgroundContainerScanner.java
index 7877f5aaf4..c956e9a032 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/AbstractContainerScanner.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/AbstractBackgroundContainerScanner.java
@@ -31,9 +31,9 @@ import java.util.concurrent.TimeUnit;
/**
* Base class for scheduled scanners on a Datanode.
*/
-public abstract class AbstractContainerScanner extends Thread {
+public abstract class AbstractBackgroundContainerScanner extends Thread {
public static final Logger LOG =
- LoggerFactory.getLogger(AbstractContainerScanner.class);
+ LoggerFactory.getLogger(AbstractBackgroundContainerScanner.class);
private final long dataScanInterval;
@@ -43,7 +43,8 @@ public abstract class AbstractContainerScanner extends Thread
{
*/
private volatile boolean stopping = false;
- public AbstractContainerScanner(String name, long dataScanInterval) {
+ public AbstractBackgroundContainerScanner(String name,
+ long dataScanInterval) {
this.dataScanInterval = dataScanInterval;
setName(name);
setDaemon(true);
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/ContainerDataScanner.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/BackgroundContainerDataScanner.java
similarity index 79%
rename from
hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/ContainerDataScanner.java
rename to
hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/BackgroundContainerDataScanner.java
index 91f9d95533..dd9ba8212e 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/ContainerDataScanner.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/BackgroundContainerDataScanner.java
@@ -20,6 +20,7 @@ package org.apache.hadoop.ozone.container.ozoneimpl;
import com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.hdfs.util.Canceler;
import org.apache.hadoop.hdfs.util.DataTransferThrottler;
+import org.apache.hadoop.ozone.container.common.helpers.ContainerUtils;
import org.apache.hadoop.ozone.container.common.impl.ContainerData;
import org.apache.hadoop.ozone.container.common.interfaces.Container;
import org.apache.hadoop.ozone.container.common.volume.HddsVolume;
@@ -34,9 +35,10 @@ import java.util.Optional;
/**
* Data scanner that full checks a volume. Each volume gets a separate thread.
*/
-public class ContainerDataScanner extends AbstractContainerScanner {
+public class BackgroundContainerDataScanner extends
+ AbstractBackgroundContainerScanner {
public static final Logger LOG =
- LoggerFactory.getLogger(ContainerDataScanner.class);
+ LoggerFactory.getLogger(BackgroundContainerDataScanner.class);
/**
* The volume that we're scanning.
@@ -47,21 +49,28 @@ public class ContainerDataScanner extends
AbstractContainerScanner {
private final Canceler canceler;
private static final String NAME_FORMAT = "ContainerDataScanner(%s)";
private final ContainerDataScannerMetrics metrics;
+ private final long minScanGap;
- public ContainerDataScanner(ContainerScannerConfiguration conf,
- ContainerController controller,
- HddsVolume volume) {
+ public BackgroundContainerDataScanner(ContainerScannerConfiguration conf,
+ ContainerController controller,
+ HddsVolume volume) {
super(String.format(NAME_FORMAT, volume), conf.getDataScanInterval());
this.controller = controller;
this.volume = volume;
throttler = new HddsDataTransferThrottler(conf.getBandwidthPerVolume());
canceler = new Canceler();
this.metrics = ContainerDataScannerMetrics.create(volume.toString());
+ this.minScanGap = conf.getContainerScanMinGap();
+ }
+
+ private boolean shouldScan(Container<?> container) {
+ return container.shouldScanData() &&
+ !ContainerUtils.recentlyScanned(container, minScanGap, LOG);
}
@Override
public void scanContainer(Container<?> c) throws IOException {
- if (!c.shouldScanData()) {
+ if (!shouldScan(c)) {
return;
}
ContainerData containerData = c.getContainerData();
@@ -70,12 +79,12 @@ public class ContainerDataScanner extends
AbstractContainerScanner {
if (!c.scanData(throttler, canceler)) {
metrics.incNumUnHealthyContainers();
controller.markContainerUnhealthy(containerId);
- } else {
- Instant now = Instant.now();
- logScanCompleted(containerData, now);
- controller.updateDataScanTimestamp(containerId, now);
}
+
metrics.incNumContainersScanned();
+ Instant now = Instant.now();
+ logScanCompleted(containerData, now);
+ controller.updateDataScanTimestamp(containerId, now);
}
@Override
@@ -125,13 +134,15 @@ public class ContainerDataScanner extends
AbstractContainerScanner {
@Override
public synchronized void throttle(long numOfBytes) {
- ContainerDataScanner.this.metrics.incNumBytesScanned(numOfBytes);
+ BackgroundContainerDataScanner.this.metrics.incNumBytesScanned(
+ numOfBytes);
super.throttle(numOfBytes);
}
@Override
public synchronized void throttle(long numOfBytes, Canceler c) {
- ContainerDataScanner.this.metrics.incNumBytesScanned(numOfBytes);
+ BackgroundContainerDataScanner.this.metrics.incNumBytesScanned(
+ numOfBytes);
super.throttle(numOfBytes, c);
}
}
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/ContainerMetadataScanner.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/BackgroundContainerMetadataScanner.java
similarity index 72%
rename from
hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/ContainerMetadataScanner.java
rename to
hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/BackgroundContainerMetadataScanner.java
index b1c3e66e7e..cd321dd3b7 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/ContainerMetadataScanner.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/BackgroundContainerMetadataScanner.java
@@ -18,6 +18,7 @@
package org.apache.hadoop.ozone.container.ozoneimpl;
import com.google.common.annotations.VisibleForTesting;
+import org.apache.hadoop.ozone.container.common.helpers.ContainerUtils;
import org.apache.hadoop.ozone.container.common.interfaces.Container;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -30,18 +31,21 @@ import java.util.Iterator;
* containers.
* Only one thread will be responsible for scanning all volumes.
*/
-public class ContainerMetadataScanner extends AbstractContainerScanner {
+public class BackgroundContainerMetadataScanner extends
+ AbstractBackgroundContainerScanner {
public static final Logger LOG =
- LoggerFactory.getLogger(ContainerMetadataScanner.class);
+ LoggerFactory.getLogger(BackgroundContainerMetadataScanner.class);
private final ContainerMetadataScannerMetrics metrics;
private final ContainerController controller;
+ private final long minScanGap;
- public ContainerMetadataScanner(ContainerScannerConfiguration conf,
- ContainerController controller) {
+ public BackgroundContainerMetadataScanner(ContainerScannerConfiguration conf,
+ ContainerController controller) {
super("ContainerMetadataScanner", conf.getMetadataScanInterval());
this.controller = controller;
this.metrics = ContainerMetadataScannerMetrics.create();
+ this.minScanGap = conf.getContainerScanMinGap();
}
@Override
@@ -52,6 +56,14 @@ public class ContainerMetadataScanner extends
AbstractContainerScanner {
@VisibleForTesting
@Override
public void scanContainer(Container<?> container) throws IOException {
+ // Full data scan also does a metadata scan. If a full data scan was done
+ // recently, we can skip this metadata scan.
+ if (ContainerUtils.recentlyScanned(container, minScanGap, LOG)) {
+ return;
+ }
+
+ // Do not update the scan timestamp since this was just a metadata scan,
+ // not a full scan.
if (!container.scanMetaData()) {
metrics.incNumUnHealthyContainers();
controller.markContainerUnhealthy(
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/ContainerScannerConfiguration.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/ContainerScannerConfiguration.java
index 20c519bd6e..599b15ab8f 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/ContainerScannerConfiguration.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/ContainerScannerConfiguration.java
@@ -28,6 +28,8 @@ import org.slf4j.LoggerFactory;
import java.time.Duration;
+import static org.apache.hadoop.hdds.conf.ConfigTag.DATANODE;
+
/**
* This class defines configuration parameters for the container scanners.
**/
@@ -48,6 +50,11 @@ public class ContainerScannerConfiguration {
"hdds.container.scrub.volume.bytes.per.second";
public static final String ON_DEMAND_VOLUME_BYTES_PER_SECOND_KEY =
"hdds.container.scrub.on.demand.volume.bytes.per.second";
+ public static final String CONTAINER_SCAN_MIN_GAP =
+ "hdds.container.scrub.min.gap";
+
+ static final long CONTAINER_SCAN_MIN_GAP_DEFAULT =
+ Duration.ofMinutes(15).toMillis();
public static final long METADATA_SCAN_INTERVAL_DEFAULT =
Duration.ofHours(3).toMillis();
@@ -101,6 +108,16 @@ public class ContainerScannerConfiguration {
private long onDemandBandwidthPerVolume
= ON_DEMAND_BANDWIDTH_PER_VOLUME_DEFAULT;
+ @Config(key = "min.gap",
+ defaultValue = "15m",
+ type = ConfigType.TIME,
+ tags = { DATANODE },
+ description = "The minimum gap between two successive scans of the same"
+ + " container. Unit could be defined with"
+ + " postfix (ns,ms,s,m,h,d)."
+ )
+ private long containerScanMinGap = CONTAINER_SCAN_MIN_GAP_DEFAULT;
+
@PostConstruct
public void validate() {
if (metadataScanInterval < 0) {
@@ -117,6 +134,13 @@ public class ContainerScannerConfiguration {
dataScanInterval = DATA_SCAN_INTERVAL_DEFAULT;
}
+ if (containerScanMinGap < 0) {
+ LOG.warn(CONTAINER_SCAN_MIN_GAP +
+ " must be >= 0 and was set to {}. Defaulting to {}",
+ containerScanMinGap, CONTAINER_SCAN_MIN_GAP);
+ containerScanMinGap = CONTAINER_SCAN_MIN_GAP_DEFAULT;
+ }
+
if (bandwidthPerVolume < 0) {
LOG.warn(VOLUME_BYTES_PER_SECOND_KEY +
" must be >= 0 and was set to {}. Defaulting to {}",
@@ -162,4 +186,8 @@ public class ContainerScannerConfiguration {
public long getOnDemandBandwidthPerVolume() {
return onDemandBandwidthPerVolume;
}
+
+ public long getContainerScanMinGap() {
+ return containerScanMinGap;
+ }
}
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/OnDemandContainerScanner.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/OnDemandContainerDataScanner.java
similarity index 82%
rename from
hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/OnDemandContainerScanner.java
rename to
hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/OnDemandContainerDataScanner.java
index 69c8ba3fee..f0bf31257e 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/OnDemandContainerScanner.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/OnDemandContainerDataScanner.java
@@ -20,6 +20,7 @@ package org.apache.hadoop.ozone.container.ozoneimpl;
import com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.hdfs.util.Canceler;
import org.apache.hadoop.hdfs.util.DataTransferThrottler;
+import org.apache.hadoop.ozone.container.common.helpers.ContainerUtils;
import org.apache.hadoop.ozone.container.common.impl.ContainerData;
import org.apache.hadoop.ozone.container.common.interfaces.Container;
import org.slf4j.Logger;
@@ -37,11 +38,11 @@ import java.util.concurrent.TimeUnit;
/**
* Class for performing on demand scans of containers.
*/
-public final class OnDemandContainerScanner {
+public final class OnDemandContainerDataScanner {
public static final Logger LOG =
- LoggerFactory.getLogger(OnDemandContainerScanner.class);
+ LoggerFactory.getLogger(OnDemandContainerDataScanner.class);
- private static volatile OnDemandContainerScanner instance;
+ private static volatile OnDemandContainerDataScanner instance;
private final ExecutorService scanExecutor;
private final ContainerController containerController;
@@ -50,8 +51,9 @@ public final class OnDemandContainerScanner {
private final ConcurrentHashMap
.KeySetView<Long, Boolean> containerRescheduleCheckSet;
private final OnDemandScannerMetrics metrics;
+ private final long minScanGap;
- private OnDemandContainerScanner(
+ private OnDemandContainerDataScanner(
ContainerScannerConfiguration conf, ContainerController controller) {
containerController = controller;
throttler = new DataTransferThrottler(
@@ -60,6 +62,7 @@ public final class OnDemandContainerScanner {
metrics = OnDemandScannerMetrics.create();
scanExecutor = Executors.newSingleThreadExecutor();
containerRescheduleCheckSet = ConcurrentHashMap.newKeySet();
+ minScanGap = conf.getContainerScanMinGap();
}
public static synchronized void init(
@@ -69,20 +72,29 @@ public final class OnDemandContainerScanner {
" a second time on a datanode.");
return;
}
- instance = new OnDemandContainerScanner(conf, controller);
+ instance = new OnDemandContainerDataScanner(conf, controller);
+ }
+
+ private static boolean shouldScan(Container<?> container) {
+ if (instance == null) {
+ LOG.debug("Skipping on demand scan for container {} since scanner was " +
+ "not initialized.", container.getContainerData().getContainerID());
+ }
+ return instance != null &&
+ container.shouldScanData() &&
+ !ContainerUtils.recentlyScanned(container, instance.minScanGap, LOG);
}
public static Optional<Future<?>> scanContainer(Container<?> container) {
- if (instance == null || !container.shouldScanData()) {
+ if (!shouldScan(container)) {
return Optional.empty();
}
+
Future<?> resultFuture = null;
long containerId = container.getContainerData().getContainerID();
if (addContainerToScheduledContainers(containerId)) {
resultFuture = instance.scanExecutor.submit(() -> {
- if (container.shouldScanData()) {
- performOnDemandScan(container);
- }
+ performOnDemandScan(container);
removeContainerFromScheduledContainers(containerId);
});
}
@@ -99,19 +111,23 @@ public final class OnDemandContainerScanner {
}
private static void performOnDemandScan(Container<?> container) {
+ if (!shouldScan(container)) {
+ return;
+ }
+
long containerId = container.getContainerData().getContainerID();
try {
ContainerData containerData = container.getContainerData();
logScanStart(containerData);
- if (container.scanData(instance.throttler, instance.canceler)) {
- Instant now = Instant.now();
- logScanCompleted(containerData, now);
- instance.containerController.updateDataScanTimestamp(containerId, now);
- } else {
- instance.containerController.markContainerUnhealthy(containerId);
+ if (!container.scanData(instance.throttler, instance.canceler)) {
instance.metrics.incNumUnHealthyContainers();
+ instance.containerController.markContainerUnhealthy(containerId);
}
+
instance.metrics.incNumContainersScanned();
+ Instant now = Instant.now();
+ logScanCompleted(containerData, now);
+ instance.containerController.updateDataScanTimestamp(containerId, now);
} catch (IOException e) {
LOG.warn("Unexpected exception while scanning container "
+ containerId, e);
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/OzoneContainer.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/OzoneContainer.java
index d276b617d5..bc2461b3ff 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/OzoneContainer.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/OzoneContainer.java
@@ -106,8 +106,8 @@ public class OzoneContainer {
private final XceiverServerSpi writeChannel;
private final XceiverServerSpi readChannel;
private final ContainerController controller;
- private ContainerMetadataScanner metadataScanner;
- private List<ContainerDataScanner> dataScanners;
+ private BackgroundContainerMetadataScanner metadataScanner;
+ private List<BackgroundContainerDataScanner> dataScanners;
private final BlockDeletingService blockDeletingService;
private final StaleRecoveringContainerScrubbingService
recoveringContainerScrubbingService;
@@ -328,8 +328,8 @@ public class OzoneContainer {
}
dataScanners = new ArrayList<>();
for (StorageVolume v : volumeSet.getVolumesList()) {
- ContainerDataScanner s = new ContainerDataScanner(c, controller,
- (HddsVolume) v);
+ BackgroundContainerDataScanner s =
+ new BackgroundContainerDataScanner(c, controller, (HddsVolume) v);
s.start();
dataScanners.add(s);
}
@@ -337,7 +337,8 @@ public class OzoneContainer {
private void initMetadataScanner(ContainerScannerConfiguration c) {
if (this.metadataScanner == null) {
- this.metadataScanner = new ContainerMetadataScanner(c, controller);
+ this.metadataScanner =
+ new BackgroundContainerMetadataScanner(c, controller);
}
this.metadataScanner.start();
}
@@ -348,7 +349,7 @@ public class OzoneContainer {
"so the on-demand container data scanner will not start.");
return;
}
- OnDemandContainerScanner.init(c, controller);
+ OnDemandContainerDataScanner.init(c, controller);
}
/**
@@ -364,10 +365,10 @@ public class OzoneContainer {
if (dataScanners == null) {
return;
}
- for (ContainerDataScanner s : dataScanners) {
+ for (BackgroundContainerDataScanner s : dataScanners) {
s.shutdown();
}
- OnDemandContainerScanner.shutdown();
+ OnDemandContainerDataScanner.shutdown();
}
/**
diff --git
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/ContainerTestUtils.java
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/ContainerTestUtils.java
index 31d5000acb..2c912b277a 100644
---
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/ContainerTestUtils.java
+++
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/ContainerTestUtils.java
@@ -176,7 +176,7 @@ public final class ContainerTestUtils {
boolean scanMetaDataSuccess, boolean scanDataSuccess,
AtomicLong containerIdSeq) {
setupMockContainer(c, shouldScanData, scanDataSuccess, containerIdSeq);
- when(c.scanMetaData()).thenReturn(scanMetaDataSuccess);
+ Mockito.lenient().when(c.scanMetaData()).thenReturn(scanMetaDataSuccess);
}
public static void setupMockContainer(
diff --git
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestBackgroundContainerDataScanner.java
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestBackgroundContainerDataScanner.java
new file mode 100644
index 0000000000..dc39ee2a9d
--- /dev/null
+++
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestBackgroundContainerDataScanner.java
@@ -0,0 +1,134 @@
+/*
+ * 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.ozone.container.ozoneimpl;
+
+import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.BeforeEach;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.never;
+
+/**
+ * Unit tests for the background container data scanner.
+ */
+@MockitoSettings(strictness = Strictness.LENIENT)
+public class TestBackgroundContainerDataScanner extends
+ TestContainerScannersAbstract {
+
+ private BackgroundContainerDataScanner scanner;
+
+ @BeforeEach
+ public void setup() {
+ super.setup();
+ scanner = new BackgroundContainerDataScanner(conf, controller, vol);
+ }
+
+ @Test
+ @Override
+ public void testRecentlyScannedContainerIsSkipped() {
+ setScannedTimestampRecent(healthy);
+ scanner.runIteration();
+ Mockito.verify(healthy, never()).scanData(any(), any());
+ }
+
+ @Test
+ @Override
+ public void testPreviouslyScannedContainerIsScanned() {
+ // If the last scan time is before than the configured gap, the container
+ // should be scanned.
+ setScannedTimestampOld(healthy);
+ scanner.runIteration();
+ Mockito.verify(healthy, atLeastOnce()).scanData(any(), any());
+ }
+
+ @Test
+ @Override
+ public void testUnscannedContainerIsScanned() {
+ // If there is no last scanned time, the container should be scanned.
+ Mockito.when(healthy.getContainerData().lastDataScanTime())
+ .thenReturn(Optional.empty());
+ scanner.runIteration();
+ Mockito.verify(healthy, atLeastOnce()).scanData(any(), any());
+ }
+
+ @Test
+ @Override
+ public void testScannerMetrics() {
+ scanner.runIteration();
+
+ ContainerDataScannerMetrics metrics = scanner.getMetrics();
+ assertEquals(1, metrics.getNumScanIterations());
+ assertEquals(2, metrics.getNumContainersScanned());
+ assertEquals(1, metrics.getNumUnHealthyContainers());
+ }
+
+ @Test
+ @Override
+ public void testScannerMetricsUnregisters() {
+ String name = scanner.getMetrics().getName();
+
+ assertNotNull(DefaultMetricsSystem.instance().getSource(name));
+
+ scanner.shutdown();
+ scanner.run();
+
+ assertNull(DefaultMetricsSystem.instance().getSource(name));
+ }
+
+ @Test
+ @Override
+ public void testUnhealthyContainersDetected() throws Exception {
+ scanner.runIteration();
+ verifyContainerMarkedUnhealthy(healthy, never());
+ verifyContainerMarkedUnhealthy(corruptData, atLeastOnce());
+ verifyContainerMarkedUnhealthy(openCorruptMetadata, never());
+ verifyContainerMarkedUnhealthy(openContainer, never());
+ }
+
+ @Test
+ public void testScanTimestampUpdated() throws Exception {
+ scanner.runIteration();
+ // Open containers should not be scanned.
+ Mockito.verify(controller, never())
+ .updateDataScanTimestamp(
+ eq(openContainer.getContainerData().getContainerID()), any());
+ Mockito.verify(controller, never())
+ .updateDataScanTimestamp(
+ eq(openCorruptMetadata.getContainerData().getContainerID()),
any());
+ // All other containers should have been scanned.
+ Mockito.verify(controller, atLeastOnce())
+ .updateDataScanTimestamp(
+ eq(healthy.getContainerData().getContainerID()), any());
+ Mockito.verify(controller, atLeastOnce())
+ .updateDataScanTimestamp(
+ eq(corruptData.getContainerData().getContainerID()), any());
+ }
+}
diff --git
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestBackgroundContainerMetadataScanner.java
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestBackgroundContainerMetadataScanner.java
new file mode 100644
index 0000000000..8ae61a1a27
--- /dev/null
+++
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestBackgroundContainerMetadataScanner.java
@@ -0,0 +1,114 @@
+/*
+ * 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.ozone.container.ozoneimpl;
+
+import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.BeforeEach;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.never;
+
+/**
+ * Unit tests for the background container metadata scanner.
+ */
+@MockitoSettings(strictness = Strictness.LENIENT)
+public class TestBackgroundContainerMetadataScanner extends
+ TestContainerScannersAbstract {
+
+ private BackgroundContainerMetadataScanner scanner;
+
+ @BeforeEach
+ public void setup() {
+ super.setup();
+ scanner = new BackgroundContainerMetadataScanner(conf, controller);
+ }
+
+ @Test
+ @Override
+ public void testRecentlyScannedContainerIsSkipped() {
+ // If the last scan time is before than the configured gap, the container
+ // should be scanned.
+ setScannedTimestampRecent(healthy);
+ scanner.runIteration();
+ Mockito.verify(healthy, never()).scanMetaData();
+ }
+
+ @Test
+ @Override
+ public void testPreviouslyScannedContainerIsScanned() {
+ setScannedTimestampOld(healthy);
+ scanner.runIteration();
+ Mockito.verify(healthy, atLeastOnce()).scanMetaData();
+ }
+
+ @Test
+ @Override
+ public void testUnscannedContainerIsScanned() throws Exception {
+ // If there is no last scanned time, the container should be scanned.
+ Mockito.when(healthy.getContainerData().lastDataScanTime())
+ .thenReturn(Optional.empty());
+ scanner.runIteration();
+ Mockito.verify(healthy, atLeastOnce()).scanMetaData();
+ }
+
+ @Test
+ @Override
+ public void testScannerMetrics() {
+ scanner.runIteration();
+
+ ContainerMetadataScannerMetrics metrics = scanner.getMetrics();
+ assertEquals(1, metrics.getNumScanIterations());
+ assertEquals(3, metrics.getNumContainersScanned());
+ assertEquals(1, metrics.getNumUnHealthyContainers());
+ }
+
+ @Test
+ @Override
+ public void testScannerMetricsUnregisters() {
+ String name = scanner.getMetrics().getName();
+
+ assertNotNull(DefaultMetricsSystem.instance().getSource(name));
+
+ scanner.shutdown();
+ scanner.run();
+
+ assertNull(DefaultMetricsSystem.instance().getSource(name));
+ }
+
+ @Test
+ @Override
+ public void testUnhealthyContainersDetected() throws Exception {
+ scanner.runIteration();
+ verifyContainerMarkedUnhealthy(healthy, never());
+ // Metadata scanner cannot detect data corruption.
+ verifyContainerMarkedUnhealthy(corruptData, never());
+ verifyContainerMarkedUnhealthy(openCorruptMetadata, atLeastOnce());
+ verifyContainerMarkedUnhealthy(openContainer, never());
+ }
+}
diff --git
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestContainerScannerConfiguration.java
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestContainerScannerConfiguration.java
index 077acbb9d9..f11a7f5522 100644
---
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestContainerScannerConfiguration.java
+++
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestContainerScannerConfiguration.java
@@ -25,6 +25,8 @@ import org.junit.jupiter.api.Test;
import java.time.Duration;
import static
org.apache.hadoop.ozone.container.ozoneimpl.ContainerScannerConfiguration.BANDWIDTH_PER_VOLUME_DEFAULT;
+import static
org.apache.hadoop.ozone.container.ozoneimpl.ContainerScannerConfiguration.CONTAINER_SCAN_MIN_GAP;
+import static
org.apache.hadoop.ozone.container.ozoneimpl.ContainerScannerConfiguration.CONTAINER_SCAN_MIN_GAP_DEFAULT;
import static
org.apache.hadoop.ozone.container.ozoneimpl.ContainerScannerConfiguration.DATA_SCAN_INTERVAL_DEFAULT;
import static
org.apache.hadoop.ozone.container.ozoneimpl.ContainerScannerConfiguration.DATA_SCAN_INTERVAL_KEY;
import static
org.apache.hadoop.ozone.container.ozoneimpl.ContainerScannerConfiguration.METADATA_SCAN_INTERVAL_DEFAULT;
@@ -55,6 +57,7 @@ public class TestContainerScannerConfiguration {
conf.setLong(METADATA_SCAN_INTERVAL_KEY, validInterval);
conf.setLong(DATA_SCAN_INTERVAL_KEY, validInterval);
+ conf.setLong(CONTAINER_SCAN_MIN_GAP, validInterval);
conf.setLong(VOLUME_BYTES_PER_SECOND_KEY, validBandwidth);
conf.setLong(ON_DEMAND_VOLUME_BYTES_PER_SECOND_KEY,
validOnDemandBandwidth);
@@ -63,6 +66,7 @@ public class TestContainerScannerConfiguration {
assertEquals(validInterval, csConf.getMetadataScanInterval());
assertEquals(validInterval, csConf.getDataScanInterval());
+ assertEquals(validInterval, csConf.getContainerScanMinGap());
assertEquals(validBandwidth, csConf.getBandwidthPerVolume());
assertEquals(validOnDemandBandwidth,
csConf.getOnDemandBandwidthPerVolume());
@@ -75,6 +79,7 @@ public class TestContainerScannerConfiguration {
conf.setLong(METADATA_SCAN_INTERVAL_KEY, invalidInterval);
conf.setLong(DATA_SCAN_INTERVAL_KEY, invalidInterval);
+ conf.setLong(CONTAINER_SCAN_MIN_GAP, invalidInterval);
conf.setLong(VOLUME_BYTES_PER_SECOND_KEY, invalidBandwidth);
conf.setLong(ON_DEMAND_VOLUME_BYTES_PER_SECOND_KEY, invalidBandwidth);
@@ -85,6 +90,8 @@ public class TestContainerScannerConfiguration {
csConf.getMetadataScanInterval());
assertEquals(DATA_SCAN_INTERVAL_DEFAULT,
csConf.getDataScanInterval());
+ assertEquals(CONTAINER_SCAN_MIN_GAP_DEFAULT,
+ csConf.getContainerScanMinGap());
assertEquals(BANDWIDTH_PER_VOLUME_DEFAULT,
csConf.getBandwidthPerVolume());
assertEquals(ON_DEMAND_BANDWIDTH_PER_VOLUME_DEFAULT,
@@ -105,5 +112,7 @@ public class TestContainerScannerConfiguration {
csConf.getBandwidthPerVolume());
assertEquals(ON_DEMAND_BANDWIDTH_PER_VOLUME_DEFAULT,
csConf.getOnDemandBandwidthPerVolume());
+ assertEquals(CONTAINER_SCAN_MIN_GAP_DEFAULT,
+ csConf.getContainerScanMinGap());
}
}
diff --git
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestContainerScannerMetrics.java
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestContainerScannerMetrics.java
deleted file mode 100644
index 6d9eb31db1..0000000000
---
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestContainerScannerMetrics.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * 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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.ozone.container.ozoneimpl;
-
-import org.apache.commons.compress.utils.Lists;
-import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
-import org.apache.hadoop.ozone.container.common.ContainerTestUtils;
-import org.apache.hadoop.ozone.container.common.impl.ContainerData;
-import org.apache.hadoop.ozone.container.common.interfaces.Container;
-import org.apache.hadoop.ozone.container.common.volume.HddsVolume;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-import org.mockito.junit.jupiter.MockitoSettings;
-import org.mockito.quality.Strictness;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Optional;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.atomic.AtomicLong;
-
-import static org.apache.hadoop.hdds.conf.OzoneConfiguration.newInstanceOf;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-/**
- * This test verifies the container scanner metrics functionality.
- */
-@ExtendWith(MockitoExtension.class)
-@MockitoSettings(strictness = Strictness.LENIENT)
-public class TestContainerScannerMetrics {
-
- private final AtomicLong containerIdSeq = new AtomicLong(100);
-
- @Mock
- private Container<ContainerData> healthy;
-
- @Mock
- private Container<ContainerData> corruptMetadata;
-
- @Mock
- private Container<ContainerData> corruptData;
-
- @Mock
- private HddsVolume vol;
-
- private ContainerScannerConfiguration conf;
- private ContainerController controller;
-
- @BeforeEach
- public void setup() {
- conf = newInstanceOf(ContainerScannerConfiguration.class);
- conf.setMetadataScanInterval(0);
- conf.setDataScanInterval(0);
- conf.setEnabled(true);
- controller = mockContainerController();
- }
-
- @AfterEach
- public void tearDown() {
- OnDemandContainerScanner.shutdown();
- }
-
- @Test
- public void testContainerMetaDataScannerMetrics() {
- ContainerMetadataScanner subject =
- new ContainerMetadataScanner(conf, controller);
- subject.runIteration();
-
- ContainerMetadataScannerMetrics metrics = subject.getMetrics();
- assertEquals(1, metrics.getNumScanIterations());
- assertEquals(3, metrics.getNumContainersScanned());
- assertEquals(1, metrics.getNumUnHealthyContainers());
- }
-
- @Test
- public void testContainerMetaDataScannerMetricsUnregisters() {
- ContainerMetadataScanner subject =
- new ContainerMetadataScanner(conf, controller);
- String name = subject.getMetrics().getName();
-
- assertNotNull(DefaultMetricsSystem.instance().getSource(name));
-
- subject.shutdown();
- subject.run();
-
- assertNull(DefaultMetricsSystem.instance().getSource(name));
- }
-
- @Test
- public void testContainerDataScannerMetrics() {
- ContainerDataScanner subject =
- new ContainerDataScanner(conf, controller, vol);
- subject.runIteration();
-
- ContainerDataScannerMetrics metrics = subject.getMetrics();
- assertEquals(1, metrics.getNumScanIterations());
- assertEquals(2, metrics.getNumContainersScanned());
- assertEquals(1, metrics.getNumUnHealthyContainers());
- }
-
- @Test
- public void testContainerDataScannerMetricsUnregisters() throws IOException {
- HddsVolume volume = new HddsVolume.Builder("/").failedVolume(true).build();
- ContainerDataScanner subject =
- new ContainerDataScanner(conf, controller, volume);
- String name = subject.getMetrics().getName();
-
- assertNotNull(DefaultMetricsSystem.instance().getSource(name));
-
- subject.shutdown();
- subject.run();
-
- assertNull(DefaultMetricsSystem.instance().getSource(name));
- }
-
- @Test
- public void testOnDemandScannerMetrics() throws Exception {
- OnDemandContainerScanner.init(conf, controller);
- ArrayList<Optional<Future<?>>> resultFutureList = Lists.newArrayList();
- resultFutureList.add(OnDemandContainerScanner.scanContainer(corruptData));
- resultFutureList.add(
- OnDemandContainerScanner.scanContainer(corruptMetadata));
- resultFutureList.add(OnDemandContainerScanner.scanContainer(healthy));
- waitOnScannerToFinish(resultFutureList);
- OnDemandScannerMetrics metrics = OnDemandContainerScanner.getMetrics();
- //Containers with shouldScanData = false shouldn't increase
- // the number of scanned containers
- assertEquals(1, metrics.getNumUnHealthyContainers());
- assertEquals(2, metrics.getNumContainersScanned());
- }
-
- private void waitOnScannerToFinish(
- ArrayList<Optional<Future<?>>> resultFutureList)
- throws ExecutionException, InterruptedException {
- for (Optional<Future<?>> future : resultFutureList) {
- if (future.isPresent()) {
- future.get().get();
- }
- }
- }
-
- @Test
- public void testOnDemandScannerMetricsUnregisters() {
- OnDemandContainerScanner.init(conf, controller);
- String metricsName = OnDemandContainerScanner.getMetrics().getName();
- assertNotNull(DefaultMetricsSystem.instance().getSource(metricsName));
- OnDemandContainerScanner.shutdown();
- OnDemandContainerScanner.scanContainer(healthy);
- assertNull(DefaultMetricsSystem.instance().getSource(metricsName));
- }
-
- private ContainerController mockContainerController() {
- // healthy container
- ContainerTestUtils.setupMockContainer(healthy,
- true, true, true, containerIdSeq);
-
- // unhealthy container (corrupt data)
- ContainerTestUtils.setupMockContainer(corruptData,
- true, true, false, containerIdSeq);
-
- // unhealthy container (corrupt metadata)
- ContainerTestUtils.setupMockContainer(corruptMetadata,
- false, false, false, containerIdSeq);
-
- Collection<Container<?>> containers = Arrays.asList(
- healthy, corruptData, corruptMetadata);
- ContainerController mock = mock(ContainerController.class);
- when(mock.getContainers(vol)).thenReturn(containers.iterator());
- when(mock.getContainers()).thenReturn(containers.iterator());
-
- return mock;
- }
-}
diff --git
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestContainerScannersAbstract.java
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestContainerScannersAbstract.java
new file mode 100644
index 0000000000..4e00d3327b
--- /dev/null
+++
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestContainerScannersAbstract.java
@@ -0,0 +1,155 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.ozone.container.ozoneimpl;
+
+import org.apache.hadoop.ozone.container.common.ContainerTestUtils;
+import org.apache.hadoop.ozone.container.common.impl.ContainerData;
+import org.apache.hadoop.ozone.container.common.interfaces.Container;
+import org.apache.hadoop.ozone.container.common.volume.HddsVolume;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+import org.mockito.verification.VerificationMode;
+
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.apache.hadoop.hdds.conf.OzoneConfiguration.newInstanceOf;
+import static
org.apache.hadoop.ozone.container.ozoneimpl.ContainerScannerConfiguration.CONTAINER_SCAN_MIN_GAP_DEFAULT;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * General testing guidelines for the various container scanners whose tests
+ * subclass this one.
+ */
+@MockitoSettings(strictness = Strictness.LENIENT)
+@SuppressWarnings("checkstyle:VisibilityModifier")
+public abstract class TestContainerScannersAbstract {
+
+ private static final AtomicLong CONTAINER_SEQ_ID = new AtomicLong(100);
+
+ @Mock
+ protected Container<ContainerData> healthy;
+
+ @Mock
+ protected Container<ContainerData> openContainer;
+
+ @Mock
+ protected Container<ContainerData> openCorruptMetadata;
+
+ @Mock
+ protected Container<ContainerData> corruptData;
+
+ @Mock
+ protected HddsVolume vol;
+
+ protected ContainerScannerConfiguration conf;
+ protected ContainerController controller;
+
+ public void setup() {
+ conf = newInstanceOf(ContainerScannerConfiguration.class);
+ conf.setMetadataScanInterval(0);
+ conf.setDataScanInterval(0);
+ conf.setEnabled(true);
+ controller = mockContainerController();
+ }
+
+ // ALL SCANNERS SHOULD TEST THESE THINGS
+
+ @Test
+ public abstract void testRecentlyScannedContainerIsSkipped() throws
Exception;
+
+ @Test
+ public abstract void testPreviouslyScannedContainerIsScanned()
+ throws Exception;
+
+ @Test
+ public abstract void testUnscannedContainerIsScanned() throws Exception;
+
+ @Test
+ public abstract void testUnhealthyContainersDetected() throws Exception;
+
+ @Test
+ public abstract void testScannerMetrics() throws Exception;
+
+ @Test
+ public abstract void testScannerMetricsUnregisters() throws Exception;
+
+ // HELPER METHODS
+
+ protected void setScannedTimestampOld(Container<ContainerData> container) {
+ // If the last scan time is before than the configured gap, the container
+ // should be scanned.
+ Instant oldLastScanTime = Instant.now()
+ .minus(CONTAINER_SCAN_MIN_GAP_DEFAULT, ChronoUnit.MILLIS)
+ .minus(10, ChronoUnit.MINUTES);
+ Mockito.when(container.getContainerData().lastDataScanTime())
+ .thenReturn(Optional.of(oldLastScanTime));
+ }
+
+ protected void setScannedTimestampRecent(Container<ContainerData> container)
{
+ // If the last scan time is within the configured gap, the container
+ // should be skipped.
+ Instant recentLastScanTime = Instant.now()
+ .minus(CONTAINER_SCAN_MIN_GAP_DEFAULT, ChronoUnit.MILLIS)
+ .plus(1, ChronoUnit.MINUTES);
+ Mockito.when(container.getContainerData().lastDataScanTime())
+ .thenReturn(Optional.of(recentLastScanTime));
+ }
+
+ protected void verifyContainerMarkedUnhealthy(
+ Container<ContainerData> container, VerificationMode invocationTimes)
+ throws Exception {
+ Mockito.verify(controller, invocationTimes).markContainerUnhealthy(
+ container.getContainerData().getContainerID());
+ }
+
+ private ContainerController mockContainerController() {
+ // healthy container
+ ContainerTestUtils.setupMockContainer(healthy,
+ true, true, true, CONTAINER_SEQ_ID);
+
+ // Open container (only metadata can be scanned)
+ ContainerTestUtils.setupMockContainer(openContainer,
+ false, true, false, CONTAINER_SEQ_ID);
+
+ // unhealthy container (corrupt data)
+ ContainerTestUtils.setupMockContainer(corruptData,
+ true, true, false, CONTAINER_SEQ_ID);
+
+ // unhealthy container (corrupt metadata). To simulate container still
+ // being open while metadata is corrupted, shouldScanData will return
false.
+ ContainerTestUtils.setupMockContainer(openCorruptMetadata,
+ false, false, false, CONTAINER_SEQ_ID);
+
+ Collection<Container<?>> containers = Arrays.asList(
+ healthy, corruptData, openCorruptMetadata);
+ ContainerController mock = mock(ContainerController.class);
+ when(mock.getContainers(vol)).thenReturn(containers.iterator());
+ when(mock.getContainers()).thenReturn(containers.iterator());
+
+ return mock;
+ }
+}
diff --git
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestOnDemandContainerDataScanner.java
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestOnDemandContainerDataScanner.java
new file mode 100644
index 0000000000..033688a693
--- /dev/null
+++
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestOnDemandContainerDataScanner.java
@@ -0,0 +1,212 @@
+/*
+ * 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.ozone.container.ozoneimpl;
+
+import org.apache.commons.compress.utils.Lists;
+import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
+import org.apache.hadoop.ozone.container.common.impl.ContainerData;
+import org.apache.hadoop.ozone.container.common.interfaces.Container;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.Optional;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.never;
+
+/**
+ * Unit tests for the on-demand container scanner.
+ */
+@MockitoSettings(strictness = Strictness.LENIENT)
+public class TestOnDemandContainerDataScanner extends
+ TestContainerScannersAbstract {
+
+ @BeforeEach
+ public void setup() {
+ super.setup();
+ }
+
+ @Test
+ @Override
+ public void testRecentlyScannedContainerIsSkipped() throws Exception {
+ setScannedTimestampRecent(healthy);
+ scanContainer(healthy);
+ Mockito.verify(healthy, never()).scanData(any(), any());
+ }
+
+ @Test
+ @Override
+ public void testPreviouslyScannedContainerIsScanned() throws Exception {
+ // If the last scan time is before than the configured gap, the container
+ // should be scanned.
+ setScannedTimestampOld(healthy);
+ scanContainer(healthy);
+ Mockito.verify(healthy, atLeastOnce()).scanData(any(), any());
+ }
+
+ @Test
+ @Override
+ public void testUnscannedContainerIsScanned() throws Exception {
+ // If there is no last scanned time, the container should be scanned.
+ Mockito.when(healthy.getContainerData().lastDataScanTime())
+ .thenReturn(Optional.empty());
+ scanContainer(healthy);
+ Mockito.verify(healthy, atLeastOnce()).scanData(any(), any());
+ }
+
+ @AfterEach
+ public void tearDown() {
+ OnDemandContainerDataScanner.shutdown();
+ }
+
+ @Test
+ public void testScanTimestampUpdated() throws Exception {
+ OnDemandContainerDataScanner.init(conf, controller);
+ Optional<Future<?>> scanFuture =
+ OnDemandContainerDataScanner.scanContainer(healthy);
+ Assertions.assertTrue(scanFuture.isPresent());
+ scanFuture.get().get();
+ Mockito.verify(controller, atLeastOnce())
+ .updateDataScanTimestamp(
+ eq(healthy.getContainerData().getContainerID()), any());
+ }
+
+ @Test
+ public void testContainerScannerMultipleInitsAndShutdowns() throws Exception
{
+ OnDemandContainerDataScanner.init(conf, controller);
+ OnDemandContainerDataScanner.init(conf, controller);
+ OnDemandContainerDataScanner.shutdown();
+ OnDemandContainerDataScanner.shutdown();
+ //There shouldn't be an interaction after shutdown:
+ OnDemandContainerDataScanner.scanContainer(corruptData);
+ verifyContainerMarkedUnhealthy(corruptData, never());
+ }
+
+ @Test
+ public void testSameContainerQueuedMultipleTimes() throws Exception {
+ OnDemandContainerDataScanner.init(conf, controller);
+ //Given a container that has not finished scanning
+ CountDownLatch latch = new CountDownLatch(1);
+ Mockito.lenient().when(corruptData.scanData(
+ OnDemandContainerDataScanner.getThrottler(),
+ OnDemandContainerDataScanner.getCanceler()))
+ .thenAnswer((Answer<Boolean>) invocation -> {
+ latch.await();
+ return false;
+ });
+ Optional<Future<?>> onGoingScan = OnDemandContainerDataScanner
+ .scanContainer(corruptData);
+ Assertions.assertTrue(onGoingScan.isPresent());
+ Assertions.assertFalse(onGoingScan.get().isDone());
+ //When scheduling the same container again
+ Optional<Future<?>> secondScan = OnDemandContainerDataScanner
+ .scanContainer(corruptData);
+ //Then the second scan is not scheduled and the first scan can still finish
+ Assertions.assertFalse(secondScan.isPresent());
+ latch.countDown();
+ onGoingScan.get().get();
+ Mockito.verify(controller, atLeastOnce()).
+
markContainerUnhealthy(corruptData.getContainerData().getContainerID());
+ }
+
+ @Test
+ @Override
+ public void testScannerMetrics() throws Exception {
+ OnDemandContainerDataScanner.init(conf, controller);
+ ArrayList<Optional<Future<?>>> resultFutureList = Lists.newArrayList();
+ resultFutureList.add(OnDemandContainerDataScanner.scanContainer(
+ corruptData));
+ resultFutureList.add(
+ OnDemandContainerDataScanner.scanContainer(openContainer));
+ resultFutureList.add(
+ OnDemandContainerDataScanner.scanContainer(openCorruptMetadata));
+ resultFutureList.add(OnDemandContainerDataScanner.scanContainer(healthy));
+ waitOnScannerToFinish(resultFutureList);
+ OnDemandScannerMetrics metrics = OnDemandContainerDataScanner.getMetrics();
+ //Containers with shouldScanData = false shouldn't increase
+ // the number of scanned containers
+ assertEquals(1, metrics.getNumUnHealthyContainers());
+ assertEquals(2, metrics.getNumContainersScanned());
+ }
+
+ @Test
+ @Override
+ public void testScannerMetricsUnregisters() {
+ OnDemandContainerDataScanner.init(conf, controller);
+ String metricsName = OnDemandContainerDataScanner.getMetrics().getName();
+ assertNotNull(DefaultMetricsSystem.instance().getSource(metricsName));
+ OnDemandContainerDataScanner.shutdown();
+ OnDemandContainerDataScanner.scanContainer(healthy);
+ assertNull(DefaultMetricsSystem.instance().getSource(metricsName));
+ }
+
+ @Test
+ @Override
+ public void testUnhealthyContainersDetected() throws Exception {
+ // Without initialization,
+ // there shouldn't be interaction with containerController
+ OnDemandContainerDataScanner.scanContainer(corruptData);
+ Mockito.verifyZeroInteractions(controller);
+
+ scanContainer(healthy);
+ verifyContainerMarkedUnhealthy(healthy, never());
+ scanContainer(corruptData);
+ verifyContainerMarkedUnhealthy(corruptData, atLeastOnce());
+ scanContainer(openCorruptMetadata);
+ verifyContainerMarkedUnhealthy(openCorruptMetadata, never());
+ scanContainer(openContainer);
+ verifyContainerMarkedUnhealthy(openContainer, never());
+ }
+
+ private void scanContainer(Container<ContainerData> container)
+ throws Exception {
+ OnDemandContainerDataScanner.init(conf, controller);
+ Optional<Future<?>> scanFuture =
+ OnDemandContainerDataScanner.scanContainer(container);
+ if (scanFuture.isPresent()) {
+ scanFuture.get().get();
+ }
+ }
+
+ private void waitOnScannerToFinish(
+ ArrayList<Optional<Future<?>>> resultFutureList)
+ throws ExecutionException, InterruptedException {
+ for (Optional<Future<?>> future : resultFutureList) {
+ if (future.isPresent()) {
+ future.get().get();
+ }
+ }
+ }
+}
diff --git
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestOnDemandContainerScanner.java
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestOnDemandContainerScanner.java
deleted file mode 100644
index c2686b559c..0000000000
---
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestOnDemandContainerScanner.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * 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.ozone.container.ozoneimpl;
-
-import org.apache.hadoop.ozone.container.common.ContainerTestUtils;
-import org.apache.hadoop.ozone.container.common.impl.ContainerData;
-import org.apache.hadoop.ozone.container.common.interfaces.Container;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.junit.MockitoJUnitRunner;
-import org.mockito.stubbing.Answer;
-import org.mockito.verification.VerificationMode;
-
-import java.io.IOException;
-import java.util.Optional;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.atomic.AtomicLong;
-
-import static org.apache.hadoop.hdds.conf.OzoneConfiguration.newInstanceOf;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-
-/**
- * Unit tests for the on-demand container scanner.
- */
-@RunWith(MockitoJUnitRunner.class)
-public class TestOnDemandContainerScanner {
-
- private final AtomicLong containerIdSeq = new AtomicLong(100);
-
- @Mock
- private Container<ContainerData> healthy;
-
- @Mock
- private Container<ContainerData> openContainer;
-
- @Mock
- private Container<ContainerData> corruptData;
-
- private ContainerScannerConfiguration conf;
- private ContainerController controller;
-
- @Before
- public void setup() {
- conf = newInstanceOf(ContainerScannerConfiguration.class);
- conf.setMetadataScanInterval(0);
- conf.setDataScanInterval(0);
- controller = mockContainerController();
- }
-
- @After
- public void tearDown() {
- OnDemandContainerScanner.shutdown();
- }
-
- @Test
- public void testOnDemandContainerScanner() throws Exception {
- //Without initialization,
- // there shouldn't be interaction with containerController
- OnDemandContainerScanner.scanContainer(corruptData);
- Mockito.verifyZeroInteractions(controller);
- OnDemandContainerScanner.init(conf, controller);
- testContainerMarkedUnhealthy(healthy, never());
- testContainerMarkedUnhealthy(corruptData, atLeastOnce());
- testContainerMarkedUnhealthy(openContainer, never());
- }
-
- @Test
- public void testContainerScannerMultipleInitsAndShutdowns() throws Exception
{
- OnDemandContainerScanner.init(conf, controller);
- OnDemandContainerScanner.init(conf, controller);
- OnDemandContainerScanner.shutdown();
- OnDemandContainerScanner.shutdown();
- //There shouldn't be an interaction after shutdown:
- testContainerMarkedUnhealthy(corruptData, never());
- }
-
- @Test
- public void testSameContainerQueuedMultipleTimes() throws Exception {
- OnDemandContainerScanner.init(conf, controller);
- //Given a container that has not finished scanning
- CountDownLatch latch = new CountDownLatch(1);
- Mockito.lenient().when(corruptData.scanData(
- OnDemandContainerScanner.getThrottler(),
- OnDemandContainerScanner.getCanceler()))
- .thenAnswer((Answer<Boolean>) invocation -> {
- latch.await();
- return false;
- });
- Optional<Future<?>> onGoingScan = OnDemandContainerScanner
- .scanContainer(corruptData);
- Assert.assertTrue(onGoingScan.isPresent());
- Assert.assertFalse(onGoingScan.get().isDone());
- //When scheduling the same container again
- Optional<Future<?>> secondScan = OnDemandContainerScanner
- .scanContainer(corruptData);
- //Then the second scan is not scheduled and the first scan can still finish
- Assert.assertFalse(secondScan.isPresent());
- latch.countDown();
- onGoingScan.get().get();
- Mockito.verify(controller, atLeastOnce()).
-
markContainerUnhealthy(corruptData.getContainerData().getContainerID());
- }
-
- private void testContainerMarkedUnhealthy(
- Container<?> container, VerificationMode invocationTimes)
- throws InterruptedException, ExecutionException, IOException {
- Optional<Future<?>> result =
- OnDemandContainerScanner.scanContainer(container);
- if (result.isPresent()) {
- result.get().get();
- }
- Mockito.verify(controller, invocationTimes).markContainerUnhealthy(
- container.getContainerData().getContainerID());
- }
-
- private ContainerController mockContainerController() {
- // healthy container
- ContainerTestUtils.setupMockContainer(healthy,
- true, true, containerIdSeq);
-
- // unhealthy container (corrupt data)
- ContainerTestUtils.setupMockContainer(corruptData,
- true, false, containerIdSeq);
-
- // unhealthy container (corrupt metadata)
- ContainerTestUtils.setupMockContainer(openContainer,
- false, false, containerIdSeq);
-
- return mock(ContainerController.class);
- }
-}
diff --git
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/dn/scanner/TestDataScanner.java
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/dn/scanner/TestContainerDataScanners.java
similarity index 97%
rename from
hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/dn/scanner/TestDataScanner.java
rename to
hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/dn/scanner/TestContainerDataScanners.java
index f0ad740c45..16519a0001 100644
---
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/dn/scanner/TestDataScanner.java
+++
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/dn/scanner/TestContainerDataScanners.java
@@ -46,7 +46,7 @@ import org.apache.hadoop.ozone.container.ContainerTestHelper;
import org.apache.hadoop.ozone.container.TestHelper;
import org.apache.hadoop.ozone.container.common.impl.ContainerSet;
import org.apache.hadoop.ozone.container.common.interfaces.Container;
-import org.apache.hadoop.ozone.container.ozoneimpl.ContainerMetadataScanner;
+import
org.apache.hadoop.ozone.container.ozoneimpl.BackgroundContainerMetadataScanner;
import
org.apache.hadoop.ozone.container.ozoneimpl.ContainerScannerConfiguration;
import org.apache.hadoop.ozone.container.ozoneimpl.OzoneContainer;
import org.junit.AfterClass;
@@ -71,7 +71,7 @@ import static
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProt
/**
* This class tests the data scanner functionality.
*/
-public class TestDataScanner {
+public class TestContainerDataScanners {
/**
* Set a timeout for each test.
@@ -168,8 +168,8 @@ public class TestDataScanner {
ContainerScannerConfiguration conf = ozoneConfig.getObject(
ContainerScannerConfiguration.class);
- ContainerMetadataScanner sb = new ContainerMetadataScanner(conf,
- oc.getController());
+ BackgroundContainerMetadataScanner sb =
+ new BackgroundContainerMetadataScanner(conf, oc.getController());
//Scan the open container and trigger on-demand scan for the closed one
sb.scanContainer(openContainer);
tryReadKeyWithMissingChunksDir(bucket, keyNameInClosedContainer);
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]