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 5a6865fb2c HDDS-8214. Recon - OM DB Insights - Key Level Info (#4516)
5a6865fb2c is described below
commit 5a6865fb2c24388b10adedd30f2f24657ca1be2c
Author: devmadhuu <[email protected]>
AuthorDate: Thu May 25 08:06:08 2023 +0530
HDDS-8214. Recon - OM DB Insights - Key Level Info (#4516)
* HDDS-8214. Recon - OM DB Insights - Container Level Info.
* HDDS-8214. Recon - OM DB Insights - Key Level Info.
* HDDS-8214. Recon - OM DB Insights - Key Level Info.
* HDDS-8214. Recon - OM DB Insights - Key Level Info.
* HDDS-8214. Recon - OM DB Insights - Key Level Info.
* HDDS-8214. Recon - OM DB Insights - Key Level Info.
* HDDS-8214. Recon - OM DB Insights - Key Level Info.
* HDDS-8214. Recon - OM DB Insights - Key Level Info.
* HDDS-8214. Recon - OM DB Insights - Key Level Info.
* HDDS-8214. Recon - OM DB Insights - Key Level Info.
* HDDS-8214. Recon - OM DB Insights - Key Level Info.
* HDDS-8214. Recon - OM DB Insights - Key Level Info.
* HDDS-8214. Recon - OM DB Insights - Key Level Info.
* HDDS-8214. Recon - OM DB Insights - Key Level Info.
* HDDS-8214. Recon - OM DB Insights - Key Level Info.
* HDDS-8214. Recon - OM DB Insights - Key Level Info.
* HDDS-8214. Recon - OM DB Insights - Key Level Info.
* HDDS-8214. Recon - OM DB Insights - Key Level Info.
* HDDS-8214. Recon - OM DB Insights - Key Level Info.
* HDDS-8214. Recon - OM DB Insights - Key Level Info.
* HDDS-8214. Recon - OM DB Insights - Key Level Info.
---------
Co-authored-by: deveshsingh <devmadhu@[email protected]>
---
.../hadoop/ozone/recon/api/ContainerEndpoint.java | 74 ++-
.../ozone/recon/api/OMDBInsightEndpoint.java | 481 ++++++++++++++++++++
.../recon/api/types/ContainerDiscrepancyInfo.java | 2 +
.../ozone/recon/api/types/KeyEntityInfo.java | 109 +++++
.../recon/api/types/KeyInsightInfoResponse.java | 148 ++++++
.../ozone/recon/api/TestContainerEndpoint.java | 122 +++++
.../ozone/recon/api/TestOmDBInsightEndPoint.java | 498 +++++++++++++++++++++
7 files changed, 1433 insertions(+), 1 deletion(-)
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 1d52fe8890..3a52f3883d 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
@@ -430,7 +430,7 @@ public class ContainerEndpoint {
* }
* @param limit limits the number of deleted containers
* @param prevKey previous container Id to skip
- * @return Response of delete containers.
+ * @return Response of deleted containers.
*/
@GET
@Path("/deleted")
@@ -575,4 +575,76 @@ public class ContainerEndpoint {
}
return Response.ok(containerDiscrepancyInfoList).build();
}
+
+ /** This API retrieves set of deleted containers in SCM which are present
+ * in OM to find out list of keys mapped to such DELETED state containers.
+ *
+ * limit - limits the number of such SCM DELETED containers present in OM.
+ * prevKey - Skip containers till it seeks correctly to the previous
+ * containerId.
+ * Sample API Response:
+ * [
+ * {
+ * "containerId": 2,
+ * "numberOfKeys": 2,
+ * "pipelines": []
+ * }
+ * ]
+ */
+ @GET
+ @Path("/mismatch/deleted")
+ public Response getOmContainersDeletedInSCM(
+ @DefaultValue(DEFAULT_FETCH_COUNT) @QueryParam(RECON_QUERY_LIMIT)
+ int limit,
+ @DefaultValue(PREV_CONTAINER_ID_DEFAULT_VALUE)
+ @QueryParam(RECON_QUERY_PREVKEY) long prevKey) {
+ if (prevKey < 0) {
+ // Send back an empty response
+ return Response.status(Response.Status.NOT_ACCEPTABLE).build();
+ }
+ List<ContainerDiscrepancyInfo> containerDiscrepancyInfoList =
+ new ArrayList<>();
+ try {
+ Map<Long, ContainerMetadata> omContainers =
+ reconContainerMetadataManager.getContainers(limit, prevKey);
+
+ List<Long> deletedStateSCMContainerIds =
+ containerManager.getContainers().stream()
+ .filter(containerInfo -> (containerInfo.getState() ==
+ HddsProtos.LifeCycleState.DELETED))
+ .map(containerInfo -> containerInfo.getContainerID()).collect(
+ Collectors.toList());
+
+ List<Map.Entry<Long, ContainerMetadata>>
+ omContainersDeletedInSCM =
+ omContainers.entrySet().stream().filter(containerMetadataEntry ->
+ (deletedStateSCMContainerIds.contains(
+ containerMetadataEntry.getKey())))
+ .collect(
+ Collectors.toList());
+
+ omContainersDeletedInSCM.forEach(
+ containerMetadataEntry -> {
+ ContainerDiscrepancyInfo containerDiscrepancyInfo =
+ new ContainerDiscrepancyInfo();
+ containerDiscrepancyInfo.setContainerID(
+ containerMetadataEntry.getKey());
+ containerDiscrepancyInfo.setNumberOfKeys(
+ containerMetadataEntry.getValue().getNumberOfKeys());
+ containerDiscrepancyInfo.setPipelines(
+ containerMetadataEntry.getValue()
+ .getPipelines());
+ containerDiscrepancyInfoList.add(containerDiscrepancyInfo);
+ });
+ } catch (IOException ex) {
+ throw new WebApplicationException(ex,
+ Response.Status.INTERNAL_SERVER_ERROR);
+ } 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(containerDiscrepancyInfoList).build();
+ }
}
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
new file mode 100644
index 0000000000..51fba63b73
--- /dev/null
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
@@ -0,0 +1,481 @@
+/**
+ * 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.commons.lang3.StringUtils;
+import org.apache.hadoop.hdds.scm.server.OzoneStorageContainerManager;
+import org.apache.hadoop.hdds.utils.db.Table;
+import org.apache.hadoop.hdds.utils.db.TableIterator;
+import org.apache.hadoop.ozone.om.helpers.BucketLayout;
+import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
+import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo;
+import org.apache.hadoop.ozone.recon.api.types.KeyEntityInfo;
+import org.apache.hadoop.ozone.recon.api.types.KeyInsightInfoResponse;
+import org.apache.hadoop.ozone.recon.recovery.ReconOMMetadataManager;
+import org.apache.hadoop.ozone.recon.scm.ReconContainerManager;
+import org.apache.hadoop.ozone.recon.spi.ReconContainerMetadataManager;
+
+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.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.apache.hadoop.ozone.recon.ReconConstants.DEFAULT_FETCH_COUNT;
+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 key level info under OM DB Insight page of Recon.
+ * 1. Number of open keys for Legacy/OBS buckets.
+ * 2. Number of open files for FSO buckets.
+ * 3. Amount of data mapped to open keys and open files.
+ * 4. Number of pending delete keys in legacy/OBS buckets and pending
+ * delete files in FSO buckets.
+ * 5. Amount of data mapped to pending delete keys in legacy/OBS buckets and
+ * pending delete files in FSO buckets.
+ */
+@Path("/keys")
+@Produces(MediaType.APPLICATION_JSON)
+@AdminOnly
+public class OMDBInsightEndpoint {
+
+ @Inject
+ private ContainerEndpoint containerEndpoint;
+ @Inject
+ private ReconContainerMetadataManager reconContainerMetadataManager;
+ private final ReconOMMetadataManager omMetadataManager;
+ private final ReconContainerManager containerManager;
+
+ @Inject
+ public OMDBInsightEndpoint(OzoneStorageContainerManager reconSCM,
+ ReconOMMetadataManager omMetadataManager) {
+ this.containerManager =
+ (ReconContainerManager) reconSCM.getContainerManager();
+ this.omMetadataManager = omMetadataManager;
+ }
+
+ /**
+ * This method retrieves set of keys/files which are open.
+ *
+ * @return the http json response wrapped in below format:
+ * {
+ * replicatedTotal: 13824,
+ * unreplicatedTotal: 4608,
+ * entities: [
+ * {
+ * path: “/vol1/bucket1/key1”,
+ * keyState: “Open”,
+ * inStateSince: 1667564193026,
+ * size: 1024,
+ * replicatedSize: 3072,
+ * unreplicatedSize: 1024,
+ * replicationType: RATIS,
+ * replicationFactor: THREE
+ * }.
+ * {
+ * path: “/vol1/bucket1/key2”,
+ * keyState: “Open”,
+ * inStateSince: 1667564193026,
+ * size: 512,
+ * replicatedSize: 1536,
+ * unreplicatedSize: 512,
+ * replicationType: RATIS,
+ * replicationFactor: THREE
+ * }.
+ * {
+ * path: “/vol1/fso-bucket/dir1/file1”,
+ * keyState: “Open”,
+ * inStateSince: 1667564193026,
+ * size: 1024,
+ * replicatedSize: 3072,
+ * unreplicatedSize: 1024,
+ * replicationType: RATIS,
+ * replicationFactor: THREE
+ * }.
+ * {
+ * path: “/vol1/fso-bucket/dir1/dir2/file2”,
+ * keyState: “Open”,
+ * inStateSince: 1667564193026,
+ * size: 2048,
+ * replicatedSize: 6144,
+ * unreplicatedSize: 2048,
+ * replicationType: RATIS,
+ * replicationFactor: THREE
+ * }
+ * ]
+ * }
+ */
+ @GET
+ @Path("/open")
+ public Response getOpenKeyInfo(
+ @DefaultValue(DEFAULT_FETCH_COUNT) @QueryParam(RECON_QUERY_LIMIT)
+ int limit,
+ @DefaultValue(StringUtils.EMPTY) @QueryParam(RECON_QUERY_PREVKEY)
+ String prevKey) {
+ KeyInsightInfoResponse openKeyInsightInfo = new KeyInsightInfoResponse();
+ List<KeyEntityInfo> nonFSOKeyInfoList =
+ openKeyInsightInfo.getNonFSOKeyInfoList();
+ boolean skipPrevKeyDone = false;
+ boolean isLegacyBucketLayout = true;
+ boolean recordsFetchedLimitReached = false;
+ String lastKey = "";
+ List<KeyEntityInfo> fsoKeyInfoList =
openKeyInsightInfo.getFsoKeyInfoList();
+ for (BucketLayout layout : Arrays.asList(BucketLayout.LEGACY,
+ BucketLayout.FILE_SYSTEM_OPTIMIZED)) {
+ isLegacyBucketLayout = (layout == BucketLayout.LEGACY);
+ Table<String, OmKeyInfo> openKeyTable =
+ omMetadataManager.getOpenKeyTable(layout);
+ try (
+ TableIterator<String, ? extends Table.KeyValue<String, OmKeyInfo>>
+ keyIter = openKeyTable.iterator()) {
+ boolean skipPrevKey = false;
+ String seekKey = prevKey;
+ if (!skipPrevKeyDone && StringUtils.isNotBlank(prevKey)) {
+ skipPrevKey = true;
+ Table.KeyValue<String, OmKeyInfo> seekKeyValue =
+ keyIter.seek(seekKey);
+ // check if RocksDB was able to seek correctly to the given key
prefix
+ // if not, then return empty result
+ // In case of an empty prevKeyPrefix, all the keys are returned
+ if (seekKeyValue == null ||
+ (StringUtils.isNotBlank(prevKey) &&
+ !seekKeyValue.getKey().equals(prevKey))) {
+ continue;
+ }
+ }
+ while (keyIter.hasNext()) {
+ Table.KeyValue<String, OmKeyInfo> kv = keyIter.next();
+ String key = kv.getKey();
+ lastKey = key;
+ OmKeyInfo omKeyInfo = kv.getValue();
+ // skip the prev key if prev key is present
+ if (skipPrevKey && key.equals(prevKey)) {
+ skipPrevKeyDone = true;
+ continue;
+ }
+ KeyEntityInfo keyEntityInfo = new KeyEntityInfo();
+ keyEntityInfo.setKey(key);
+ keyEntityInfo.setPath(omKeyInfo.getKeyName());
+ keyEntityInfo.setInStateSince(omKeyInfo.getCreationTime());
+ keyEntityInfo.setSize(omKeyInfo.getDataSize());
+ keyEntityInfo.setReplicatedSize(omKeyInfo.getReplicatedSize());
+ keyEntityInfo.setReplicationConfig(omKeyInfo.getReplicationConfig());
+ openKeyInsightInfo.setUnreplicatedTotal(
+ openKeyInsightInfo.getUnreplicatedTotal() +
+ keyEntityInfo.getSize());
+ openKeyInsightInfo.setReplicatedTotal(
+ openKeyInsightInfo.getReplicatedTotal() +
+ keyEntityInfo.getReplicatedSize());
+ boolean added =
+ isLegacyBucketLayout ? nonFSOKeyInfoList.add(keyEntityInfo) :
+ fsoKeyInfoList.add(keyEntityInfo);
+ if ((nonFSOKeyInfoList.size() + fsoKeyInfoList.size()) == limit) {
+ recordsFetchedLimitReached = true;
+ break;
+ }
+ }
+ } catch (IOException ex) {
+ throw new WebApplicationException(ex,
+ Response.Status.INTERNAL_SERVER_ERROR);
+ } catch (IllegalArgumentException e) {
+ throw new WebApplicationException(e, Response.Status.BAD_REQUEST);
+ } catch (Exception ex) {
+ throw new WebApplicationException(ex,
+ Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ if (recordsFetchedLimitReached) {
+ break;
+ }
+ }
+ openKeyInsightInfo.setLastKey(lastKey);
+ return Response.ok(openKeyInsightInfo).build();
+ }
+
+ private void getPendingForDeletionKeyInfo(
+ int limit,
+ String prevKey,
+ KeyInsightInfoResponse deletedKeyAndDirInsightInfo) {
+ List<RepeatedOmKeyInfo> repeatedOmKeyInfoList =
+ deletedKeyAndDirInsightInfo.getRepeatedOmKeyInfoList();
+ Table<String, RepeatedOmKeyInfo> deletedTable =
+ omMetadataManager.getDeletedTable();
+ try (
+ TableIterator<String, ? extends Table.KeyValue<String,
+ RepeatedOmKeyInfo>>
+ keyIter = deletedTable.iterator()) {
+ boolean skipPrevKey = false;
+ String seekKey = prevKey;
+ String lastKey = "";
+ if (StringUtils.isNotBlank(prevKey)) {
+ skipPrevKey = true;
+ Table.KeyValue<String, RepeatedOmKeyInfo> seekKeyValue =
+ keyIter.seek(seekKey);
+ // check if RocksDB was able to seek correctly to the given key prefix
+ // if not, then return empty result
+ // In case of an empty prevKeyPrefix, all the keys are returned
+ if (seekKeyValue == null ||
+ (StringUtils.isNotBlank(prevKey) &&
+ !seekKeyValue.getKey().equals(prevKey))) {
+ return;
+ }
+ }
+ while (keyIter.hasNext()) {
+ Table.KeyValue<String, RepeatedOmKeyInfo> kv = keyIter.next();
+ String key = kv.getKey();
+ lastKey = key;
+ RepeatedOmKeyInfo repeatedOmKeyInfo = kv.getValue();
+ // skip the prev key if prev key is present
+ if (skipPrevKey && key.equals(prevKey)) {
+ continue;
+ }
+ updateReplicatedAndUnReplicatedTotal(deletedKeyAndDirInsightInfo,
+ repeatedOmKeyInfo);
+ repeatedOmKeyInfoList.add(repeatedOmKeyInfo);
+ if ((repeatedOmKeyInfoList.size()) == limit) {
+ break;
+ }
+ }
+ deletedKeyAndDirInsightInfo.setLastKey(lastKey);
+ } catch (IOException ex) {
+ throw new WebApplicationException(ex,
+ Response.Status.INTERNAL_SERVER_ERROR);
+ } catch (IllegalArgumentException e) {
+ throw new WebApplicationException(e, Response.Status.BAD_REQUEST);
+ } catch (Exception ex) {
+ throw new WebApplicationException(ex,
+ Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ /** This method retrieves set of keys/files pending for deletion.
+ *
+ * limit - limits the number of key/files returned.
+ * prevKey - E.g. /vol1/bucket1/key1, this will skip keys till it
+ * seeks correctly to the given prevKey.
+ * Sample API Response:
+ * {
+ * "lastKey": "vol1/bucket1/key1",
+ * "replicatedTotal": -1530804718628866300,
+ * "unreplicatedTotal": -1530804718628866300,
+ * "deletedkeyinfo": [
+ * {
+ * "omKeyInfoList": [
+ * {
+ * "metadata": {},
+ * "objectID": 0,
+ * "updateID": 0,
+ * "parentObjectID": 0,
+ * "volumeName": "sampleVol",
+ * "bucketName": "bucketOne",
+ * "keyName": "key_one",
+ * "dataSize": -1530804718628866300,
+ * "keyLocationVersions": [],
+ * "creationTime": 0,
+ * "modificationTime": 0,
+ * "replicationConfig": {
+ * "replicationFactor": "ONE",
+ * "requiredNodes": 1,
+ * "replicationType": "STANDALONE"
+ * },
+ * "fileChecksum": null,
+ * "fileName": "key_one",
+ * "acls": [],
+ * "path": "0/key_one",
+ * "file": false,
+ * "latestVersionLocations": null,
+ * "replicatedSize": -1530804718628866300,
+ * "fileEncryptionInfo": null,
+ * "objectInfo": "OMKeyInfo{volume='sampleVol', bucket='bucketOne',
+ * key='key_one', dataSize='-1530804718628866186',
creationTime='0',
+ * objectID='0', parentID='0', replication='STANDALONE/ONE',
+ * fileChecksum='null}",
+ * "updateIDset": false
+ * }
+ * ]
+ * }
+ * ],
+ * "status": "OK"
+ * }
+ */
+ @GET
+ @Path("/deletePending")
+ public Response getDeletedKeyInfo(
+ @DefaultValue(DEFAULT_FETCH_COUNT) @QueryParam(RECON_QUERY_LIMIT)
+ int limit,
+ @DefaultValue(StringUtils.EMPTY) @QueryParam(RECON_QUERY_PREVKEY)
+ String prevKey) {
+ KeyInsightInfoResponse
+ deletedKeyInsightInfo = new KeyInsightInfoResponse();
+ getPendingForDeletionKeyInfo(limit, prevKey,
+ deletedKeyInsightInfo);
+ return Response.ok(deletedKeyInsightInfo).build();
+ }
+
+ private void getPendingForDeletionDirInfo(
+ int limit, String prevKey,
+ KeyInsightInfoResponse pendingForDeletionKeyInfo) {
+
+ List<KeyEntityInfo> deletedDirInfoList =
+ pendingForDeletionKeyInfo.getDeletedDirInfoList();
+
+ Table<String, OmKeyInfo> deletedDirTable =
+ omMetadataManager.getDeletedDirTable();
+ try (
+ TableIterator<String, ? extends Table.KeyValue<String, OmKeyInfo>>
+ keyIter = deletedDirTable.iterator()) {
+ boolean skipPrevKey = false;
+ String seekKey = prevKey;
+ String lastKey = "";
+ if (StringUtils.isNotBlank(prevKey)) {
+ skipPrevKey = true;
+ Table.KeyValue<String, OmKeyInfo> seekKeyValue =
+ keyIter.seek(seekKey);
+ // check if RocksDB was able to seek correctly to the given key prefix
+ // if not, then return empty result
+ // In case of an empty prevKeyPrefix, all the keys are returned
+ if (seekKeyValue == null ||
+ (StringUtils.isNotBlank(prevKey) &&
+ !seekKeyValue.getKey().equals(prevKey))) {
+ return;
+ }
+ }
+ while (keyIter.hasNext()) {
+ Table.KeyValue<String, OmKeyInfo> kv = keyIter.next();
+ String key = kv.getKey();
+ lastKey = key;
+ OmKeyInfo omKeyInfo = kv.getValue();
+ // skip the prev key if prev key is present
+ if (skipPrevKey && key.equals(prevKey)) {
+ continue;
+ }
+ KeyEntityInfo keyEntityInfo = new KeyEntityInfo();
+ keyEntityInfo.setKey(key);
+ keyEntityInfo.setPath(omKeyInfo.getKeyName());
+ keyEntityInfo.setInStateSince(omKeyInfo.getCreationTime());
+ keyEntityInfo.setSize(omKeyInfo.getDataSize());
+ keyEntityInfo.setReplicatedSize(omKeyInfo.getReplicatedSize());
+ keyEntityInfo.setReplicationConfig(omKeyInfo.getReplicationConfig());
+ pendingForDeletionKeyInfo.setUnreplicatedTotal(
+ pendingForDeletionKeyInfo.getUnreplicatedTotal() +
+ keyEntityInfo.getSize());
+ pendingForDeletionKeyInfo.setReplicatedTotal(
+ pendingForDeletionKeyInfo.getReplicatedTotal() +
+ keyEntityInfo.getReplicatedSize());
+ deletedDirInfoList.add(keyEntityInfo);
+ if (deletedDirInfoList.size() == limit) {
+ break;
+ }
+ }
+ pendingForDeletionKeyInfo.setLastKey(lastKey);
+ } catch (IOException ex) {
+ throw new WebApplicationException(ex,
+ Response.Status.INTERNAL_SERVER_ERROR);
+ } catch (IllegalArgumentException e) {
+ throw new WebApplicationException(e, Response.Status.BAD_REQUEST);
+ } catch (Exception ex) {
+ throw new WebApplicationException(ex,
+ Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ /** This method retrieves set of directories pending for deletion.
+ *
+ * limit - limits the number of directories returned.
+ * prevKey - E.g. /vol1/bucket1/bucket1/dir1, this will skip dirs till it
+ * seeks correctly to the given prevKey.
+ * Sample API Response:
+ * {
+ * "lastKey": "vol1/bucket1/bucket1/dir1"
+ * "replicatedTotal": -1530804718628866300,
+ * "unreplicatedTotal": -1530804718628866300,
+ * "deletedkeyinfo": [
+ * {
+ * "omKeyInfoList": [
+ * {
+ * "metadata": {},
+ * "objectID": 0,
+ * "updateID": 0,
+ * "parentObjectID": 0,
+ * "volumeName": "sampleVol",
+ * "bucketName": "bucketOne",
+ * "keyName": "key_one",
+ * "dataSize": -1530804718628866300,
+ * "keyLocationVersions": [],
+ * "creationTime": 0,
+ * "modificationTime": 0,
+ * "replicationConfig": {
+ * "replicationFactor": "ONE",
+ * "requiredNodes": 1,
+ * "replicationType": "STANDALONE"
+ * },
+ * "fileChecksum": null,
+ * "fileName": "key_one",
+ * "acls": [],
+ * "path": "0/key_one",
+ * "file": false,
+ * "latestVersionLocations": null,
+ * "replicatedSize": -1530804718628866300,
+ * "fileEncryptionInfo": null,
+ * "objectInfo": "OMKeyInfo{volume='sampleVol', bucket='bucketOne',
+ * key='key_one', dataSize='-1530804718628866186',
creationTime='0',
+ * objectID='0', parentID='0', replication='STANDALONE/ONE',
+ * fileChecksum='null}",
+ * "updateIDset": false
+ * }
+ * ]
+ * }
+ * ],
+ * "status": "OK"
+ * }
+ */
+ @GET
+ @Path("/deletePending/dirs")
+ public Response getDeletedDirInfo(
+ @DefaultValue(DEFAULT_FETCH_COUNT) @QueryParam(RECON_QUERY_LIMIT)
+ int limit,
+ @DefaultValue(StringUtils.EMPTY) @QueryParam(RECON_QUERY_PREVKEY)
+ String prevKey) {
+ KeyInsightInfoResponse
+ deletedDirInsightInfo = new KeyInsightInfoResponse();
+ getPendingForDeletionDirInfo(limit, prevKey,
+ deletedDirInsightInfo);
+ return Response.ok(deletedDirInsightInfo).build();
+ }
+
+ private void updateReplicatedAndUnReplicatedTotal(
+ KeyInsightInfoResponse deletedKeyAndDirInsightInfo,
+ RepeatedOmKeyInfo repeatedOmKeyInfo) {
+ repeatedOmKeyInfo.getOmKeyInfoList().forEach(omKeyInfo -> {
+ deletedKeyAndDirInsightInfo.setUnreplicatedTotal(
+ deletedKeyAndDirInsightInfo.getUnreplicatedTotal() +
+ omKeyInfo.getDataSize());
+ deletedKeyAndDirInsightInfo.setReplicatedTotal(
+ deletedKeyAndDirInsightInfo.getReplicatedTotal() +
+ omKeyInfo.getReplicatedSize());
+ });
+ }
+}
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/ContainerDiscrepancyInfo.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/ContainerDiscrepancyInfo.java
index 33702bf3a0..91bfb8630d 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/ContainerDiscrepancyInfo.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/ContainerDiscrepancyInfo.java
@@ -17,6 +17,7 @@
*/
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.scm.pipeline.Pipeline;
@@ -37,6 +38,7 @@ public class ContainerDiscrepancyInfo {
private List<Pipeline> pipelines;
@JsonProperty("existsAt")
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
private String existsAt;
public ContainerDiscrepancyInfo() {
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/KeyEntityInfo.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/KeyEntityInfo.java
new file mode 100644
index 0000000000..cf02c503f4
--- /dev/null
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/KeyEntityInfo.java
@@ -0,0 +1,109 @@
+/*
+ * 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.JsonProperty;
+import org.apache.hadoop.hdds.client.ReplicationConfig;
+
+import java.time.Instant;
+
+/**
+ * POJO object wrapper for metadata of a given key/file.
+ */
+public class KeyEntityInfo {
+
+ /** This is key table key of rocksDB and will help UI to implement pagination
+ * where UI will use the last record key to send in API as preKeyPrefix. */
+ @JsonProperty("key")
+ private String key;
+
+ /** Path of a key/file. */
+ @JsonProperty("path")
+ private String path;
+
+ @JsonProperty("inStateSince")
+ private long inStateSince;
+
+ @JsonProperty("size")
+ private long size;
+
+ @JsonProperty("replicatedSize")
+ private long replicatedSize;
+
+ @JsonProperty("replicationInfo")
+ private ReplicationConfig replicationConfig;
+
+ public KeyEntityInfo() {
+ key = "";
+ path = "";
+ inStateSince = Instant.now().toEpochMilli();
+ size = 0L;
+ replicatedSize = 0L;
+ replicationConfig = null;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ public long getInStateSince() {
+ return inStateSince;
+ }
+
+ public void setInStateSince(long inStateSince) {
+ this.inStateSince = inStateSince;
+ }
+
+ public long getSize() {
+ return size;
+ }
+
+ public void setSize(long size) {
+ this.size = size;
+ }
+
+ public long getReplicatedSize() {
+ return replicatedSize;
+ }
+
+ public void setReplicatedSize(long replicatedSize) {
+ this.replicatedSize = replicatedSize;
+ }
+
+ public ReplicationConfig getReplicationConfig() {
+ return replicationConfig;
+ }
+
+ public void setReplicationConfig(
+ ReplicationConfig replicationConfig) {
+ this.replicationConfig = replicationConfig;
+ }
+}
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/KeyInsightInfoResponse.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/KeyInsightInfoResponse.java
new file mode 100644
index 0000000000..18da6b438e
--- /dev/null
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/KeyInsightInfoResponse.java
@@ -0,0 +1,148 @@
+/*
+ * 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.ozone.om.helpers.RepeatedOmKeyInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * HTTP Response wrapped for keys insights.
+ */
+public class KeyInsightInfoResponse {
+
+ /** last key sent. */
+ @JsonProperty("lastKey")
+ private String lastKey;
+
+ /** Amount of data mapped to all keys and files in
+ * a cluster across all DNs. */
+ @JsonProperty("replicatedTotal")
+ private long replicatedTotal;
+
+ /** Amount of data mapped to all keys and files on a single DN. */
+ @JsonProperty("unreplicatedTotal")
+ private long unreplicatedTotal;
+
+ /** List of all non-fso keys. */
+ @JsonProperty("nonFSO")
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ private List<KeyEntityInfo> nonFSOKeyInfoList;
+
+ /** List of all fso keys. */
+ @JsonProperty("fso")
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ private List<KeyEntityInfo> fsoKeyInfoList;
+
+ /** List of all deleted and repeatedly deleted keys. */
+ @JsonProperty("deletedKeyInfo")
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ private List<RepeatedOmKeyInfo> repeatedOmKeyInfoList;
+
+ @JsonProperty("deletedDirInfo")
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ private List<KeyEntityInfo> deletedDirInfoList;
+
+ /** Path status. */
+ @JsonProperty("status")
+ private ResponseStatus responseCode;
+
+ public KeyInsightInfoResponse() {
+ responseCode = ResponseStatus.OK;
+ lastKey = "";
+ replicatedTotal = 0L;
+ unreplicatedTotal = 0L;
+ nonFSOKeyInfoList = new ArrayList<>();
+ fsoKeyInfoList = new ArrayList<>();
+ repeatedOmKeyInfoList = new ArrayList<>();
+ deletedDirInfoList = new ArrayList<>();
+ }
+
+ public String getLastKey() {
+ return lastKey;
+ }
+
+ public void setLastKey(String lastKey) {
+ this.lastKey = lastKey;
+ }
+
+ public long getReplicatedTotal() {
+ return replicatedTotal;
+ }
+
+ public void setReplicatedTotal(long replicatedTotal) {
+ this.replicatedTotal = replicatedTotal;
+ }
+
+ public long getUnreplicatedTotal() {
+ return unreplicatedTotal;
+ }
+
+ public void setUnreplicatedTotal(long unreplicatedTotal) {
+ this.unreplicatedTotal = unreplicatedTotal;
+ }
+
+ public List<KeyEntityInfo> getNonFSOKeyInfoList() {
+ return nonFSOKeyInfoList;
+ }
+
+ public void setNonFSOKeyInfoList(
+ List<KeyEntityInfo> nonFSOKeyInfoList) {
+ this.nonFSOKeyInfoList = nonFSOKeyInfoList;
+ }
+
+ public List<KeyEntityInfo> getFsoKeyInfoList() {
+ return fsoKeyInfoList;
+ }
+
+ public void setFsoKeyInfoList(
+ List<KeyEntityInfo> fsoKeyInfoList) {
+ this.fsoKeyInfoList = fsoKeyInfoList;
+ }
+
+ public List<RepeatedOmKeyInfo> getRepeatedOmKeyInfoList() {
+ return repeatedOmKeyInfoList;
+ }
+
+ public void setRepeatedOmKeyInfoList(
+ List<RepeatedOmKeyInfo> repeatedOmKeyInfoList) {
+ this.repeatedOmKeyInfoList = repeatedOmKeyInfoList;
+ }
+
+ public List<KeyEntityInfo> getDeletedDirInfoList() {
+ return deletedDirInfoList;
+ }
+
+ public void setDeletedDirInfoList(
+ List<KeyEntityInfo> deletedDirInfoList) {
+ this.deletedDirInfoList = deletedDirInfoList;
+ }
+
+ public ResponseStatus getResponseCode() {
+ return responseCode;
+ }
+
+ public void setResponseCode(ResponseStatus responseCode) {
+ this.responseCode = responseCode;
+ }
+
+}
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 9bb6cb1a8a..47e25bf22b 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
@@ -34,6 +34,7 @@ import org.apache.hadoop.hdds.scm.pipeline.PipelineID;
import org.apache.hadoop.hdds.scm.server.OzoneStorageContainerManager;
import org.apache.hadoop.hdds.utils.db.RDBBatchOperation;
import org.apache.hadoop.hdds.utils.db.Table;
+import
org.apache.hadoop.ozone.common.statemachine.InvalidStateTransitionException;
import org.apache.hadoop.ozone.om.OMMetadataManager;
import org.apache.hadoop.ozone.om.helpers.BucketLayout;
import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
@@ -1237,6 +1238,20 @@ public class TestContainerEndpoint {
deletedContainerInfo.getContainerState());
}
+ private void updateContainerStateToDeleted(long containerId)
+ throws IOException, InvalidStateTransitionException, TimeoutException {
+
reconContainerManager.updateContainerState(ContainerID.valueOf(containerId),
+ HddsProtos.LifeCycleEvent.FINALIZE);
+
reconContainerManager.updateContainerState(ContainerID.valueOf(containerId),
+ HddsProtos.LifeCycleEvent.CLOSE);
+ reconContainerManager
+ .updateContainerState(ContainerID.valueOf(containerId),
+ HddsProtos.LifeCycleEvent.DELETE);
+ reconContainerManager
+ .updateContainerState(ContainerID.valueOf(containerId),
+ HddsProtos.LifeCycleEvent.CLEANUP);
+ }
+
@Test
public void testGetContainerInsightsNonSCMContainers()
throws IOException, TimeoutException {
@@ -1285,4 +1300,111 @@ public class TestContainerEndpoint {
assertEquals(1, containerDiscrepancyInfoList.size());
assertEquals("SCM", containerDiscrepancyInfo.getExistsAt());
}
+
+ @Test
+ public void testGetOmContainersDeletedInSCM() throws Exception {
+ Map<Long, ContainerMetadata> omContainers =
+ reconContainerMetadataManager.getContainers(-1, 0);
+ putContainerInfos(2);
+ List<ContainerInfo> scmContainers = reconContainerManager.getContainers();
+ assertEquals(2, omContainers.size());
+ assertEquals(2, scmContainers.size());
+ // Update container state of Container Id 1 to CLOSING to CLOSED
+ // and then to DELETED
+ reconContainerManager.updateContainerState(ContainerID.valueOf(1),
+ HddsProtos.LifeCycleEvent.FINALIZE);
+ reconContainerManager.updateContainerState(ContainerID.valueOf(1),
+ HddsProtos.LifeCycleEvent.CLOSE);
+ reconContainerManager
+ .updateContainerState(ContainerID.valueOf(1),
+ HddsProtos.LifeCycleEvent.DELETE);
+ Set<ContainerID> containerIDs = containerStateManager
+ .getContainerIDs(HddsProtos.LifeCycleState.DELETING);
+ Assert.assertEquals(1, containerIDs.size());
+
+ reconContainerManager
+ .updateContainerState(ContainerID.valueOf(1),
+ HddsProtos.LifeCycleEvent.CLEANUP);
+ containerIDs = containerStateManager
+ .getContainerIDs(HddsProtos.LifeCycleState.DELETED);
+ Assert.assertEquals(1, containerIDs.size());
+
+ List<ContainerInfo> deletedSCMContainers =
+ reconContainerManager.getContainers(HddsProtos.LifeCycleState.DELETED);
+ assertEquals(1, deletedSCMContainers.size());
+
+ Response omContainersDeletedInSCMResponse =
+ containerEndpoint.getOmContainersDeletedInSCM(-1, 0);
+ assertNotNull(omContainersDeletedInSCMResponse);
+ List<ContainerDiscrepancyInfo> containerDiscrepancyInfoList =
+ (List<ContainerDiscrepancyInfo>)
+ omContainersDeletedInSCMResponse.getEntity();
+ assertEquals(3, containerDiscrepancyInfoList.get(0)
+ .getNumberOfKeys());
+ assertEquals(1, containerDiscrepancyInfoList.size());
+ }
+
+ @Test
+ public void testGetOmContainersDeletedInSCMLimitParam() throws Exception {
+ Map<Long, ContainerMetadata> omContainers =
+ reconContainerMetadataManager.getContainers(-1, 0);
+ putContainerInfos(2);
+ List<ContainerInfo> scmContainers = reconContainerManager.getContainers();
+ assertEquals(omContainers.size(), scmContainers.size());
+ // Update container state of Container Id 1 to CLOSING to CLOSED
+ // and then to DELETED
+ updateContainerStateToDeleted(1);
+
+ Set<ContainerID> containerIDs = containerStateManager
+ .getContainerIDs(HddsProtos.LifeCycleState.DELETED);
+ Assert.assertEquals(1, containerIDs.size());
+
+ List<ContainerInfo> deletedSCMContainers =
+ reconContainerManager.getContainers(HddsProtos.LifeCycleState.DELETED);
+ assertEquals(1, deletedSCMContainers.size());
+
+ Response omContainersDeletedInSCMResponse =
+ containerEndpoint.getOmContainersDeletedInSCM(1, 0);
+ assertNotNull(omContainersDeletedInSCMResponse);
+ List<ContainerDiscrepancyInfo> containerDiscrepancyInfoList =
+ (List<ContainerDiscrepancyInfo>)
+ omContainersDeletedInSCMResponse.getEntity();
+ assertEquals(3, containerDiscrepancyInfoList.get(0)
+ .getNumberOfKeys());
+ assertEquals(1, containerDiscrepancyInfoList.size());
+ }
+
+ @Test
+ public void testGetOmContainersDeletedInSCMPrevContainerParam()
+ throws Exception {
+ Map<Long, ContainerMetadata> omContainers =
+ reconContainerMetadataManager.getContainers(-1, 0);
+ putContainerInfos(2);
+ List<ContainerInfo> scmContainers = reconContainerManager.getContainers();
+ assertEquals(omContainers.size(), scmContainers.size());
+ // Update container state of Container Id 1 to CLOSING to CLOSED
+ // and then to DELETED
+ updateContainerStateToDeleted(1);
+ updateContainerStateToDeleted(2);
+
+ Set<ContainerID> containerIDs = containerStateManager
+ .getContainerIDs(HddsProtos.LifeCycleState.DELETED);
+ Assert.assertEquals(2, containerIDs.size());
+
+ List<ContainerInfo> deletedSCMContainers =
+ reconContainerManager.getContainers(HddsProtos.LifeCycleState.DELETED);
+ assertEquals(2, deletedSCMContainers.size());
+
+ Response omContainersDeletedInSCMResponse =
+ containerEndpoint.getOmContainersDeletedInSCM(2,
+ 1);
+ assertNotNull(omContainersDeletedInSCMResponse);
+ List<ContainerDiscrepancyInfo> containerDiscrepancyInfoList =
+ (List<ContainerDiscrepancyInfo>)
+ omContainersDeletedInSCMResponse.getEntity();
+ assertEquals(2, containerDiscrepancyInfoList.get(0)
+ .getNumberOfKeys());
+ assertEquals(1, containerDiscrepancyInfoList.size());
+ assertEquals(2, containerDiscrepancyInfoList.get(0).getContainerID());
+ }
}
diff --git
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestOmDBInsightEndPoint.java
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestOmDBInsightEndPoint.java
new file mode 100644
index 0000000000..23b94e4ccf
--- /dev/null
+++
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestOmDBInsightEndPoint.java
@@ -0,0 +1,498 @@
+/**
+ * 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.BlockID;
+import org.apache.hadoop.hdds.client.StandaloneReplicationConfig;
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
+import org.apache.hadoop.hdds.scm.pipeline.Pipeline;
+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.BucketLayout;
+import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
+import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfo;
+import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfoGroup;
+import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo;
+import org.apache.hadoop.ozone.recon.ReconTestInjector;
+import org.apache.hadoop.ozone.recon.api.types.KeyInsightInfoResponse;
+import org.apache.hadoop.ozone.recon.persistence.ContainerHealthSchemaManager;
+import org.apache.hadoop.ozone.recon.recovery.ReconOMMetadataManager;
+import org.apache.hadoop.ozone.recon.scm.ReconPipelineManager;
+import org.apache.hadoop.ozone.recon.scm.ReconStorageContainerManagerFacade;
+import org.apache.hadoop.ozone.recon.spi.ReconContainerMetadataManager;
+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.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.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Collectors;
+
+import static
org.apache.hadoop.ozone.recon.OMMetadataManagerTestUtils.getBucketLayout;
+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.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Unit test for OmDBInsightEndPoint.
+ */
+public class TestOmDBInsightEndPoint {
+
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+ private OzoneStorageContainerManager ozoneStorageContainerManager;
+ private ReconContainerMetadataManager reconContainerMetadataManager;
+ private OMMetadataManager omMetadataManager;
+ private ReconPipelineManager reconPipelineManager;
+ private ReconOMMetadataManager reconOMMetadataManager;
+ private OMDBInsightEndpoint omdbInsightEndpoint;
+ private Pipeline pipeline;
+ private Random random = new Random();
+
+ @Before
+ public void setUp() throws Exception {
+ omMetadataManager = initializeNewOmMetadataManager(
+ temporaryFolder.newFolder());
+ reconOMMetadataManager = getTestReconOmMetadataManager(omMetadataManager,
+ 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(OMDBInsightEndpoint.class)
+ .addBinding(ContainerHealthSchemaManager.class)
+ .build();
+ reconContainerMetadataManager =
+ reconTestInjector.getInstance(ReconContainerMetadataManager.class);
+ omdbInsightEndpoint = reconTestInjector.getInstance(
+ OMDBInsightEndpoint.class);
+ ozoneStorageContainerManager =
+ reconTestInjector.getInstance(OzoneStorageContainerManager.class);
+ reconPipelineManager = (ReconPipelineManager)
+ ozoneStorageContainerManager.getPipelineManager();
+ pipeline = getRandomPipeline();
+ reconPipelineManager.addPipeline(pipeline);
+ setUpOmData();
+ }
+
+ private void setUpOmData() throws Exception {
+ List<OmKeyLocationInfo> omKeyLocationInfoList = new ArrayList<>();
+ BlockID blockID1 = new BlockID(1, 101);
+ OmKeyLocationInfo omKeyLocationInfo1 = getOmKeyLocationInfo(blockID1,
+ pipeline);
+ omKeyLocationInfoList.add(omKeyLocationInfo1);
+
+ BlockID blockID2 = new BlockID(2, 102);
+ OmKeyLocationInfo omKeyLocationInfo2 = getOmKeyLocationInfo(blockID2,
+ pipeline);
+ omKeyLocationInfoList.add(omKeyLocationInfo2);
+
+ OmKeyLocationInfoGroup omKeyLocationInfoGroup = new
+ OmKeyLocationInfoGroup(0, omKeyLocationInfoList);
+
+ //key = key_one, Blocks = [ {CID = 1, LID = 101}, {CID = 2, LID = 102} ]
+ writeDataToOm(reconOMMetadataManager,
+ "key_one", "bucketOne", "sampleVol",
+ Collections.singletonList(omKeyLocationInfoGroup));
+
+ List<OmKeyLocationInfoGroup> infoGroups = new ArrayList<>();
+ BlockID blockID3 = new BlockID(1, 103);
+ OmKeyLocationInfo omKeyLocationInfo3 = getOmKeyLocationInfo(blockID3,
+ pipeline);
+
+ List<OmKeyLocationInfo> omKeyLocationInfoListNew = new ArrayList<>();
+ omKeyLocationInfoListNew.add(omKeyLocationInfo3);
+ infoGroups.add(new OmKeyLocationInfoGroup(0,
+ omKeyLocationInfoListNew));
+
+ BlockID blockID4 = new BlockID(2, 104);
+ OmKeyLocationInfo omKeyLocationInfo4 = getOmKeyLocationInfo(blockID4,
+ pipeline);
+
+ omKeyLocationInfoListNew = new ArrayList<>();
+ omKeyLocationInfoListNew.add(omKeyLocationInfo4);
+ infoGroups.add(new OmKeyLocationInfoGroup(1,
+ omKeyLocationInfoListNew));
+
+ //key = key_two, Blocks = [ {CID = 1, LID = 103}, {CID = 1, LID = 104} ]
+ writeDataToOm(reconOMMetadataManager,
+ "key_two", "bucketOne", "sampleVol", infoGroups);
+
+ List<OmKeyLocationInfo> omKeyLocationInfoList2 = new ArrayList<>();
+ BlockID blockID5 = new BlockID(3, 105);
+ OmKeyLocationInfo omKeyLocationInfo5 = getOmKeyLocationInfo(blockID5,
+ pipeline);
+ omKeyLocationInfoList2.add(omKeyLocationInfo5);
+
+ BlockID blockID6 = new BlockID(3, 106);
+ OmKeyLocationInfo omKeyLocationInfo6 = getOmKeyLocationInfo(blockID6,
+ pipeline);
+ omKeyLocationInfoList2.add(omKeyLocationInfo6);
+
+ OmKeyLocationInfoGroup omKeyLocationInfoGroup2 = new
+ OmKeyLocationInfoGroup(0, omKeyLocationInfoList2);
+
+ //key = key_three, Blocks = [ {CID = 2, LID = 2}, {CID = 2, LID = 3} ]
+ writeDataToOm(reconOMMetadataManager,
+ "key_three", "bucketOne", "sampleVol",
+ Collections.singletonList(omKeyLocationInfoGroup2));
+
+ //Generate Recon container DB data.
+ OMMetadataManager omMetadataManagerMock = mock(OMMetadataManager.class);
+ Table tableMock = mock(Table.class);
+ when(tableMock.getName()).thenReturn("KeyTable");
+ when(omMetadataManagerMock.getKeyTable(getBucketLayout()))
+ .thenReturn(tableMock);
+ ContainerKeyMapperTask containerKeyMapperTask =
+ new ContainerKeyMapperTask(reconContainerMetadataManager);
+ containerKeyMapperTask.reprocess(reconOMMetadataManager);
+ }
+
+ @Test
+ public void testGetOpenKeyInfo() throws Exception {
+ OmKeyInfo omKeyInfo =
+ getOmKeyInfo("sampleVol", "bucketOne", "key_one", true);
+
+ reconOMMetadataManager.getOpenKeyTable(getBucketLayout())
+ .put("/sampleVol/bucketOne/key_one", omKeyInfo);
+ OmKeyInfo omKeyInfo1 =
+ reconOMMetadataManager.getOpenKeyTable(getBucketLayout())
+ .get("/sampleVol/bucketOne/key_one");
+ Assertions.assertEquals("key_one", omKeyInfo1.getKeyName());
+ Response openKeyInfoResp = omdbInsightEndpoint.getOpenKeyInfo(-1, "");
+ KeyInsightInfoResponse keyInsightInfoResp =
+ (KeyInsightInfoResponse) openKeyInfoResp.getEntity();
+ Assertions.assertNotNull(keyInsightInfoResp);
+ Assertions.assertEquals("key_one",
+ keyInsightInfoResp.getNonFSOKeyInfoList().get(0).getPath());
+ }
+
+ @Test
+ public void testGetOpenKeyInfoLimitParam() throws Exception {
+ OmKeyInfo omKeyInfo1 =
+ getOmKeyInfo("sampleVol", "bucketOne", "key_one", true);
+ OmKeyInfo omKeyInfo2 =
+ getOmKeyInfo("sampleVol", "bucketOne", "key_two", true);
+ OmKeyInfo omKeyInfo3 =
+ getOmKeyInfo("sampleVol", "bucketOne", "key_three", true);
+
+ reconOMMetadataManager.getOpenKeyTable(getBucketLayout())
+ .put("/sampleVol/bucketOne/key_one", omKeyInfo1);
+ reconOMMetadataManager.getOpenKeyTable(BucketLayout.FILE_SYSTEM_OPTIMIZED)
+ .put("/sampleVol/bucketOne/key_two", omKeyInfo2);
+ reconOMMetadataManager.getOpenKeyTable(getBucketLayout())
+ .put("/sampleVol/bucketOne/key_three", omKeyInfo3);
+ Response openKeyInfoResp = omdbInsightEndpoint.getOpenKeyInfo(2, "");
+ KeyInsightInfoResponse keyInsightInfoResp =
+ (KeyInsightInfoResponse) openKeyInfoResp.getEntity();
+ Assertions.assertNotNull(keyInsightInfoResp);
+ Assertions.assertEquals(2,
+ keyInsightInfoResp.getNonFSOKeyInfoList().size());
+ Assertions.assertEquals(0, keyInsightInfoResp.getFsoKeyInfoList().size());
+ Assertions.assertEquals(2, keyInsightInfoResp.getFsoKeyInfoList().size() +
+ keyInsightInfoResp.getNonFSOKeyInfoList().size());
+ Assertions.assertEquals("key_three",
+ keyInsightInfoResp.getNonFSOKeyInfoList().get(1).getPath());
+
+ openKeyInfoResp = omdbInsightEndpoint.getOpenKeyInfo(3, "");
+ keyInsightInfoResp =
+ (KeyInsightInfoResponse) openKeyInfoResp.getEntity();
+ Assertions.assertNotNull(keyInsightInfoResp);
+ Assertions.assertEquals(2,
+ keyInsightInfoResp.getNonFSOKeyInfoList().size());
+ Assertions.assertEquals(1, keyInsightInfoResp.getFsoKeyInfoList().size());
+ Assertions.assertEquals(3, keyInsightInfoResp.getFsoKeyInfoList().size() +
+ keyInsightInfoResp.getNonFSOKeyInfoList().size());
+ Assertions.assertEquals("key_three",
+ keyInsightInfoResp.getNonFSOKeyInfoList().get(1).getPath());
+ }
+
+ @Test
+ public void testGetOpenKeyInfoPrevKeyParam() throws Exception {
+ OmKeyInfo omKeyInfo1 =
+ getOmKeyInfo("sampleVol", "bucketOne", "key_one", true);
+ OmKeyInfo omKeyInfo2 =
+ getOmKeyInfo("sampleVol", "bucketOne", "key_two", true);
+ OmKeyInfo omKeyInfo3 =
+ getOmKeyInfo("sampleVol", "bucketOne", "key_three", true);
+
+ reconOMMetadataManager.getOpenKeyTable(getBucketLayout())
+ .put("/sampleVol/bucketOne/key_one", omKeyInfo1);
+ reconOMMetadataManager.getOpenKeyTable(BucketLayout.FILE_SYSTEM_OPTIMIZED)
+ .put("/sampleVol/bucketOne/key_two", omKeyInfo2);
+ reconOMMetadataManager.getOpenKeyTable(getBucketLayout())
+ .put("/sampleVol/bucketOne/key_three", omKeyInfo3);
+ Response openKeyInfoResp =
+ omdbInsightEndpoint.getOpenKeyInfo(-1, "/sampleVol/bucketOne/key_one");
+ KeyInsightInfoResponse keyInsightInfoResp =
+ (KeyInsightInfoResponse) openKeyInfoResp.getEntity();
+ Assertions.assertNotNull(keyInsightInfoResp);
+ Assertions.assertEquals(1,
+ keyInsightInfoResp.getNonFSOKeyInfoList().size());
+ Assertions.assertEquals(1, keyInsightInfoResp.getFsoKeyInfoList().size());
+ Assertions.assertEquals(2, keyInsightInfoResp.getFsoKeyInfoList().size() +
+ keyInsightInfoResp.getNonFSOKeyInfoList().size());
+ Assertions.assertEquals("key_three",
+ keyInsightInfoResp.getNonFSOKeyInfoList().get(0).getPath());
+ Assertions.assertEquals("key_two",
+ keyInsightInfoResp.getFsoKeyInfoList().get(0).getPath());
+ }
+
+ @Test
+ public void testGetDeletedKeyInfoLimitParam() throws Exception {
+ OmKeyInfo omKeyInfo1 =
+ getOmKeyInfo("sampleVol", "bucketOne", "key_one", true);
+ OmKeyInfo omKeyInfo2 =
+ getOmKeyInfo("sampleVol", "bucketOne", "key_two", true);
+ OmKeyInfo omKeyInfo3 =
+ getOmKeyInfo("sampleVol", "bucketOne", "key_three", true);
+
+ reconOMMetadataManager.getKeyTable(getBucketLayout())
+ .put("/sampleVol/bucketOne/key_one", omKeyInfo1);
+ reconOMMetadataManager.getKeyTable(getBucketLayout())
+ .put("/sampleVol/bucketOne/key_two", omKeyInfo2);
+ reconOMMetadataManager.getKeyTable(getBucketLayout())
+ .put("/sampleVol/bucketOne/key_three", omKeyInfo3);
+
+ OmKeyInfo omKeyInfoCopy =
+ reconOMMetadataManager.getKeyTable(getBucketLayout())
+ .get("/sampleVol/bucketOne/key_one");
+ Assertions.assertEquals("key_one", omKeyInfoCopy.getKeyName());
+ RepeatedOmKeyInfo repeatedOmKeyInfo1 = new
RepeatedOmKeyInfo(omKeyInfoCopy);
+
+ reconOMMetadataManager.getDeletedTable()
+ .put("/sampleVol/bucketOne/key_one", repeatedOmKeyInfo1);
+ Assertions.assertEquals("key_one",
+ repeatedOmKeyInfo1.getOmKeyInfoList().get(0).getKeyName());
+
+ RepeatedOmKeyInfo repeatedOmKeyInfo2 = new RepeatedOmKeyInfo(omKeyInfo2);
+ RepeatedOmKeyInfo repeatedOmKeyInfo3 = new RepeatedOmKeyInfo(omKeyInfo2);
+ reconOMMetadataManager.getDeletedTable()
+ .put("/sampleVol/bucketOne/key_two", repeatedOmKeyInfo2);
+ reconOMMetadataManager.getDeletedTable()
+ .put("/sampleVol/bucketOne/key_three", repeatedOmKeyInfo3);
+
+ Response deletedKeyInfo = omdbInsightEndpoint.getDeletedKeyInfo(2, "");
+ KeyInsightInfoResponse keyInsightInfoResp =
+ (KeyInsightInfoResponse) deletedKeyInfo.getEntity();
+ Assertions.assertNotNull(keyInsightInfoResp);
+ Assertions.assertEquals(2,
+ keyInsightInfoResp.getRepeatedOmKeyInfoList().size());
+ Assertions.assertEquals("key_two",
+ keyInsightInfoResp.getRepeatedOmKeyInfoList().get(1).getOmKeyInfoList()
+ .get(0).getKeyName());
+ }
+
+ @Test
+ public void testGetDeletedKeyInfoPrevKeyParam() throws Exception {
+ OmKeyInfo omKeyInfo1 =
+ getOmKeyInfo("sampleVol", "bucketOne", "key_one", true);
+ OmKeyInfo omKeyInfo2 =
+ getOmKeyInfo("sampleVol", "bucketOne", "key_two", true);
+ OmKeyInfo omKeyInfo3 =
+ getOmKeyInfo("sampleVol", "bucketOne", "key_three", true);
+
+ RepeatedOmKeyInfo repeatedOmKeyInfo1 = new RepeatedOmKeyInfo(omKeyInfo1);
+ RepeatedOmKeyInfo repeatedOmKeyInfo2 = new RepeatedOmKeyInfo(omKeyInfo2);
+ RepeatedOmKeyInfo repeatedOmKeyInfo3 = new RepeatedOmKeyInfo(omKeyInfo3);
+
+ reconOMMetadataManager.getDeletedTable()
+ .put("/sampleVol/bucketOne/key_one", repeatedOmKeyInfo1);
+ reconOMMetadataManager.getDeletedTable()
+ .put("/sampleVol/bucketOne/key_two", repeatedOmKeyInfo2);
+ reconOMMetadataManager.getDeletedTable()
+ .put("/sampleVol/bucketOne/key_three", repeatedOmKeyInfo3);
+
+ Response deletedKeyInfo = omdbInsightEndpoint.getDeletedKeyInfo(2,
+ "/sampleVol/bucketOne/key_one");
+ KeyInsightInfoResponse keyInsightInfoResp =
+ (KeyInsightInfoResponse) deletedKeyInfo.getEntity();
+ Assertions.assertNotNull(keyInsightInfoResp);
+ Assertions.assertEquals(2,
+ keyInsightInfoResp.getRepeatedOmKeyInfoList().size());
+
+ List<String> pendingDeleteKeys =
+ keyInsightInfoResp.getRepeatedOmKeyInfoList().stream()
+ .map(
+ repeatedOmKeyInfo ->
repeatedOmKeyInfo.getOmKeyInfoList().get(0)
+ .getKeyName())
+ .collect(Collectors.toList());
+ Assertions.assertFalse(pendingDeleteKeys.contains("key_one"));
+ }
+
+ @Test
+ public void testGetDeletedKeyInfo() throws Exception {
+ OmKeyInfo omKeyInfo =
+ getOmKeyInfo("sampleVol", "bucketOne", "key_one", true);
+
+ reconOMMetadataManager.getKeyTable(getBucketLayout())
+ .put("/sampleVol/bucketOne/key_one", omKeyInfo);
+ OmKeyInfo omKeyInfo1 =
reconOMMetadataManager.getKeyTable(getBucketLayout())
+ .get("/sampleVol/bucketOne/key_one");
+ Assertions.assertEquals("key_one", omKeyInfo1.getKeyName());
+ RepeatedOmKeyInfo repeatedOmKeyInfo = new RepeatedOmKeyInfo(omKeyInfo);
+ reconOMMetadataManager.getDeletedTable()
+ .put("/sampleVol/bucketOne/key_one", repeatedOmKeyInfo);
+ RepeatedOmKeyInfo repeatedOmKeyInfo1 =
+ reconOMMetadataManager.getDeletedTable()
+ .get("/sampleVol/bucketOne/key_one");
+ Assertions.assertEquals("key_one",
+ repeatedOmKeyInfo1.getOmKeyInfoList().get(0).getKeyName());
+ Response deletedKeyInfo = omdbInsightEndpoint.getDeletedKeyInfo(-1, "");
+ KeyInsightInfoResponse keyInsightInfoResp =
+ (KeyInsightInfoResponse) deletedKeyInfo.getEntity();
+ Assertions.assertNotNull(keyInsightInfoResp);
+ Assertions.assertEquals("key_one",
+ keyInsightInfoResp.getRepeatedOmKeyInfoList().get(0).getOmKeyInfoList()
+ .get(0).getKeyName());
+ }
+
+ private OmKeyInfo getOmKeyInfo(String volumeName, String bucketName,
+ String keyName, boolean isFile) {
+ return new OmKeyInfo.Builder()
+ .setVolumeName(volumeName)
+ .setBucketName(bucketName)
+ .setKeyName(keyName)
+ .setFile(isFile)
+ .setReplicationConfig(StandaloneReplicationConfig
+ .getInstance(HddsProtos.ReplicationFactor.ONE))
+ .setDataSize(random.nextLong())
+ .build();
+ }
+
+ @Test
+ public void testGetDeletedDirInfoLimitParam() throws Exception {
+ OmKeyInfo omKeyInfo1 =
+ getOmKeyInfo("sampleVol", "bucketOne", "dir_one", false);
+ OmKeyInfo omKeyInfo2 =
+ getOmKeyInfo("sampleVol", "bucketOne", "dir_two", false);
+ OmKeyInfo omKeyInfo3 =
+ getOmKeyInfo("sampleVol", "bucketOne", "dir_three", false);
+
+ reconOMMetadataManager.getDeletedDirTable()
+ .put("/sampleVol/bucketOne/dir_one", omKeyInfo1);
+ reconOMMetadataManager.getDeletedDirTable()
+ .put("/sampleVol/bucketOne/dir_two", omKeyInfo2);
+ reconOMMetadataManager.getDeletedDirTable()
+ .put("/sampleVol/bucketOne/dir_three", omKeyInfo3);
+
+ OmKeyInfo omKeyInfoCopy =
+ reconOMMetadataManager.getDeletedDirTable()
+ .get("/sampleVol/bucketOne/dir_one");
+ Assertions.assertEquals("dir_one", omKeyInfoCopy.getKeyName());
+
+ Response deletedDirInfo = omdbInsightEndpoint.getDeletedDirInfo(2, "");
+ KeyInsightInfoResponse keyInsightInfoResp =
+ (KeyInsightInfoResponse) deletedDirInfo.getEntity();
+ Assertions.assertNotNull(keyInsightInfoResp);
+ Assertions.assertEquals(2,
+ keyInsightInfoResp.getDeletedDirInfoList().size());
+ Assertions.assertEquals("/sampleVol/bucketOne/dir_one",
+ keyInsightInfoResp.getDeletedDirInfoList().get(0).getKey());
+ }
+
+ @Test
+ public void testGetDeletedDirInfoPrevKeyParam() throws Exception {
+ OmKeyInfo omKeyInfo1 =
+ getOmKeyInfo("sampleVol", "bucketOne", "dir_one", false);
+ OmKeyInfo omKeyInfo2 =
+ getOmKeyInfo("sampleVol", "bucketOne", "dir_two", false);
+ OmKeyInfo omKeyInfo3 =
+ getOmKeyInfo("sampleVol", "bucketOne", "dir_three", false);
+
+ reconOMMetadataManager.getDeletedDirTable()
+ .put("/sampleVol/bucketOne/dir_one", omKeyInfo1);
+ reconOMMetadataManager.getDeletedDirTable()
+ .put("/sampleVol/bucketOne/dir_two", omKeyInfo2);
+ reconOMMetadataManager.getDeletedDirTable()
+ .put("/sampleVol/bucketOne/dir_three", omKeyInfo3);
+
+ OmKeyInfo omKeyInfoCopy =
+ reconOMMetadataManager.getDeletedDirTable()
+ .get("/sampleVol/bucketOne/dir_one");
+ Assertions.assertEquals("dir_one", omKeyInfoCopy.getKeyName());
+
+ Response deletedDirInfo = omdbInsightEndpoint.getDeletedDirInfo(2,
+ "/sampleVol/bucketOne/dir_one");
+ KeyInsightInfoResponse keyInsightInfoResp =
+ (KeyInsightInfoResponse) deletedDirInfo.getEntity();
+ Assertions.assertNotNull(keyInsightInfoResp);
+ Assertions.assertEquals(2,
+ keyInsightInfoResp.getDeletedDirInfoList().size());
+ Assertions.assertEquals("/sampleVol/bucketOne/dir_three",
+ keyInsightInfoResp.getDeletedDirInfoList().get(0).getKey());
+ Assertions.assertEquals("/sampleVol/bucketOne/dir_two",
+ keyInsightInfoResp.getLastKey());
+ }
+
+ @Test
+ public void testGetDeletedDirInfo() throws Exception {
+ OmKeyInfo omKeyInfo1 =
+ getOmKeyInfo("sampleVol", "bucketOne", "dir_one", false);
+ OmKeyInfo omKeyInfo2 =
+ getOmKeyInfo("sampleVol", "bucketOne", "dir_two", false);
+ OmKeyInfo omKeyInfo3 =
+ getOmKeyInfo("sampleVol", "bucketOne", "dir_three", false);
+
+ reconOMMetadataManager.getDeletedDirTable()
+ .put("/sampleVol/bucketOne/dir_one", omKeyInfo1);
+ reconOMMetadataManager.getDeletedDirTable()
+ .put("/sampleVol/bucketOne/dir_two", omKeyInfo2);
+ reconOMMetadataManager.getDeletedDirTable()
+ .put("/sampleVol/bucketOne/dir_three", omKeyInfo3);
+
+ OmKeyInfo omKeyInfoCopy =
+ reconOMMetadataManager.getDeletedDirTable()
+ .get("/sampleVol/bucketOne/dir_one");
+ Assertions.assertEquals("dir_one", omKeyInfoCopy.getKeyName());
+
+ Response deletedDirInfo = omdbInsightEndpoint.getDeletedDirInfo(-1, "");
+ KeyInsightInfoResponse keyInsightInfoResp =
+ (KeyInsightInfoResponse) deletedDirInfo.getEntity();
+ Assertions.assertNotNull(keyInsightInfoResp);
+ Assertions.assertEquals(3,
+ keyInsightInfoResp.getDeletedDirInfoList().size());
+ Assertions.assertEquals("/sampleVol/bucketOne/dir_one",
+ keyInsightInfoResp.getDeletedDirInfoList().get(0).getKey());
+ Assertions.assertEquals("/sampleVol/bucketOne/dir_two",
+ keyInsightInfoResp.getLastKey());
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]