-
Notifications
You must be signed in to change notification settings - Fork 621
HDDS-15949. Handle split MPU part counting for abort batch sizing and container-key-mapping CLI #10849
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
HDDS-15949. Handle split MPU part counting for abort batch sizing and container-key-mapping CLI #10849
Changes from all commits
0cba235
cb9a2ec
4059cf4
9575f32
e848eaa
d8ac21d
d4b7b89
7c7c5a2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -52,7 +52,10 @@ | |||||||||||||||||||
| 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.OmKeyLocationInfoGroup; | ||||||||||||||||||||
| import org.apache.hadoop.ozone.om.helpers.OmMultipartKeyInfo; | ||||||||||||||||||||
| import org.apache.hadoop.ozone.om.helpers.OmMultipartPartInfo; | ||||||||||||||||||||
| import org.apache.hadoop.ozone.om.helpers.OmMultipartPartKey; | ||||||||||||||||||||
| import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs; | ||||||||||||||||||||
| import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PartKeyInfo; | ||||||||||||||||||||
| import picocli.CommandLine; | ||||||||||||||||||||
|
|
@@ -100,6 +103,7 @@ public class ContainerToKeyMapping extends AbstractSubcommand implements Callabl | |||||||||||||||||||
| private Table<String, OmKeyInfo> openFileTable; | ||||||||||||||||||||
| private Table<String, OmKeyInfo> openKeyTable; | ||||||||||||||||||||
| private Table<String, OmMultipartKeyInfo> multipartInfoTable; | ||||||||||||||||||||
| private Table<OmMultipartPartKey, OmMultipartPartInfo> multipartPartsTable; | ||||||||||||||||||||
| private DBStore dirTreeDbStore; | ||||||||||||||||||||
| private Table<Long, String> dirTreeTable; | ||||||||||||||||||||
| // Cache volume IDs to avoid repeated lookups | ||||||||||||||||||||
|
|
@@ -138,6 +142,7 @@ public Void call() throws Exception { | |||||||||||||||||||
| 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); | ||||||||||||||||||||
| multipartPartsTable = OMDBDefinition.MULTIPART_PARTS_TABLE_DEF.getTable(omDbStore, CacheType.NO_CACHE); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| retrieve(dbPath, writer, containerIDs); | ||||||||||||||||||||
| } catch (Exception e) { | ||||||||||||||||||||
|
|
@@ -313,11 +318,18 @@ private void processMultipartUpload(Set<Long> containerIds, Map<Long, List<Strin | |||||||||||||||||||
| String dbKey = entry.getKey(); | ||||||||||||||||||||
| OmMultipartKeyInfo mpuInfo = entry.getValue(); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Collect all target containers that have parts of this MPU | ||||||||||||||||||||
| // Collect all target containers that have parts of this MPU. Legacy | ||||||||||||||||||||
| // (schemaVersion 0) MPUs embed their parts in the multipartInfoTable | ||||||||||||||||||||
| // value, whereas split (schemaVersion 1) MPUs store each part as a | ||||||||||||||||||||
| // separate row in the multipartPartsTable. | ||||||||||||||||||||
| Set<Long> matchedContainers = new HashSet<>(); | ||||||||||||||||||||
| for (PartKeyInfo partKeyInfo : mpuInfo.getPartKeyInfoMap()) { | ||||||||||||||||||||
| OmKeyInfo partKey = OmKeyInfo.getFromProtobuf(partKeyInfo.getPartKeyInfo()); | ||||||||||||||||||||
| matchedContainers.addAll(getKeyContainers(partKey, containerIds)); | ||||||||||||||||||||
| if (mpuInfo.getSchemaVersion() == OmMultipartKeyInfo.SPLIT_PARTS_TABLE_SCHEMA_VERSION) { | ||||||||||||||||||||
| matchedContainers.addAll(getSplitPartContainers(dbKey, containerIds)); | ||||||||||||||||||||
| } else { | ||||||||||||||||||||
| for (PartKeyInfo partKeyInfo : mpuInfo.getPartKeyInfoMap()) { | ||||||||||||||||||||
| OmKeyInfo partKey = OmKeyInfo.getFromProtobuf(partKeyInfo.getPartKeyInfo()); | ||||||||||||||||||||
| matchedContainers.addAll(getKeyContainers(partKey, containerIds)); | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| if (!matchedContainers.isEmpty()) { | ||||||||||||||||||||
|
|
@@ -332,8 +344,43 @@ private void processMultipartUpload(Set<Long> containerIds, Map<Long, List<Strin | |||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| private Set<Long> getKeyContainers(OmKeyInfo keyInfo, Set<Long> targetContainerIds) { | ||||||||||||||||||||
| return getContainers(keyInfo.getKeyLocationVersions(), targetContainerIds); | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| /** | ||||||||||||||||||||
| * Scans the split multipartPartsTable for all parts belonging to the given | ||||||||||||||||||||
| * multipart upload (its uploadId is the last path component of the | ||||||||||||||||||||
| * multipartInfoTable db key) and returns the target containers referenced by | ||||||||||||||||||||
| * those parts' block locations. | ||||||||||||||||||||
| */ | ||||||||||||||||||||
| private Set<Long> getSplitPartContainers(String multipartInfoDbKey, Set<Long> targetContainerIds) { | ||||||||||||||||||||
| Set<Long> matchedContainers = new HashSet<>(); | ||||||||||||||||||||
| String uploadId = multipartInfoDbKey.substring( | ||||||||||||||||||||
| multipartInfoDbKey.lastIndexOf(OM_KEY_PREFIX) + OM_KEY_PREFIX.length()); | ||||||||||||||||||||
|
Comment on lines
+358
to
+359
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use the below approach instead of manual substring parsing -
Suggested change
|
||||||||||||||||||||
| OmMultipartPartKey prefix = OmMultipartPartKey.prefix(uploadId); | ||||||||||||||||||||
| try (TableIterator<OmMultipartPartKey, Table.KeyValue<OmMultipartPartKey, OmMultipartPartInfo>> | ||||||||||||||||||||
| partIterator = multipartPartsTable.iterator(prefix)) { | ||||||||||||||||||||
| while (partIterator.hasNext()) { | ||||||||||||||||||||
| Table.KeyValue<OmMultipartPartKey, OmMultipartPartInfo> partEntry = partIterator.next(); | ||||||||||||||||||||
| OmMultipartPartKey partKey = partEntry.getKey(); | ||||||||||||||||||||
| // Prefix iteration can overshoot into the next upload's rows; stop then. | ||||||||||||||||||||
| if (!uploadId.equals(partKey.getUploadId())) { | ||||||||||||||||||||
| break; | ||||||||||||||||||||
| } | ||||||||||||||||||||
| if (partKey.hasPartNumber()) { | ||||||||||||||||||||
| matchedContainers.addAll( | ||||||||||||||||||||
| getContainers(partEntry.getValue().getKeyLocationInfos(), targetContainerIds)); | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } catch (Exception e) { | ||||||||||||||||||||
| err().println("Exception occurred reading multipartPartsTable for upload " + uploadId + ", " + e); | ||||||||||||||||||||
| } | ||||||||||||||||||||
| return matchedContainers; | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| private Set<Long> getContainers(List<OmKeyLocationInfoGroup> locationVersions, Set<Long> targetContainerIds) { | ||||||||||||||||||||
| Set<Long> keyContainers = new HashSet<>(); | ||||||||||||||||||||
| keyInfo.getKeyLocationVersions().forEach( | ||||||||||||||||||||
| locationVersions.forEach( | ||||||||||||||||||||
| e -> e.getLocationList().forEach( | ||||||||||||||||||||
| blk -> { | ||||||||||||||||||||
| long cid = blk.getBlockID().getContainerID(); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,6 +31,7 @@ | |
| import org.apache.hadoop.hdds.client.StandaloneReplicationConfig; | ||
| import org.apache.hadoop.hdds.conf.OzoneConfiguration; | ||
| import org.apache.hadoop.hdds.protocol.proto.HddsProtos; | ||
| import org.apache.hadoop.ozone.OzoneConsts; | ||
| import org.apache.hadoop.ozone.debug.OzoneDebug; | ||
| import org.apache.hadoop.ozone.om.OMMetadataManager; | ||
| import org.apache.hadoop.ozone.om.OmMetadataManagerImpl; | ||
|
|
@@ -41,6 +42,8 @@ | |
| 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.OmMultipartPartInfo; | ||
| import org.apache.hadoop.ozone.om.helpers.OmMultipartPartKey; | ||
| 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; | ||
|
|
@@ -189,6 +192,18 @@ public void testContainerToKeyMappingWithMPUOnlyFileNames() { | |
| assertThat(output).contains("/vol1/obs-bucket/mpuKey/test-upload-id"); | ||
| } | ||
|
|
||
| @Test | ||
| public void testContainerToKeyMappingWithSplitSchemaMPU() { | ||
| int exitCode = execute("--containers", String.valueOf(CONTAINER_ID_4), "--in-progress"); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a bug, but using a distinct
|
||
| assertEquals(0, exitCode); | ||
|
|
||
| String output = outWriter.toString(); | ||
|
|
||
| assertThat(output).contains("\"" + CONTAINER_ID_4 + "\""); | ||
| assertThat(output).contains("\"openKeys\""); | ||
| assertThat(output).contains("/vol1/obs-bucket/splitMpuKey/split-upload-id"); | ||
| } | ||
|
|
||
| @Test | ||
|
|
||
| public void testNonExistentContainer() { | ||
|
|
@@ -292,6 +307,7 @@ private void createTestData() throws Exception { | |
|
|
||
| // Create MPU (multipart upload) for OBS bucket with parts in container 5 | ||
| createMultipartUpload(); | ||
| createSplitSchemaMultipartUpload(); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -339,6 +355,46 @@ private void createMultipartUpload() throws Exception { | |
| omMetadataManager.getMultipartInfoTable().put(mpuKey, mpuInfo); | ||
| } | ||
|
|
||
| /** | ||
| * Helper method to create a split-schema multipart upload with parts in | ||
| * multipartPartsTable. | ||
| */ | ||
| private void createSplitSchemaMultipartUpload() throws Exception { | ||
| String mpuKeyName = "splitMpuKey"; | ||
| String uploadId = "split-upload-id"; | ||
|
|
||
| OmKeyInfo part1Info = new OmKeyInfo.Builder(createOBSKeyInfo( | ||
| mpuKeyName + "/" + uploadId + "/part-1", MPU_PART1_ID + 10, CONTAINER_ID_4)) | ||
| .addMetadata(OzoneConsts.ETAG, "etag-1") | ||
| .build(); | ||
| OmMultipartPartInfo partInfo1 = OmMultipartPartInfo.from( | ||
| mpuKeyName + "/" + uploadId + "/part-1", 1, part1Info); | ||
|
|
||
| OmKeyInfo part2Info = new OmKeyInfo.Builder(createOBSKeyInfo( | ||
| mpuKeyName + "/" + uploadId + "/part-2", MPU_PART2_ID + 10, CONTAINER_ID_4)) | ||
| .addMetadata(OzoneConsts.ETAG, "etag-2") | ||
| .build(); | ||
| OmMultipartPartInfo partInfo2 = OmMultipartPartInfo.from( | ||
| mpuKeyName + "/" + uploadId + "/part-2", 2, part2Info); | ||
|
|
||
| omMetadataManager.getMultipartPartsTable().put(OmMultipartPartKey.of(uploadId, 1), partInfo1); | ||
| omMetadataManager.getMultipartPartsTable().put(OmMultipartPartKey.of(uploadId, 2), partInfo2); | ||
|
|
||
| OmMultipartKeyInfo mpuInfo = new OmMultipartKeyInfo.Builder() | ||
| .setUploadID(uploadId) | ||
| .setCreationTime(System.currentTimeMillis()) | ||
| .setReplicationConfig(StandaloneReplicationConfig.getInstance(HddsProtos.ReplicationFactor.ONE)) | ||
| .setSchemaVersion(OmMultipartKeyInfo.SPLIT_PARTS_TABLE_SCHEMA_VERSION) | ||
| .setObjectID(MPU_KEY_ID + 10) | ||
| .setParentID(0) | ||
| .setUpdateID(1) | ||
| .build(); | ||
|
|
||
| String mpuKey = omMetadataManager.getMultipartKey( | ||
| VOLUME_NAME, OBS_BUCKET_NAME, mpuKeyName, uploadId); | ||
| omMetadataManager.getMultipartInfoTable().put(mpuKey, mpuInfo); | ||
| } | ||
|
|
||
| /** | ||
| * Helper method to create OmKeyInfo with a block in specified container (FSO). | ||
| */ | ||
|
|
@@ -386,6 +442,8 @@ private OmKeyInfo createOBSKeyInfo(String keyName, long objectId, long container | |
| .setDataSize(1024) | ||
| .setObjectID(objectId) | ||
| .setUpdateID(1) | ||
| .setCreationTime(System.currentTimeMillis()) | ||
| .setModificationTime(System.currentTimeMillis()) | ||
| .addOmKeyLocationInfoGroup(locationGroup) | ||
| .build(); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add test for the new code path. Thanks!
TestOmMetadataManager
TestContainerToKeyMapping
TestKeyLifecycleService