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 2642f375de1 HDDS-14518. Support open keys and MPU in
ContainerToKeyMapping tool (#9703)
2642f375de1 is described below
commit 2642f375de1acf17b16c5553b1de4d375b7ad6d7
Author: Sarveksha Yeshavantha Raju
<[email protected]>
AuthorDate: Wed Feb 25 17:53:11 2026 +0530
HDDS-14518. Support open keys and MPU in ContainerToKeyMapping tool (#9703)
---
.../ozone/debug/om/ContainerToKeyMapping.java | 118 +++++++++++++++++++--
.../ozone/debug/om/TestContainerToKeyMapping.java | 117 +++++++++++++++++++-
2 files changed, 225 insertions(+), 10 deletions(-)
diff --git
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/om/ContainerToKeyMapping.java
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/om/ContainerToKeyMapping.java
index f6dc0e3732e..0da411b34d4 100644
---
a/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/om/ContainerToKeyMapping.java
+++
b/hadoop-ozone/cli-debug/src/main/java/org/apache/hadoop/ozone/debug/om/ContainerToKeyMapping.java
@@ -52,7 +52,9 @@
import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
import org.apache.hadoop.ozone.om.helpers.OmDirectoryInfo;
import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
+import org.apache.hadoop.ozone.om.helpers.OmMultipartKeyInfo;
import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PartKeyInfo;
import picocli.CommandLine;
/**
@@ -84,12 +86,20 @@ public class ContainerToKeyMapping extends
AbstractSubcommand implements Callabl
description = "Only display file names without full path")
private boolean onlyFileNames;
+ @CommandLine.Option(names = {"--in-progress"},
+ defaultValue = "false",
+ description = "Includes in-progress open files/keys and multipart
uploads")
+ private boolean inProgress;
+
private DBStore omDbStore;
private Table<String, OmVolumeArgs> volumeTable;
private Table<String, OmBucketInfo> bucketTable;
private Table<String, OmDirectoryInfo> directoryTable;
private Table<String, OmKeyInfo> fileTable;
private Table<String, OmKeyInfo> keyTable;
+ private Table<String, OmKeyInfo> openFileTable;
+ private Table<String, OmKeyInfo> openKeyTable;
+ private Table<String, OmMultipartKeyInfo> multipartInfoTable;
private DBStore dirTreeDbStore;
private Table<Long, String> dirTreeTable;
// Cache volume IDs to avoid repeated lookups
@@ -98,7 +108,6 @@ public class ContainerToKeyMapping extends
AbstractSubcommand implements Callabl
@Override
public Void call() throws Exception {
-
String dbPath = parent.getDbPath();
// Parse container IDs
Set<Long> containerIDs = Arrays.stream(containers.split(","))
@@ -126,6 +135,9 @@ public Void call() throws Exception {
directoryTable = OMDBDefinition.DIRECTORY_TABLE_DEF.getTable(omDbStore,
CacheType.NO_CACHE);
fileTable = OMDBDefinition.FILE_TABLE_DEF.getTable(omDbStore,
CacheType.NO_CACHE);
keyTable = OMDBDefinition.KEY_TABLE_DEF.getTable(omDbStore,
CacheType.NO_CACHE);
+ openFileTable = OMDBDefinition.OPEN_FILE_TABLE_DEF.getTable(omDbStore,
CacheType.NO_CACHE);
+ openKeyTable = OMDBDefinition.OPEN_KEY_TABLE_DEF.getTable(omDbStore,
CacheType.NO_CACHE);
+ multipartInfoTable =
OMDBDefinition.MULTIPART_INFO_TABLE_DEF.getTable(omDbStore, CacheType.NO_CACHE);
retrieve(dbPath, writer, containerIDs);
} catch (Exception e) {
@@ -181,6 +193,8 @@ private void retrieve(String dbPath, PrintWriter writer,
Set<Long> containerIds)
// Map to collect keys per container
Map<Long, List<String>> containerToKeysMap = new HashMap<>();
+ // Map to collect open keys per container
+ Map<Long, List<String>> containerToOpenKeysMap = inProgress ? new
HashMap<>() : null;
// Track unreferenced keys count per container (FSO only)
Map<Long, Long> unreferencedCountMap = new HashMap<>();
for (Long containerId : containerIds) {
@@ -188,13 +202,20 @@ private void retrieve(String dbPath, PrintWriter writer,
Set<Long> containerIds)
unreferencedCountMap.put(containerId, 0L);
}
+ // Process open file and open key tables
+ if (inProgress) {
+ for (Long containerId : containerIds) {
+ containerToOpenKeysMap.put(containerId, new ArrayList<>());
+ }
+ processOpenFiles(containerIds, containerToOpenKeysMap);
+ processOpenKeys(containerIds, containerToOpenKeysMap);
+ processMultipartUpload(containerIds, containerToOpenKeysMap);
+ }
// Process FSO keys (fileTable)
processFSOKeys(containerIds, containerToKeysMap, unreferencedCountMap,
bucketVolMap);
-
// Process OBS keys (keyTable)
processOBSKeys(containerIds, containerToKeysMap);
-
- jsonOutput(writer, containerToKeysMap, unreferencedCountMap);
+ jsonOutput(writer, containerToKeysMap, containerToOpenKeysMap,
unreferencedCountMap);
}
private void processFSOKeys(Set<Long> containerIds, Map<Long, List<String>>
containerToKeysMap,
@@ -251,6 +272,69 @@ private void processOBSKeys(Set<Long> containerIds,
Map<Long, List<String>> cont
}
}
+ private void processOpenFiles(Set<Long> containerIds, Map<Long,
List<String>> containerToOpenKeysMap) {
+ try (TableIterator<String, ? extends Table.KeyValue<String, OmKeyInfo>>
fileIterator =
+ openFileTable.iterator()) {
+ while (fileIterator.hasNext()) {
+ Table.KeyValue<String, OmKeyInfo> entry = fileIterator.next();
+ addOpenKeyToContainerMap(entry.getKey(), entry.getValue(),
containerIds, containerToOpenKeysMap);
+ }
+ } catch (Exception e) {
+ err().println("Exception occurred reading openFileTable (FSO keys), " +
e);
+ }
+ }
+
+ private void processOpenKeys(Set<Long> containerIds, Map<Long, List<String>>
containerToOpenKeysMap) {
+ try (TableIterator<String, ? extends Table.KeyValue<String, OmKeyInfo>>
keyIterator =
+ openKeyTable.iterator()) {
+ while (keyIterator.hasNext()) {
+ Table.KeyValue<String, OmKeyInfo> entry = keyIterator.next();
+ addOpenKeyToContainerMap(entry.getKey(), entry.getValue(),
containerIds, containerToOpenKeysMap);
+ }
+ } catch (Exception e) {
+ err().println("Exception occurred reading openKeyTable (OBS keys), " +
e);
+ }
+ }
+
+ private void addOpenKeyToContainerMap(String dbKey, OmKeyInfo keyInfo,
Set<Long> containerIds,
+ Map<Long, List<String>> containerToOpenKeysMap) {
+ // Find which containers this key uses
+ Set<Long> keyContainers = getKeyContainers(keyInfo, containerIds);
+
+ if (!keyContainers.isEmpty()) {
+ for (Long containerId : keyContainers) {
+ containerToOpenKeysMap.get(containerId).add(dbKey);
+ }
+ }
+ }
+
+ private void processMultipartUpload(Set<Long> containerIds, Map<Long,
List<String>> containerToOpenKeysMap) {
+ try (TableIterator<String, ? extends Table.KeyValue<String,
OmMultipartKeyInfo>> mpuIterator =
+ multipartInfoTable.iterator()) {
+
+ while (mpuIterator.hasNext()) {
+ Table.KeyValue<String, OmMultipartKeyInfo> entry = mpuIterator.next();
+ String dbKey = entry.getKey();
+ OmMultipartKeyInfo mpuInfo = entry.getValue();
+
+ // Collect all target containers that have parts of this MPU
+ Set<Long> matchedContainers = new HashSet<>();
+ for (PartKeyInfo partKeyInfo : mpuInfo.getPartKeyInfoMap()) {
+ OmKeyInfo partKey =
OmKeyInfo.getFromProtobuf(partKeyInfo.getPartKeyInfo());
+ matchedContainers.addAll(getKeyContainers(partKey, containerIds));
+ }
+
+ if (!matchedContainers.isEmpty()) {
+ for (Long containerId : matchedContainers) {
+ containerToOpenKeysMap.get(containerId).add(dbKey);
+ }
+ }
+ }
+ } catch (Exception e) {
+ err().println("Exception occurred reading multipartInfoTable, " + e);
+ }
+ }
+
private Set<Long> getKeyContainers(OmKeyInfo keyInfo, Set<Long>
targetContainerIds) {
Set<Long> keyContainers = new HashSet<>();
keyInfo.getKeyLocationVersions().forEach(
@@ -317,11 +401,11 @@ private String reconstructFullPath(OmKeyInfo keyInfo,
Map<Long, Pair<Long, Strin
// Check dir tree
Pair<Long, String> nameParentPair = getFromDirTree(prvParent);
if (nameParentPair == null) {
- // If parent is not found, mark the key as unreferenced and increment
its count
+ // If parent is not found (maybe in deletion process), increment
unreferenced count
for (Long containerId : keyContainers) {
unreferencedCountMap.put(containerId,
unreferencedCountMap.get(containerId) + 1);
}
- return "[unreferenced] " + keyInfo.getKeyName();
+ return null;
}
sb.insert(0, nameParentPair.getValue() + OM_KEY_PREFIX);
prvParent = nameParentPair.getKey();
@@ -372,7 +456,7 @@ private void addToDirTree(Long objectId, Long parentId,
String name) throws IOEx
}
private void jsonOutput(PrintWriter writer, Map<Long, List<String>>
containerToKeysMap,
- Map<Long, Long> unreferencedCountMap) {
+ Map<Long, List<String>> containerToOpenKeysMap, Map<Long, Long>
unreferencedCountMap) {
try {
ObjectMapper mapper = new ObjectMapper();
ObjectNode root = mapper.createObjectNode();
@@ -388,13 +472,30 @@ private void jsonOutput(PrintWriter writer, Map<Long,
List<String>> containerToK
}
containerNode.set("keys", keysArray);
- containerNode.put("totalKeys", entry.getValue().size()); // includes
unreferenced keys
+
+ // Add open keys array only if --in-progress flag is set
+ long totalKeys = entry.getValue().size();
+ if (containerToOpenKeysMap != null) {
+ ArrayNode openKeysArray = mapper.createArrayNode();
+ List<String> openKeys = containerToOpenKeysMap.get(containerId);
+ if (openKeys != null) {
+ for (String key : openKeys) {
+ openKeysArray.add(key);
+ }
+ totalKeys += openKeys.size();
+ }
+ containerNode.set("openKeys", openKeysArray);
+ }
// Add unreferenced count if > 0
long unreferencedCount = unreferencedCountMap.get(containerId);
if (unreferencedCount > 0) {
containerNode.put("unreferencedKeys", unreferencedCount);
+ totalKeys += unreferencedCount;
}
+
+ // Total keys = committed keys + open keys + unreferenced keys
+ containerNode.put("totalKeys", totalKeys);
containersNode.set(containerId.toString(), containerNode);
}
@@ -407,4 +508,3 @@ private void jsonOutput(PrintWriter writer, Map<Long,
List<String>> containerToK
}
}
}
-
diff --git
a/hadoop-ozone/cli-debug/src/test/java/org/apache/hadoop/ozone/debug/om/TestContainerToKeyMapping.java
b/hadoop-ozone/cli-debug/src/test/java/org/apache/hadoop/ozone/debug/om/TestContainerToKeyMapping.java
index 66f55fda1a4..4cad62cd719 100644
---
a/hadoop-ozone/cli-debug/src/test/java/org/apache/hadoop/ozone/debug/om/TestContainerToKeyMapping.java
+++
b/hadoop-ozone/cli-debug/src/test/java/org/apache/hadoop/ozone/debug/om/TestContainerToKeyMapping.java
@@ -40,7 +40,10 @@
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.OmMultipartKeyInfo;
import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.KeyInfo;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PartKeyInfo;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -72,8 +75,14 @@ public class TestContainerToKeyMapping {
private static final long CONTAINER_ID_1 = 1L;
private static final long CONTAINER_ID_2 = 2L;
private static final long CONTAINER_ID_3 = 3L;
+ private static final long CONTAINER_ID_4 = 4L;
private static final long UNREFERENCED_FILE_ID = 500L;
private static final long MISSING_DIR_ID = 999L; // Non-existent parent
+ private static final long OPEN_FILE_ID = 600L;
+ private static final long OPEN_KEY_ID = 610L;
+ private static final long MPU_KEY_ID = 700L;
+ private static final long MPU_PART1_ID = 710L;
+ private static final long MPU_PART2_ID = 720L;
@BeforeEach
public void setup() throws Exception {
@@ -137,6 +146,51 @@ public void testContainerToKeyMappingWithOnlyFileNames() {
}
@Test
+ public void testContainerToKeyMappingWithOpenKeys() {
+ int exitCode = execute("--containers", CONTAINER_ID_1 + "," +
CONTAINER_ID_2, "--in-progress");
+ assertEquals(0, exitCode);
+
+ String output = outWriter.toString();
+
+ // Check open FSO file in openKeys
+ assertThat(output).contains("\"" + CONTAINER_ID_1 + "\"");
+ assertThat(output).contains("\"openKeys\"");
+ assertThat(output).contains("/100/200/300/openFile/1");
+
+ // Check open OBS key in openKeys
+ assertThat(output).contains("\"" + CONTAINER_ID_2 + "\"");
+ assertThat(output).contains("\"openKeys\"");
+ assertThat(output).contains("/vol1/obs-bucket/openKey");
+ }
+
+ @Test
+ public void testContainerToKeyMappingWithMPU() {
+ int exitCode = execute("--containers", String.valueOf(CONTAINER_ID_4),
"--in-progress");
+ assertEquals(0, exitCode);
+
+ String output = outWriter.toString();
+
+ // Check MPU parts in openKeys
+ assertThat(output).contains("\"" + CONTAINER_ID_4 + "\"");
+ assertThat(output).contains("\"openKeys\"");
+ assertThat(output).contains("/vol1/obs-bucket/mpuKey/test-upload-id");
+ }
+
+ @Test
+ public void testContainerToKeyMappingWithMPUOnlyFileNames() {
+ int exitCode = execute("--containers", String.valueOf(CONTAINER_ID_4),
"--in-progress", "--onlyFileNames");
+ assertEquals(0, exitCode);
+
+ String output = outWriter.toString();
+
+ // Open keys and MPU always show table key (not affected by
--onlyFileNames)
+ assertThat(output).contains("\"" + CONTAINER_ID_4 + "\"");
+ assertThat(output).contains("\"openKeys\"");
+ assertThat(output).contains("/vol1/obs-bucket/mpuKey/test-upload-id");
+ }
+
+ @Test
+
public void testNonExistentContainer() {
long nonExistentContainerId = 999L;
@@ -221,6 +275,68 @@ private void createTestData() throws Exception {
String unreferencedFileKey = omMetadataManager.getOzonePathKey(
VOLUME_ID, FSO_BUCKET_ID, MISSING_DIR_ID, "unreferencedFile");
omMetadataManager.getFileTable().put(unreferencedFileKey, unreferencedKey);
+
+ // Create open FSO file with a block in container 1
+ OmKeyInfo openFileInfo = createKeyInfo(
+ "openFile", OPEN_FILE_ID, DIR_ID, CONTAINER_ID_1);
+ String openFileKey = omMetadataManager.getOpenFileName(
+ VOLUME_ID, FSO_BUCKET_ID, DIR_ID, "openFile", 1L);
+
omMetadataManager.getOpenKeyTable(BucketLayout.FILE_SYSTEM_OPTIMIZED).put(openFileKey,
openFileInfo);
+
+ // Create open OBS key with a block in container 2
+ OmKeyInfo openKeyInfo = createOBSKeyInfo(
+ "openKey", OPEN_KEY_ID, CONTAINER_ID_2);
+ String openKey = omMetadataManager.getOzoneKey(
+ VOLUME_NAME, OBS_BUCKET_NAME, "openKey");
+ omMetadataManager.getOpenKeyTable(BucketLayout.OBJECT_STORE).put(openKey,
openKeyInfo);
+
+ // Create MPU (multipart upload) for OBS bucket with parts in container 5
+ createMultipartUpload();
+ }
+
+ /**
+ * Helper method to create a multipart upload with parts.
+ */
+ private void createMultipartUpload() throws Exception {
+ String mpuKeyName = "mpuKey";
+ String uploadId = "test-upload-id";
+
+ // Create part 1 with a block in container 4
+ OmKeyInfo part1Info = createOBSKeyInfo(
+ mpuKeyName + "/" + uploadId + "/part-1", MPU_PART1_ID, CONTAINER_ID_4);
+ KeyInfo part1Proto = part1Info.getProtobuf(true, 0);
+ PartKeyInfo partKeyInfo1 = PartKeyInfo.newBuilder()
+ .setPartName(mpuKeyName + "/" + uploadId + "/part-1")
+ .setPartNumber(1)
+ .setPartKeyInfo(part1Proto)
+ .build();
+
+ // Create part 2 with a block in container 4
+ OmKeyInfo part2Info = createOBSKeyInfo(
+ mpuKeyName + "/" + uploadId + "/part-2", MPU_PART2_ID, CONTAINER_ID_4);
+ KeyInfo part2Proto = part2Info.getProtobuf(true, 0);
+ PartKeyInfo partKeyInfo2 = PartKeyInfo.newBuilder()
+ .setPartName(mpuKeyName + "/" + uploadId + "/part-2")
+ .setPartNumber(2)
+ .setPartKeyInfo(part2Proto)
+ .build();
+
+ // Create OmMultipartKeyInfo - for OBS, parentID should be 0 (not the
bucket ID)
+ OmMultipartKeyInfo mpuInfo = new OmMultipartKeyInfo.Builder()
+ .setUploadID(uploadId)
+ .setCreationTime(System.currentTimeMillis())
+
.setReplicationConfig(StandaloneReplicationConfig.getInstance(HddsProtos.ReplicationFactor.ONE))
+ .addPartKeyInfoList(1, partKeyInfo1)
+ .addPartKeyInfoList(2, partKeyInfo2)
+ .setObjectID(MPU_KEY_ID)
+ .setParentID(0) // OBS keys have parentID = 0
+ .setUpdateID(1)
+ .build();
+
+ // Put into multipartInfoTable
+ String mpuKey = omMetadataManager.getMultipartKey(
+ VOLUME_NAME, OBS_BUCKET_NAME, mpuKeyName, uploadId);
+ omMetadataManager.getMultipartInfoTable().put(mpuKey, mpuInfo);
}
/**
@@ -281,4 +397,3 @@ private int execute(String... args) {
return cmd.execute(argList.toArray(new String[0]));
}
}
-
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]