This is an automated email from the ASF dual-hosted git repository.
sammichen 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 c708259b56 HDDS-8215. Recon - SCM DB Insights. (#4569)
c708259b56 is described below
commit c708259b566526dc707ae3b80520a5e0c5defbb5
Author: devmadhuu <[email protected]>
AuthorDate: Thu May 4 14:33:56 2023 +0530
HDDS-8215. Recon - SCM DB Insights. (#4569)
---
.../apache/hadoop/ozone/recon/ReconConstants.java | 2 +
.../hadoop/ozone/recon/api/BlocksEndPoint.java | 174 +++++++++++++
.../hadoop/ozone/recon/api/ContainerEndpoint.java | 118 +++++++--
.../api/types/ContainerBlocksInfoWrapper.java | 82 ++++++
.../recon/api/types/DeletedContainerInfo.java | 142 +++++++++++
.../scm/ReconStorageContainerManagerFacade.java | 6 +
.../hadoop/ozone/recon/api/TestBlocksEndPoint.java | 281 +++++++++++++++++++++
.../ozone/recon/api/TestContainerEndpoint.java | 242 +++++++++++++++---
8 files changed, 983 insertions(+), 64 deletions(-)
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/ReconConstants.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/ReconConstants.java
index 5a013dc9c9..bea8478f30 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/ReconConstants.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/ReconConstants.java
@@ -49,6 +49,8 @@ public final class ReconConstants {
public static final String RECON_QUERY_BATCH_PARAM = "batchNum";
public static final String RECON_QUERY_PREVKEY = "prevKey";
public static final String PREV_CONTAINER_ID_DEFAULT_VALUE = "0";
+ public static final String PREV_DELETED_BLOCKS_TRANSACTION_ID_DEFAULT_VALUE =
+ "0";
public static final String RECON_QUERY_LIMIT = "limit";
public static final String RECON_QUERY_VOLUME = "volume";
public static final String RECON_QUERY_BUCKET = "bucket";
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/BlocksEndPoint.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/BlocksEndPoint.java
new file mode 100644
index 0000000000..920d4122b0
--- /dev/null
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/BlocksEndPoint.java
@@ -0,0 +1,174 @@
+/**
+ * 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.recon.api;
+
+import
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos;
+import org.apache.hadoop.hdds.scm.container.ContainerID;
+import org.apache.hadoop.hdds.utils.db.DBStore;
+import org.apache.hadoop.hdds.utils.db.Table;
+import org.apache.hadoop.hdds.utils.db.TableIterator;
+import org.apache.hadoop.ozone.recon.api.types.ContainerBlocksInfoWrapper;
+import org.apache.hadoop.ozone.recon.scm.ReconContainerManager;
+import org.apache.hadoop.ozone.recon.scm.ReconStorageContainerManagerFacade;
+
+import javax.inject.Inject;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static
org.apache.hadoop.hdds.scm.metadata.SCMDBDefinition.DELETED_BLOCKS;
+import static org.apache.hadoop.ozone.recon.ReconConstants.DEFAULT_FETCH_COUNT;
+import static
org.apache.hadoop.ozone.recon.ReconConstants.PREV_DELETED_BLOCKS_TRANSACTION_ID_DEFAULT_VALUE;
+import static org.apache.hadoop.ozone.recon.ReconConstants.RECON_QUERY_LIMIT;
+import static org.apache.hadoop.ozone.recon.ReconConstants.RECON_QUERY_PREVKEY;
+
+/**
+ * Endpoint to get following information about blocks metadata.
+ * Number of blocks pending deletion.
+ * - Blocks pending deletion for open/closing containers.
+ * - Blocks pending deletion for closed containers.
+ */
+@Path("/blocks")
+@Produces(MediaType.APPLICATION_JSON)
+@AdminOnly
+public class BlocksEndPoint {
+ private final DBStore scmDBStore;
+ private final ReconContainerManager containerManager;
+
+ @Inject
+ public BlocksEndPoint(ReconStorageContainerManagerFacade reconSCM) {
+ this.containerManager =
+ (ReconContainerManager) reconSCM.getContainerManager();
+ this.scmDBStore = reconSCM.getScmDBStore();
+ }
+
+ /**
+ * This API returns list of blocks grouped by container state
+ * (OPEN/CLOSING/CLOSED).
+ * {
+ * "OPEN": [
+ * {
+ * "containerId": 100,
+ * "localIDList": [
+ * 1,
+ * 2,
+ * 3,
+ * 4
+ * ],
+ * "localIDCount": 4,
+ * "txID": 1
+ * }
+ * ]
+ * }
+ * @param limit limits the number of records having list of blocks
+ * grouped by container state (OPEN/CLOSING/CLOSED)
+ * @param prevKey deletedBlocks table key to skip records before prevKey
+ * @return list of blocks grouped by container state (OPEN/CLOSING/CLOSED)
+ */
+ @GET
+ @Path("/deletePending")
+ public Response getBlocksPendingDeletion(
+ @DefaultValue(DEFAULT_FETCH_COUNT) @QueryParam(RECON_QUERY_LIMIT)
+ int limit,
+ @DefaultValue(PREV_DELETED_BLOCKS_TRANSACTION_ID_DEFAULT_VALUE)
+ @QueryParam(RECON_QUERY_PREVKEY) long prevKey) {
+ if (limit < 0 || prevKey < 0) {
+ // Send back an empty response
+ return Response.status(Response.Status.NOT_ACCEPTABLE).build();
+ }
+ Map<String, List<ContainerBlocksInfoWrapper>>
+ containerStateBlockInfoListMap = new HashMap<>();
+ try (
+ Table<Long,
+ StorageContainerDatanodeProtocolProtos.DeletedBlocksTransaction>
+ deletedBlocksTXTable = DELETED_BLOCKS.getTable(this.scmDBStore);
+ TableIterator<Long, ? extends Table.KeyValue<Long,
+ StorageContainerDatanodeProtocolProtos.DeletedBlocksTransaction>>
+ deletedBlocksTableIterator = deletedBlocksTXTable.iterator()) {
+ boolean skipPrevKey = false;
+ Long seekKey = prevKey;
+ if (prevKey > 0) {
+ skipPrevKey = true;
+ Table.KeyValue<Long,
+ StorageContainerDatanodeProtocolProtos.DeletedBlocksTransaction>
+ seekKeyValue =
+ deletedBlocksTableIterator.seek(seekKey);
+ // check if RocksDB was able to seek correctly to the given key prefix
+ // if not, then return empty result
+ if (seekKeyValue == null) {
+ return Response.ok(containerStateBlockInfoListMap).build();
+ }
+ }
+ while (deletedBlocksTableIterator.hasNext()) {
+ Table.KeyValue<Long,
+ StorageContainerDatanodeProtocolProtos.DeletedBlocksTransaction>
+ kv = deletedBlocksTableIterator.next();
+ Long key = kv.getKey();
+ StorageContainerDatanodeProtocolProtos.DeletedBlocksTransaction
+ deletedBlocksTransaction =
+ kv.getValue();
+ // skip the prev key if prev key is present
+ if (skipPrevKey && key.equals(prevKey)) {
+ continue;
+ }
+ long containerID = deletedBlocksTransaction.getContainerID();
+ String containerState =
+ containerManager.getContainer(ContainerID.valueOf(containerID))
+ .getState().name();
+ ContainerBlocksInfoWrapper containerBlocksInfoWrapper =
+ new ContainerBlocksInfoWrapper();
+ containerBlocksInfoWrapper.setContainerID(containerID);
+ containerBlocksInfoWrapper.setLocalIDList(
+ deletedBlocksTransaction.getLocalIDList());
+ containerBlocksInfoWrapper.setLocalIDCount(
+ deletedBlocksTransaction.getLocalIDCount());
+ containerBlocksInfoWrapper.setTxID(deletedBlocksTransaction.getTxID());
+ List<ContainerBlocksInfoWrapper> containerBlocksInfoWrappers;
+ if (containerStateBlockInfoListMap.containsKey(containerState)) {
+ containerBlocksInfoWrappers =
+ containerStateBlockInfoListMap.get(containerState);
+ } else {
+ containerBlocksInfoWrappers = new ArrayList<>();
+ containerStateBlockInfoListMap.put(containerState,
+ containerBlocksInfoWrappers);
+ }
+ containerBlocksInfoWrappers.add(containerBlocksInfoWrapper);
+ // limit is applied based on number of containers per state
+ if (containerBlocksInfoWrappers.size() >= limit) {
+ break;
+ }
+ }
+ } catch (IllegalArgumentException e) {
+ throw new WebApplicationException(e, Response.Status.BAD_REQUEST);
+ } catch (Exception ex) {
+ throw new WebApplicationException(ex,
+ Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ return Response.ok(containerStateBlockInfoListMap).build();
+ }
+}
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ContainerEndpoint.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ContainerEndpoint.java
index de492f1ae9..5fe8a657cf 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ContainerEndpoint.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ContainerEndpoint.java
@@ -17,28 +17,8 @@
*/
package org.apache.hadoop.ozone.recon.api;
-import java.io.IOException;
-import java.time.Instant;
-import java.util.Collection;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-import java.util.stream.Collectors;
-
-import javax.ws.rs.DefaultValue;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-import javax.inject.Inject;
import org.apache.commons.lang3.StringUtils;
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
import org.apache.hadoop.hdds.scm.container.ContainerID;
import org.apache.hadoop.hdds.scm.container.ContainerInfo;
import org.apache.hadoop.hdds.scm.server.OzoneStorageContainerManager;
@@ -49,16 +29,17 @@ import
org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfoGroup;
import org.apache.hadoop.ozone.recon.api.types.ContainerKeyPrefix;
import org.apache.hadoop.ozone.recon.api.types.ContainerMetadata;
import org.apache.hadoop.ozone.recon.api.types.ContainersResponse;
+import org.apache.hadoop.ozone.recon.api.types.DeletedContainerInfo;
import org.apache.hadoop.ozone.recon.api.types.KeyMetadata;
+import
org.apache.hadoop.ozone.recon.api.types.KeyMetadata.ContainerBlockMetadata;
import org.apache.hadoop.ozone.recon.api.types.KeysResponse;
import org.apache.hadoop.ozone.recon.api.types.MissingContainerMetadata;
import org.apache.hadoop.ozone.recon.api.types.MissingContainersResponse;
import org.apache.hadoop.ozone.recon.api.types.UnhealthyContainerMetadata;
-import org.apache.hadoop.ozone.recon.api.types.UnhealthyContainersSummary;
import org.apache.hadoop.ozone.recon.api.types.UnhealthyContainersResponse;
-import
org.apache.hadoop.ozone.recon.api.types.KeyMetadata.ContainerBlockMetadata;
-import org.apache.hadoop.ozone.recon.persistence.ContainerHistory;
+import org.apache.hadoop.ozone.recon.api.types.UnhealthyContainersSummary;
import org.apache.hadoop.ozone.recon.persistence.ContainerHealthSchemaManager;
+import org.apache.hadoop.ozone.recon.persistence.ContainerHistory;
import org.apache.hadoop.ozone.recon.recovery.ReconOMMetadataManager;
import org.apache.hadoop.ozone.recon.scm.ReconContainerManager;
import org.apache.hadoop.ozone.recon.spi.ReconContainerMetadataManager;
@@ -68,6 +49,26 @@ import
org.hadoop.ozone.recon.schema.tables.pojos.UnhealthyContainers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.inject.Inject;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
import static
org.apache.hadoop.ozone.recon.ReconConstants.DEFAULT_BATCH_NUMBER;
import static org.apache.hadoop.ozone.recon.ReconConstants.DEFAULT_FETCH_COUNT;
import static
org.apache.hadoop.ozone.recon.ReconConstants.PREV_CONTAINER_ID_DEFAULT_VALUE;
@@ -390,6 +391,72 @@ public class ContainerEndpoint {
return getUnhealthyContainers(null, limit, batchNum);
}
+ /**
+ * This API will return all DELETED containers in SCM in below JSON format.
+ * {
+ * containers: [
+ * {
+ * containerId: 1,
+ * state: DELETED,
+ * pipelineId: "a10ffab6-8ed5-414a-aaf5-79890ff3e8a1",
+ * numOfKeys: 3,
+ * inStateSince: <stateEnterTime>
+ * },
+ * {
+ * containerId: 2,
+ * state: DELETED,
+ * pipelineId: "a10ffab6-8ed5-414a-aaf5-79890ff3e8a1",
+ * numOfKeys: 6,
+ * inStateSince: <stateEnterTime>
+ * }
+ * ]
+ * }
+ * @param limit limits the number of deleted containers
+ * @param prevKey previous container Id to skip
+ * @return Response of delete containers.
+ */
+ @GET
+ @Path("/deleted")
+ public Response getSCMDeletedContainers(
+ @DefaultValue(DEFAULT_FETCH_COUNT) @QueryParam(RECON_QUERY_LIMIT)
+ int limit,
+ @DefaultValue(PREV_CONTAINER_ID_DEFAULT_VALUE)
+ @QueryParam(RECON_QUERY_PREVKEY) long prevKey) {
+ List<DeletedContainerInfo> deletedContainerInfoList = new ArrayList<>();
+ try {
+ List<ContainerInfo> containers =
+ containerManager.getContainers(ContainerID.valueOf(prevKey), limit,
+ HddsProtos.LifeCycleState.DELETED);
+ containers = containers.stream()
+ .filter(containerInfo -> !(containerInfo.getContainerID() ==
prevKey))
+ .collect(
+ Collectors.toList());
+ containers.forEach(containerInfo -> {
+ DeletedContainerInfo deletedContainerInfo = new DeletedContainerInfo();
+ deletedContainerInfo.setContainerID(containerInfo.getContainerID());
+ deletedContainerInfo.setPipelineID(containerInfo.getPipelineID());
+ deletedContainerInfo.setNumberOfKeys(containerInfo.getNumberOfKeys());
+
deletedContainerInfo.setContainerState(containerInfo.getState().name());
+ deletedContainerInfo.setStateEnterTime(
+ containerInfo.getStateEnterTime().toEpochMilli());
+ deletedContainerInfo.setLastUsed(
+ containerInfo.getLastUsed().toEpochMilli());
+ deletedContainerInfo.setUsedBytes(containerInfo.getUsedBytes());
+ deletedContainerInfo.setReplicationConfig(
+ containerInfo.getReplicationConfig());
+ deletedContainerInfo.setReplicationFactor(
+ containerInfo.getReplicationFactor().name());
+ deletedContainerInfoList.add(deletedContainerInfo);
+ });
+ } catch (IllegalArgumentException e) {
+ throw new WebApplicationException(e, Response.Status.BAD_REQUEST);
+ } catch (Exception ex) {
+ throw new WebApplicationException(ex,
+ Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ return Response.ok(deletedContainerInfoList).build();
+ }
+
/**
* Helper function to extract the blocks for a given container from a given
* OM Key.
@@ -414,7 +481,4 @@ public class ContainerEndpoint {
return blockIds;
}
- private BucketLayout getBucketLayout() {
- return BucketLayout.DEFAULT;
- }
}
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/ContainerBlocksInfoWrapper.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/ContainerBlocksInfoWrapper.java
new file mode 100644
index 0000000000..35a270c225
--- /dev/null
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/ContainerBlocksInfoWrapper.java
@@ -0,0 +1,82 @@
+/**
+ * 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.recon.api.types;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class wraps containers and their associated blocks information.
+ */
+public class ContainerBlocksInfoWrapper {
+ @JsonProperty("containerId")
+ @JsonInclude(JsonInclude.Include.NON_DEFAULT)
+ private long containerID;
+ @JsonProperty("localIDList")
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ private List<Long> localIDList;
+ @JsonProperty("localIDCount")
+ @JsonInclude(JsonInclude.Include.NON_DEFAULT)
+ private int localIDCount;
+ @JsonProperty("txID")
+ @JsonInclude(JsonInclude.Include.NON_DEFAULT)
+ private long txID;
+
+ public ContainerBlocksInfoWrapper() {
+ this.containerID = 0;
+ this.localIDList = new ArrayList<>();
+ this.localIDCount = 0;
+ this.txID = -1;
+ }
+
+ public long getContainerID() {
+ return containerID;
+ }
+
+ public void setContainerID(long containerID) {
+ this.containerID = containerID;
+ }
+
+ public List<Long> getLocalIDList() {
+ return localIDList;
+ }
+
+ public void setLocalIDList(List<Long> localIDList) {
+ this.localIDList = localIDList;
+ }
+
+ public int getLocalIDCount() {
+ return localIDCount;
+ }
+
+ public void setLocalIDCount(int localIDCount) {
+ this.localIDCount = localIDCount;
+ }
+
+ public long getTxID() {
+ return txID;
+ }
+
+ public void setTxID(long txID) {
+ this.txID = txID;
+ }
+}
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/DeletedContainerInfo.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/DeletedContainerInfo.java
new file mode 100644
index 0000000000..c1629dc950
--- /dev/null
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/DeletedContainerInfo.java
@@ -0,0 +1,142 @@
+/*
+ * 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.recon.api.types;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.apache.hadoop.hdds.client.ReplicationConfig;
+import org.apache.hadoop.hdds.scm.pipeline.PipelineID;
+
+/**
+ * This class wraps deleted container info for API response.
+ */
+public class DeletedContainerInfo {
+
+ @JsonProperty("containerId")
+ @JsonInclude(JsonInclude.Include.NON_DEFAULT)
+ private long containerID;
+
+ @JsonProperty("pipelineID")
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ private PipelineID pipelineID;
+
+ @JsonProperty("numberOfKeys")
+ @JsonInclude(JsonInclude.Include.NON_DEFAULT)
+ private long numberOfKeys;
+
+ @JsonProperty("containerState")
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ private String containerState;
+
+ @JsonProperty("stateEnterTime")
+ @JsonInclude(JsonInclude.Include.NON_DEFAULT)
+ private long stateEnterTime;
+
+ @JsonProperty("lastUsed")
+ @JsonInclude(JsonInclude.Include.NON_DEFAULT)
+ private long lastUsed;
+
+ @JsonProperty("usedBytes")
+ @JsonInclude(JsonInclude.Include.NON_DEFAULT)
+ private long usedBytes;
+
+ @JsonProperty("replicationConfig")
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ private ReplicationConfig replicationConfig;
+
+ @JsonProperty("replicationFactor")
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ private String replicationFactor;
+
+ public DeletedContainerInfo() {
+
+ }
+
+ public long getContainerID() {
+ return containerID;
+ }
+
+ public void setContainerID(long containerID) {
+ this.containerID = containerID;
+ }
+
+ public PipelineID getPipelineID() {
+ return pipelineID;
+ }
+
+ public void setPipelineID(PipelineID pipelineID) {
+ this.pipelineID = pipelineID;
+ }
+
+ public long getNumberOfKeys() {
+ return numberOfKeys;
+ }
+
+ public void setNumberOfKeys(long numberOfKeys) {
+ this.numberOfKeys = numberOfKeys;
+ }
+
+ public String getContainerState() {
+ return containerState;
+ }
+
+ public void setContainerState(String containerState) {
+ this.containerState = containerState;
+ }
+
+ public long getStateEnterTime() {
+ return stateEnterTime;
+ }
+
+ public void setStateEnterTime(long stateEnterTime) {
+ this.stateEnterTime = stateEnterTime;
+ }
+
+ public long getLastUsed() {
+ return lastUsed;
+ }
+
+ public void setLastUsed(long lastUsed) {
+ this.lastUsed = lastUsed;
+ }
+
+ public long getUsedBytes() {
+ return usedBytes;
+ }
+
+ public void setUsedBytes(long usedBytes) {
+ this.usedBytes = usedBytes;
+ }
+
+ public ReplicationConfig getReplicationConfig() {
+ return replicationConfig;
+ }
+
+ public void setReplicationConfig(
+ ReplicationConfig replicationConfig) {
+ this.replicationConfig = replicationConfig;
+ }
+
+ public String getReplicationFactor() {
+ return replicationFactor;
+ }
+
+ public void setReplicationFactor(String replicationFactor) {
+ this.replicationFactor = replicationFactor;
+ }
+}
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ReconStorageContainerManagerFacade.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ReconStorageContainerManagerFacade.java
index e7ab206cf4..22009392fa 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ReconStorageContainerManagerFacade.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ReconStorageContainerManagerFacade.java
@@ -37,6 +37,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
+import com.google.inject.Singleton;
import org.apache.commons.io.FileUtils;
import org.apache.hadoop.fs.CommonConfigurationKeys;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
@@ -118,6 +119,7 @@ import org.slf4j.LoggerFactory;
/**
* Recon's 'lite' version of SCM.
*/
+@Singleton
public class ReconStorageContainerManagerFacade
implements OzoneStorageContainerManager {
@@ -665,6 +667,10 @@ public class ReconStorageContainerManagerFacade
return reconNodeDetails;
}
+ public DBStore getScmDBStore() {
+ return dbStore;
+ }
+
public EventQueue getEventQueue() {
return eventQueue;
}
diff --git
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestBlocksEndPoint.java
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestBlocksEndPoint.java
new file mode 100644
index 0000000000..385345a5e8
--- /dev/null
+++
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestBlocksEndPoint.java
@@ -0,0 +1,281 @@
+/**
+ * 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.recon.api;
+
+import org.apache.hadoop.hdds.client.StandaloneReplicationConfig;
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
+import
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos;
+import org.apache.hadoop.hdds.scm.container.ContainerID;
+import org.apache.hadoop.hdds.scm.container.ContainerInfo;
+import
org.apache.hadoop.hdds.scm.container.common.helpers.ContainerWithPipeline;
+import org.apache.hadoop.hdds.scm.pipeline.Pipeline;
+import org.apache.hadoop.hdds.scm.server.OzoneStorageContainerManager;
+import org.apache.hadoop.hdds.utils.db.DBStore;
+import org.apache.hadoop.hdds.utils.db.Table;
+import org.apache.hadoop.ozone.recon.ReconTestInjector;
+import org.apache.hadoop.ozone.recon.api.types.ContainerBlocksInfoWrapper;
+import org.apache.hadoop.ozone.recon.recovery.ReconOMMetadataManager;
+import org.apache.hadoop.ozone.recon.scm.ReconContainerManager;
+import org.apache.hadoop.ozone.recon.scm.ReconPipelineManager;
+import org.apache.hadoop.ozone.recon.scm.ReconStorageContainerManagerFacade;
+import org.apache.hadoop.ozone.recon.spi.StorageContainerServiceProvider;
+import org.apache.hadoop.ozone.recon.spi.impl.OzoneManagerServiceProviderImpl;
+import
org.apache.hadoop.ozone.recon.spi.impl.StorageContainerServiceProviderImpl;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
+import org.junit.rules.TemporaryFolder;
+
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeoutException;
+
+import static
org.apache.hadoop.hdds.protocol.proto.HddsProtos.ReplicationFactor.ONE;
+import static
org.apache.hadoop.hdds.scm.metadata.SCMDBDefinition.DELETED_BLOCKS;
+import static
org.apache.hadoop.ozone.recon.OMMetadataManagerTestUtils.getRandomPipeline;
+import static
org.apache.hadoop.ozone.recon.OMMetadataManagerTestUtils.getTestReconOmMetadataManager;
+import static
org.apache.hadoop.ozone.recon.OMMetadataManagerTestUtils.initializeNewOmMetadataManager;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Unit tests for APIs in BlocksEndPoint.
+ */
+public class TestBlocksEndPoint {
+
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ private ReconStorageContainerManagerFacade reconStorageContainerManager;
+ private ReconContainerManager reconContainerManager;
+ private ReconPipelineManager reconPipelineManager;
+ private BlocksEndPoint blocksEndPoint;
+ private boolean isSetupDone = false;
+ private ReconOMMetadataManager reconOMMetadataManager;
+ private DBStore scmDBStore;
+
+ private void initializeInjector() throws Exception {
+ reconOMMetadataManager = getTestReconOmMetadataManager(
+ initializeNewOmMetadataManager(temporaryFolder.newFolder()),
+ temporaryFolder.newFolder());
+
+ ReconTestInjector reconTestInjector =
+ new ReconTestInjector.Builder(temporaryFolder)
+ .withReconSqlDb()
+ .withReconOm(reconOMMetadataManager)
+ .withOmServiceProvider(mock(OzoneManagerServiceProviderImpl.class))
+ // No longer using mock reconSCM as we need nodeDB in Facade
+ // to establish datanode UUID to hostname mapping
+ .addBinding(OzoneStorageContainerManager.class,
+ ReconStorageContainerManagerFacade.class)
+ .withContainerDB()
+ .addBinding(StorageContainerServiceProvider.class,
+ mock(StorageContainerServiceProviderImpl.class))
+ .addBinding(ContainerEndpoint.class)
+ .addBinding(BlocksEndPoint.class)
+ .build();
+
+ reconStorageContainerManager =
+
reconTestInjector.getInstance(ReconStorageContainerManagerFacade.class);
+ reconContainerManager = (ReconContainerManager)
+ reconStorageContainerManager.getContainerManager();
+ reconPipelineManager = (ReconPipelineManager)
+ reconStorageContainerManager.getPipelineManager();
+ blocksEndPoint = reconTestInjector.getInstance(
+ BlocksEndPoint.class);
+ scmDBStore = reconStorageContainerManager.getScmDBStore();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ // The following setup runs only once
+ if (!isSetupDone) {
+ initializeInjector();
+ isSetupDone = true;
+ }
+ reconContainerManager.addNewContainer(
+ getTestContainer(HddsProtos.LifeCycleState.OPEN, 100L));
+ reconContainerManager.addNewContainer(
+ getTestContainer(HddsProtos.LifeCycleState.OPEN, 101L));
+ reconContainerManager.addNewContainer(
+ getTestContainer(HddsProtos.LifeCycleState.OPEN, 102L));
+ reconContainerManager.addNewContainer(
+ getTestContainer(HddsProtos.LifeCycleState.OPEN, 103L));
+ reconContainerManager.addNewContainer(
+ getTestContainer(HddsProtos.LifeCycleState.OPEN, 104L));
+ reconContainerManager.addNewContainer(
+ getTestContainer(HddsProtos.LifeCycleState.OPEN, 105L));
+ reconContainerManager.addNewContainer(
+ getTestContainer(HddsProtos.LifeCycleState.OPEN, 106L));
+ reconContainerManager.addNewContainer(
+ getTestContainer(HddsProtos.LifeCycleState.OPEN, 107L));
+ }
+
+ @Test
+ public void testGetBlocksPendingDeletion() throws Exception {
+ List<Long> localIdList = new ArrayList<>();
+ localIdList.add(1L);
+ localIdList.add(2L);
+ localIdList.add(3L);
+ localIdList.add(4L);
+ StorageContainerDatanodeProtocolProtos.DeletedBlocksTransaction dtx =
+ StorageContainerDatanodeProtocolProtos.DeletedBlocksTransaction
+ .newBuilder().setTxID(1).setContainerID(100L)
+ .addAllLocalID(localIdList).setCount(4).build();
+
+ Table<Long,
StorageContainerDatanodeProtocolProtos.DeletedBlocksTransaction>
+ deletedBlocksTable = DELETED_BLOCKS.getTable(this.scmDBStore);
+ deletedBlocksTable.put(1L, dtx);
+
+ Response blocksPendingDeletion =
+ blocksEndPoint.getBlocksPendingDeletion(1, 0);
+ Map<String, List<ContainerBlocksInfoWrapper>>
+ containerStateBlockInfoListMap =
+ (Map<String, List<ContainerBlocksInfoWrapper>>)
+ blocksPendingDeletion.getEntity();
+ Assertions.assertNotNull(containerStateBlockInfoListMap);
+ Assertions.assertEquals(1, containerStateBlockInfoListMap.size());
+ List<ContainerBlocksInfoWrapper> containerBlocksInfoWrappers =
+ containerStateBlockInfoListMap.get("OPEN");
+ ContainerBlocksInfoWrapper containerBlocksInfoWrapper =
+ containerBlocksInfoWrappers.get(0);
+ Assertions.assertEquals(100, containerBlocksInfoWrapper.getContainerID());
+ Assertions.assertEquals(4, containerBlocksInfoWrapper.getLocalIDCount());
+ Assertions.assertEquals(4,
+ containerBlocksInfoWrapper.getLocalIDList().size());
+ Assertions.assertEquals(1, containerBlocksInfoWrapper.getTxID());
+ }
+
+ @Test
+ public void testGetBlocksPendingDeletionLimitParam() throws Exception {
+ List<Long> localIdList = new ArrayList<>();
+ localIdList.add(1L);
+ localIdList.add(2L);
+ localIdList.add(3L);
+ localIdList.add(4L);
+ StorageContainerDatanodeProtocolProtos.DeletedBlocksTransaction dtx =
+ StorageContainerDatanodeProtocolProtos.DeletedBlocksTransaction
+ .newBuilder().setTxID(1).setContainerID(100L)
+ .addAllLocalID(localIdList).setCount(4).build();
+
+ Table<Long,
StorageContainerDatanodeProtocolProtos.DeletedBlocksTransaction>
+ deletedBlocksTable = DELETED_BLOCKS.getTable(this.scmDBStore);
+ deletedBlocksTable.put(1L, dtx);
+
+ dtx =
+ StorageContainerDatanodeProtocolProtos.DeletedBlocksTransaction
+ .newBuilder().setTxID(2).setContainerID(101L)
+ .addAllLocalID(localIdList).setCount(4).build();
+ deletedBlocksTable.put(2L, dtx);
+
+ Response blocksPendingDeletion =
+ blocksEndPoint.getBlocksPendingDeletion(1, 0);
+ Map<String, List<ContainerBlocksInfoWrapper>>
+ containerStateBlockInfoListMap =
+ (Map<String, List<ContainerBlocksInfoWrapper>>)
+ blocksPendingDeletion.getEntity();
+ Assertions.assertNotNull(containerStateBlockInfoListMap);
+ Assertions.assertEquals(1, containerStateBlockInfoListMap.size());
+ List<ContainerBlocksInfoWrapper> containerBlocksInfoWrappers =
+ containerStateBlockInfoListMap.get("OPEN");
+ ContainerBlocksInfoWrapper containerBlocksInfoWrapper =
+ containerBlocksInfoWrappers.get(0);
+ Assertions.assertEquals(100, containerBlocksInfoWrapper.getContainerID());
+ Assertions.assertEquals(4, containerBlocksInfoWrapper.getLocalIDCount());
+ Assertions.assertEquals(4,
+ containerBlocksInfoWrapper.getLocalIDList().size());
+ Assertions.assertEquals(1, containerBlocksInfoWrapper.getTxID());
+ }
+
+ @Test
+ public void testGetBlocksPendingDeletionPrevKeyParam() throws Exception {
+ List<Long> localIdList = new ArrayList<>();
+ localIdList.add(1L);
+ localIdList.add(2L);
+ localIdList.add(3L);
+ localIdList.add(4L);
+ StorageContainerDatanodeProtocolProtos.DeletedBlocksTransaction dtx =
+ StorageContainerDatanodeProtocolProtos.DeletedBlocksTransaction
+ .newBuilder().setTxID(1).setContainerID(100L)
+ .addAllLocalID(localIdList).setCount(4).build();
+
+ Table<Long,
StorageContainerDatanodeProtocolProtos.DeletedBlocksTransaction>
+ deletedBlocksTable = DELETED_BLOCKS.getTable(this.scmDBStore);
+ deletedBlocksTable.put(1L, dtx);
+
+ dtx =
+ StorageContainerDatanodeProtocolProtos.DeletedBlocksTransaction
+ .newBuilder().setTxID(3).setContainerID(101L)
+ .addAllLocalID(localIdList).setCount(4).build();
+ deletedBlocksTable.put(3L, dtx);
+
+ Response blocksPendingDeletion =
+ blocksEndPoint.getBlocksPendingDeletion(1, 2);
+ Map<String, List<ContainerBlocksInfoWrapper>>
+ containerStateBlockInfoListMap =
+ (Map<String, List<ContainerBlocksInfoWrapper>>)
+ blocksPendingDeletion.getEntity();
+ Assertions.assertNotNull(containerStateBlockInfoListMap);
+ Assertions.assertEquals(1, containerStateBlockInfoListMap.size());
+ List<ContainerBlocksInfoWrapper> containerBlocksInfoWrappers =
+ containerStateBlockInfoListMap.get("OPEN");
+ ContainerBlocksInfoWrapper containerBlocksInfoWrapper =
+ containerBlocksInfoWrappers.get(0);
+ Assertions.assertEquals(101, containerBlocksInfoWrapper.getContainerID());
+ Assertions.assertEquals(4, containerBlocksInfoWrapper.getLocalIDCount());
+ Assertions.assertEquals(4,
+ containerBlocksInfoWrapper.getLocalIDList().size());
+ Assertions.assertEquals(3, containerBlocksInfoWrapper.getTxID());
+
+ blocksPendingDeletion =
+ blocksEndPoint.getBlocksPendingDeletion(1, 3);
+ containerStateBlockInfoListMap =
+ (Map<String, List<ContainerBlocksInfoWrapper>>)
+ blocksPendingDeletion.getEntity();
+ Assertions.assertTrue(containerStateBlockInfoListMap.size() == 0);
+
+ blocksPendingDeletion =
+ blocksEndPoint.getBlocksPendingDeletion(1, 4);
+ containerStateBlockInfoListMap =
+ (Map<String, List<ContainerBlocksInfoWrapper>>)
+ blocksPendingDeletion.getEntity();
+ Assertions.assertTrue(containerStateBlockInfoListMap.size() == 0);
+ }
+
+ protected ContainerWithPipeline getTestContainer(
+ HddsProtos.LifeCycleState state, long containerId)
+ throws IOException, TimeoutException {
+ ContainerID localContainerID = ContainerID.valueOf(containerId);
+ Pipeline localPipeline = getRandomPipeline();
+ reconPipelineManager.addPipeline(localPipeline);
+ ContainerInfo containerInfo =
+ new ContainerInfo.Builder()
+ .setContainerID(localContainerID.getId())
+ .setNumberOfKeys(10)
+ .setPipelineID(localPipeline.getId())
+ .setReplicationConfig(StandaloneReplicationConfig.getInstance(ONE))
+ .setOwner("test")
+ .setState(state)
+ .build();
+ return new ContainerWithPipeline(containerInfo, localPipeline);
+ }
+}
diff --git
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestContainerEndpoint.java
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestContainerEndpoint.java
index 2aa84e59ce..ee6f2c5444 100644
---
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestContainerEndpoint.java
+++
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestContainerEndpoint.java
@@ -18,66 +18,40 @@
package org.apache.hadoop.ozone.recon.api;
-import static
org.apache.hadoop.ozone.recon.OMMetadataManagerTestUtils.getOmKeyLocationInfo;
-import static
org.apache.hadoop.ozone.recon.OMMetadataManagerTestUtils.getRandomPipeline;
-import static
org.apache.hadoop.ozone.recon.OMMetadataManagerTestUtils.getTestReconOmMetadataManager;
-import static
org.apache.hadoop.ozone.recon.OMMetadataManagerTestUtils.initializeNewOmMetadataManager;
-import static
org.apache.hadoop.ozone.recon.OMMetadataManagerTestUtils.writeDataToOm;
-import static org.junit.Assert.assertNotNull;
-import static
org.apache.hadoop.ozone.recon.OMMetadataManagerTestUtils.writeKeyToOm;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.TimeoutException;
-import java.util.stream.Collectors;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Response;
-
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.hdds.client.BlockID;
import org.apache.hadoop.hdds.client.RatisReplicationConfig;
+import org.apache.hadoop.hdds.client.StandaloneReplicationConfig;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
import org.apache.hadoop.hdds.protocol.proto.HddsProtos.ReplicationFactor;
import org.apache.hadoop.hdds.scm.container.ContainerID;
import org.apache.hadoop.hdds.scm.container.ContainerInfo;
+import org.apache.hadoop.hdds.scm.container.ContainerStateManager;
import
org.apache.hadoop.hdds.scm.container.common.helpers.ContainerWithPipeline;
import org.apache.hadoop.hdds.scm.pipeline.Pipeline;
import org.apache.hadoop.hdds.scm.pipeline.PipelineID;
import org.apache.hadoop.hdds.scm.server.OzoneStorageContainerManager;
+import org.apache.hadoop.hdds.utils.db.Table;
import org.apache.hadoop.ozone.om.OMMetadataManager;
-import org.apache.hadoop.ozone.om.helpers.OmDirectoryInfo;
import org.apache.hadoop.ozone.om.helpers.BucketLayout;
-import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
+import org.apache.hadoop.ozone.om.helpers.OmDirectoryInfo;
import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfo;
import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfoGroup;
+import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
import org.apache.hadoop.ozone.recon.ReconTestInjector;
import org.apache.hadoop.ozone.recon.api.types.ContainerMetadata;
import org.apache.hadoop.ozone.recon.api.types.ContainersResponse;
+import org.apache.hadoop.ozone.recon.api.types.DeletedContainerInfo;
import org.apache.hadoop.ozone.recon.api.types.KeyMetadata;
import org.apache.hadoop.ozone.recon.api.types.KeysResponse;
import org.apache.hadoop.ozone.recon.api.types.MissingContainerMetadata;
import org.apache.hadoop.ozone.recon.api.types.MissingContainersResponse;
import org.apache.hadoop.ozone.recon.api.types.UnhealthyContainerMetadata;
import org.apache.hadoop.ozone.recon.api.types.UnhealthyContainersResponse;
-import org.apache.hadoop.ozone.recon.persistence.ContainerHistory;
import org.apache.hadoop.ozone.recon.persistence.ContainerHealthSchemaManager;
+import org.apache.hadoop.ozone.recon.persistence.ContainerHistory;
import org.apache.hadoop.ozone.recon.recovery.ReconOMMetadataManager;
import org.apache.hadoop.ozone.recon.scm.ReconContainerManager;
import org.apache.hadoop.ozone.recon.scm.ReconPipelineManager;
@@ -87,15 +61,46 @@ import
org.apache.hadoop.ozone.recon.spi.StorageContainerServiceProvider;
import org.apache.hadoop.ozone.recon.spi.impl.OzoneManagerServiceProviderImpl;
import
org.apache.hadoop.ozone.recon.spi.impl.StorageContainerServiceProviderImpl;
import org.apache.hadoop.ozone.recon.tasks.ContainerKeyMapperTask;
-import org.apache.hadoop.hdds.utils.db.Table;
import
org.hadoop.ozone.recon.schema.ContainerSchemaDefinition.UnHealthyContainerStates;
import org.hadoop.ozone.recon.schema.tables.pojos.UnhealthyContainers;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
import org.junit.rules.TemporaryFolder;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.TimeoutException;
+import java.util.stream.Collectors;
+
+import static
org.apache.hadoop.hdds.protocol.proto.HddsProtos.ReplicationFactor.ONE;
+import static
org.apache.hadoop.ozone.recon.OMMetadataManagerTestUtils.getOmKeyLocationInfo;
+import static
org.apache.hadoop.ozone.recon.OMMetadataManagerTestUtils.getRandomPipeline;
+import static
org.apache.hadoop.ozone.recon.OMMetadataManagerTestUtils.getTestReconOmMetadataManager;
+import static
org.apache.hadoop.ozone.recon.OMMetadataManagerTestUtils.initializeNewOmMetadataManager;
+import static
org.apache.hadoop.ozone.recon.OMMetadataManagerTestUtils.writeDataToOm;
+import static
org.apache.hadoop.ozone.recon.OMMetadataManagerTestUtils.writeKeyToOm;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
/**
* Test for container endpoint.
*/
@@ -103,9 +108,9 @@ public class TestContainerEndpoint {
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
-
private OzoneStorageContainerManager ozoneStorageContainerManager;
private ReconContainerManager reconContainerManager;
+ private ContainerStateManager containerStateManager;
private ReconPipelineManager reconPipelineManager;
private ReconContainerMetadataManager reconContainerMetadataManager;
private ContainerEndpoint containerEndpoint;
@@ -182,6 +187,8 @@ public class TestContainerEndpoint {
pipeline = getRandomPipeline();
pipelineID = pipeline.getId();
reconPipelineManager.addPipeline(pipeline);
+ containerStateManager = reconContainerManager
+ .getContainerStateManager();
}
@Before
@@ -992,7 +999,168 @@ public class TestContainerEndpoint {
reconContainerManager.upsertContainerHistory(cID, uuid4, 4L, 1L);
}
- private BucketLayout getBucketLayout() {
- return BucketLayout.DEFAULT;
+ protected ContainerWithPipeline getTestContainer(
+ HddsProtos.LifeCycleState state, long containerId)
+ throws IOException, TimeoutException {
+ ContainerID localContainerID = ContainerID.valueOf(containerId);
+ Pipeline localPipeline = getRandomPipeline();
+ reconPipelineManager.addPipeline(localPipeline);
+ ContainerInfo containerInfo =
+ new ContainerInfo.Builder()
+ .setContainerID(localContainerID.getId())
+ .setNumberOfKeys(10)
+ .setPipelineID(localPipeline.getId())
+ .setReplicationConfig(StandaloneReplicationConfig.getInstance(ONE))
+ .setOwner("test")
+ .setState(state)
+ .build();
+ return new ContainerWithPipeline(containerInfo, localPipeline);
+ }
+
+ @Test
+ public void testGetSCMDeletedContainers() throws Exception {
+ reconContainerManager.addNewContainer(
+ getTestContainer(HddsProtos.LifeCycleState.OPEN, 102L));
+ reconContainerManager.addNewContainer(
+ getTestContainer(HddsProtos.LifeCycleState.OPEN, 103L));
+
+ reconContainerManager.updateContainerState(ContainerID.valueOf(102L),
+ HddsProtos.LifeCycleEvent.FINALIZE);
+ reconContainerManager.updateContainerState(ContainerID.valueOf(102L),
+ HddsProtos.LifeCycleEvent.CLOSE);
+ reconContainerManager
+ .updateContainerState(ContainerID.valueOf(102L),
+ HddsProtos.LifeCycleEvent.DELETE);
+ reconContainerManager
+ .updateContainerState(ContainerID.valueOf(102L),
+ HddsProtos.LifeCycleEvent.CLEANUP);
+ Set<ContainerID> containerIDs = containerStateManager
+ .getContainerIDs(HddsProtos.LifeCycleState.DELETED);
+ Assertions.assertEquals(1, containerIDs.size());
+
+ reconContainerManager.updateContainerState(ContainerID.valueOf(103L),
+ HddsProtos.LifeCycleEvent.FINALIZE);
+ reconContainerManager.updateContainerState(ContainerID.valueOf(103L),
+ HddsProtos.LifeCycleEvent.CLOSE);
+ reconContainerManager
+ .updateContainerState(ContainerID.valueOf(103L),
+ HddsProtos.LifeCycleEvent.DELETE);
+ containerIDs = containerStateManager
+ .getContainerIDs(HddsProtos.LifeCycleState.DELETING);
+ reconContainerManager
+ .updateContainerState(ContainerID.valueOf(103L),
+ HddsProtos.LifeCycleEvent.CLEANUP);
+ containerIDs = containerStateManager
+ .getContainerIDs(HddsProtos.LifeCycleState.DELETED);
+ Assertions.assertEquals(2, containerIDs.size());
+
+ Response scmDeletedContainers =
+ containerEndpoint.getSCMDeletedContainers(2, 0);
+ List<DeletedContainerInfo> deletedContainerInfoList =
+ (List<DeletedContainerInfo>) scmDeletedContainers.getEntity();
+ Assertions.assertEquals(2, deletedContainerInfoList.size());
+
+ DeletedContainerInfo deletedContainerInfo =
deletedContainerInfoList.get(0);
+ Assertions.assertEquals(102, deletedContainerInfo.getContainerID());
+ Assertions.assertEquals("DELETED",
+ deletedContainerInfo.getContainerState());
+
+ deletedContainerInfo = deletedContainerInfoList.get(1);
+ Assertions.assertEquals(103, deletedContainerInfo.getContainerID());
+ Assertions.assertEquals("DELETED",
+ deletedContainerInfo.getContainerState());
+ }
+
+ @Test
+ public void testGetSCMDeletedContainersLimitParam() throws Exception {
+ reconContainerManager.addNewContainer(
+ getTestContainer(HddsProtos.LifeCycleState.OPEN, 104L));
+ reconContainerManager.addNewContainer(
+ getTestContainer(HddsProtos.LifeCycleState.OPEN, 105L));
+ reconContainerManager.updateContainerState(ContainerID.valueOf(104L),
+ HddsProtos.LifeCycleEvent.FINALIZE);
+ reconContainerManager.updateContainerState(ContainerID.valueOf(104L),
+ HddsProtos.LifeCycleEvent.CLOSE);
+ reconContainerManager
+ .updateContainerState(ContainerID.valueOf(104L),
+ HddsProtos.LifeCycleEvent.DELETE);
+ reconContainerManager
+ .updateContainerState(ContainerID.valueOf(104L),
+ HddsProtos.LifeCycleEvent.CLEANUP);
+ Set<ContainerID> containerIDs = containerStateManager
+ .getContainerIDs(HddsProtos.LifeCycleState.DELETED);
+ Assertions.assertEquals(1, containerIDs.size());
+
+ reconContainerManager.updateContainerState(ContainerID.valueOf(105L),
+ HddsProtos.LifeCycleEvent.FINALIZE);
+ reconContainerManager.updateContainerState(ContainerID.valueOf(105L),
+ HddsProtos.LifeCycleEvent.CLOSE);
+ reconContainerManager
+ .updateContainerState(ContainerID.valueOf(105L),
+ HddsProtos.LifeCycleEvent.DELETE);
+ reconContainerManager
+ .updateContainerState(ContainerID.valueOf(105L),
+ HddsProtos.LifeCycleEvent.CLEANUP);
+ containerIDs = containerStateManager
+ .getContainerIDs(HddsProtos.LifeCycleState.DELETED);
+ Assertions.assertEquals(2, containerIDs.size());
+
+ Response scmDeletedContainers =
+ containerEndpoint.getSCMDeletedContainers(1, 0);
+ List<DeletedContainerInfo> deletedContainerInfoList =
+ (List<DeletedContainerInfo>) scmDeletedContainers.getEntity();
+ Assertions.assertEquals(1, deletedContainerInfoList.size());
+
+ DeletedContainerInfo deletedContainerInfo =
deletedContainerInfoList.get(0);
+ Assertions.assertEquals(104, deletedContainerInfo.getContainerID());
+ Assertions.assertEquals("DELETED",
+ deletedContainerInfo.getContainerState());
+ }
+
+ @Test
+ public void testGetSCMDeletedContainersPrevKeyParam() throws Exception {
+ reconContainerManager.addNewContainer(
+ getTestContainer(HddsProtos.LifeCycleState.OPEN, 106L));
+ reconContainerManager.addNewContainer(
+ getTestContainer(HddsProtos.LifeCycleState.OPEN, 107L));
+
+ reconContainerManager.updateContainerState(ContainerID.valueOf(106L),
+ HddsProtos.LifeCycleEvent.FINALIZE);
+ reconContainerManager.updateContainerState(ContainerID.valueOf(106L),
+ HddsProtos.LifeCycleEvent.CLOSE);
+ reconContainerManager
+ .updateContainerState(ContainerID.valueOf(106L),
+ HddsProtos.LifeCycleEvent.DELETE);
+ reconContainerManager
+ .updateContainerState(ContainerID.valueOf(106L),
+ HddsProtos.LifeCycleEvent.CLEANUP);
+ Set<ContainerID> containerIDs = containerStateManager
+ .getContainerIDs(HddsProtos.LifeCycleState.DELETED);
+ Assertions.assertEquals(1, containerIDs.size());
+
+ reconContainerManager.updateContainerState(ContainerID.valueOf(107L),
+ HddsProtos.LifeCycleEvent.FINALIZE);
+ reconContainerManager.updateContainerState(ContainerID.valueOf(107L),
+ HddsProtos.LifeCycleEvent.CLOSE);
+ reconContainerManager
+ .updateContainerState(ContainerID.valueOf(107L),
+ HddsProtos.LifeCycleEvent.DELETE);
+ reconContainerManager
+ .updateContainerState(ContainerID.valueOf(107L),
+ HddsProtos.LifeCycleEvent.CLEANUP);
+ containerIDs = containerStateManager
+ .getContainerIDs(HddsProtos.LifeCycleState.DELETED);
+ Assertions.assertEquals(2, containerIDs.size());
+
+ Response scmDeletedContainers =
+ containerEndpoint.getSCMDeletedContainers(2, 106L);
+ List<DeletedContainerInfo> deletedContainerInfoList =
+ (List<DeletedContainerInfo>) scmDeletedContainers.getEntity();
+ Assertions.assertEquals(1, deletedContainerInfoList.size());
+
+ DeletedContainerInfo deletedContainerInfo =
deletedContainerInfoList.get(0);
+ Assertions.assertEquals(107, deletedContainerInfo.getContainerID());
+ Assertions.assertEquals("DELETED",
+ deletedContainerInfo.getContainerState());
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]