This is an automated email from the ASF dual-hosted git repository.
priyeshkaratha 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 bc7055ab43d HDDS-16363. Fix split-schema MPU size tracking in Recon
event handlers (#11181)
bc7055ab43d is described below
commit bc7055ab43d459d001eb27030c00390809ad3b65
Author: Priyesh Karatha <[email protected]>
AuthorDate: Fri Sep 18 10:55:57 2026 +0530
HDDS-16363. Fix split-schema MPU size tracking in Recon event handlers
(#11181)
Co-authored-by: Priyesh Karatha <[email protected]>
---
.../recon/tasks/MultipartInfoInsightHandler.java | 118 +++++++++++++++++++--
.../ozone/recon/tasks/OmTableInsightTask.java | 32 +++++-
.../ozone/recon/tasks/TestOmTableInsightTask.java | 116 ++++++++++++++++++--
3 files changed, 249 insertions(+), 17 deletions(-)
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/MultipartInfoInsightHandler.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/MultipartInfoInsightHandler.java
index e4439c5e8d3..6e561e17501 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/MultipartInfoInsightHandler.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/MultipartInfoInsightHandler.java
@@ -17,8 +17,11 @@
package org.apache.hadoop.ozone.recon.tasks;
+import static
org.apache.hadoop.ozone.om.codec.OMDBDefinition.MULTIPART_INFO_TABLE;
+
import java.io.IOException;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.commons.lang3.tuple.Triple;
@@ -52,18 +55,40 @@
* {@code uploadId/partNumber}.</li>
* </ul>
*
- * <p>The event handlers below only access {@code multipartInfoTable} events,
- * whose values embed parts only for the legacy schema. Split-schema part
- * sizes therefore cannot be accounted incrementally from these events (the
- * handler has no DB access and the event carries no part data).
- * So they are reconciled during the periodic reprocess in {@link
#getTableSizeAndCount(String, OMMetadataManager)},
- * which reads the split {@code multipartPartsTable} directly.
+ * <p>Split-schema part sizes are accounted incrementally, one
+ * {@code multipartPartsTable} event at a time (see {@link
#handlePartPutEvent},
+ * {@link #handlePartDeleteEvent}, {@link #handlePartUpdateEvent}), each O(1).
+ * {@code OmMultipartPartInfo} does not carry a replication config, so the
parent
+ * MPU's config is cached here, keyed by uploadId, from the {@code
multipartInfoTable}
+ * PUT/UPDATE events handled below; OM always writes {@code multipartInfoTable}
+ * before the corresponding {@code multipartPartsTable} row in the same batch,
so the
+ * cache entry is available by the time a part event for that upload is
processed.
+ * The cache is bounded (LRU) rather than explicitly evicted per upload, since
a
+ * part-delete event can follow an info-table delete for the same upload
within the
+ * same batch and still needs the cached config.
*/
public class MultipartInfoInsightHandler implements OmTableHandler {
private static final Logger LOG =
LoggerFactory.getLogger(MultipartInfoInsightHandler.class);
+ private static final int MAX_CACHED_SPLIT_SCHEMA_UPLOADS = 10_000;
+
+ /**
+ * uploadId -> parent replication config, for split-schema MPUs, used to
compute
+ * the replicated size of {@code multipartPartsTable} events in O(1). Bounded
+ * (LRU, access-order) so long-lived Recon processes do not grow this
unbounded;
+ * a cache miss (e.g. under eviction pressure) simply skips that part's size
+ * update, which is reconciled by the next {@link #getTableSizeAndCount}
reprocess.
+ */
+ private final Map<String, ReplicationConfig>
splitSchemaUploadReplicationConfig =
+ new LinkedHashMap<String, ReplicationConfig>(16, 0.75f, true) {
+ @Override
+ protected boolean removeEldestEntry(Map.Entry<String,
ReplicationConfig> eldest) {
+ return size() > MAX_CACHED_SPLIT_SCHEMA_UPLOADS;
+ }
+ };
+
/**
* Consumes the (unreplicated, replicated) size of a single multipart part.
*/
@@ -85,6 +110,7 @@ public void handlePutEvent(OMDBUpdateEvent<String, Object>
event, String tableNa
objectCountMap.computeIfPresent(getTableCountKeyFromTable(tableName),
(k, count) -> count + 1L);
applyLegacyPartSizes(multipartKeyInfo, tableName, unReplicatedSizeMap,
replicatedSizeMap, true);
+ cacheSplitSchemaReplicationConfig(multipartKeyInfo);
} else {
LOG.warn("Put event does not have the Multipart Key Info for {}.",
event.getKey());
}
@@ -129,11 +155,56 @@ public void handleUpdateEvent(OMDBUpdateEvent<String,
Object> event, String tabl
OmMultipartKeyInfo newMultipartKeyInfo = (OmMultipartKeyInfo)
event.getValue();
applyLegacyPartSizes(oldMultipartKeyInfo, tableName,
unReplicatedSizeMap, replicatedSizeMap, false);
applyLegacyPartSizes(newMultipartKeyInfo, tableName,
unReplicatedSizeMap, replicatedSizeMap, true);
+ // A split-schema MPU's multipartInfoTable row is rewritten
(PUT->UPDATE) on
+ // every part commit, so refresh/populate the cache here too.
+ cacheSplitSchemaReplicationConfig(newMultipartKeyInfo);
} else {
LOG.warn("Update event does not have the Multipart Key Info for {}.",
event.getKey());
}
}
+ /**
+ * Invoked for a PUT (part committed) event on the {@code
multipartPartsTable}.
+ * Adds this part's size to the {@code multipartInfoTable} totals in O(1).
+ */
+ public void handlePartPutEvent(OMDBUpdateEvent<OmMultipartPartKey,
OmMultipartPartInfo> event,
+ Map<String, Long> unReplicatedSizeMap, Map<String, Long>
replicatedSizeMap) {
+ if (event.getValue() != null) {
+ applyPartSize(event.getKey(), event.getValue(), unReplicatedSizeMap,
replicatedSizeMap, true);
+ } else {
+ LOG.warn("Put event does not have the Multipart Part Info for {}.",
event.getKey());
+ }
+ }
+
+ /**
+ * Invoked for a DELETE (part removed on abort/complete) event on the
+ * {@code multipartPartsTable}. Subtracts this part's size from the
+ * {@code multipartInfoTable} totals in O(1).
+ */
+ public void handlePartDeleteEvent(OMDBUpdateEvent<OmMultipartPartKey,
OmMultipartPartInfo> event,
+ Map<String, Long> unReplicatedSizeMap, Map<String, Long>
replicatedSizeMap) {
+ if (event.getValue() != null) {
+ applyPartSize(event.getKey(), event.getValue(), unReplicatedSizeMap,
replicatedSizeMap, false);
+ } else {
+ LOG.warn("Delete event does not have the Multipart Part Info for {}.",
event.getKey());
+ }
+ }
+
+ /**
+ * Invoked for an UPDATE (part re-uploaded with the same part number) event
on
+ * the {@code multipartPartsTable}. Subtracts the old size and adds the new
+ * size from/to the {@code multipartInfoTable} totals in O(1).
+ */
+ public void handlePartUpdateEvent(OMDBUpdateEvent<OmMultipartPartKey,
OmMultipartPartInfo> event,
+ Map<String, Long> unReplicatedSizeMap, Map<String, Long>
replicatedSizeMap) {
+ if (event.getValue() == null || event.getOldValue() == null) {
+ LOG.warn("Update event does not have the old/new Multipart Part Info for
{}.", event.getKey());
+ return;
+ }
+ applyPartSize(event.getKey(), event.getOldValue(), unReplicatedSizeMap,
replicatedSizeMap, false);
+ applyPartSize(event.getKey(), event.getValue(), unReplicatedSizeMap,
replicatedSizeMap, true);
+ }
+
/**
* This method is called by the reprocess method. It calculates the record
* counts for the multipart info table. Additionally, it computes the sizes
@@ -215,7 +286,7 @@ public Triple<Long, Long, Long> getTableSizeAndCount(String
tableName,
/**
* Adds (or subtracts) the sizes of a legacy MPU's embedded parts to the size
* maps. Split-schema MPUs carry no embedded parts and are ignored here
(their
- * sizes are reconciled during reprocess; see class Javadoc).
+ * sizes are accounted per-part via {@link #handlePartPutEvent} and friends).
*
* @param add {@code true} to add the part sizes (PUT / new value in UPDATE),
* {@code false} to subtract them (DELETE / old value in UPDATE).
@@ -228,6 +299,39 @@ private void applyLegacyPartSizes(OmMultipartKeyInfo
multipartKeyInfo, String ta
});
}
+ /**
+ * Caches the replication config of a split-schema MPU, keyed by uploadId,
for use
+ * by {@link #applyPartSize}. No-op for legacy-schema MPUs.
+ */
+ private void cacheSplitSchemaReplicationConfig(OmMultipartKeyInfo
multipartKeyInfo) {
+ if (isLegacySchema(multipartKeyInfo)) {
+ return;
+ }
+ splitSchemaUploadReplicationConfig.put(multipartKeyInfo.getUploadID(),
multipartKeyInfo.getReplicationConfig());
+ }
+
+ /**
+ * Adds (or subtracts) a single split-schema part's size to/from the
+ * {@code multipartInfoTable} size maps, using the parent MPU's replication
+ * config cached by {@link #cacheSplitSchemaReplicationConfig}. If the
parent's
+ * config is not cached (e.g. evicted under memory pressure), the update is
+ * skipped with a warning; it is reconciled by the next reprocess.
+ */
+ private void applyPartSize(OmMultipartPartKey partKey, OmMultipartPartInfo
partInfo,
+ Map<String, Long> unReplicatedSizeMap, Map<String, Long>
replicatedSizeMap, boolean add) {
+ ReplicationConfig replicationConfig =
splitSchemaUploadReplicationConfig.get(partKey.getUploadId());
+ if (replicationConfig == null) {
+ LOG.warn("No cached replication config for upload {}; skipping part size
update.", partKey.getUploadId());
+ return;
+ }
+ long partDataSize = partInfo.getDataSize();
+ long partReplicatedSize = QuotaUtil.getReplicatedSize(partDataSize,
replicationConfig);
+ updateSize(unReplicatedSizeMap,
getUnReplicatedSizeKeyFromTable(MULTIPART_INFO_TABLE), partDataSize, add,
+ "unreplicated");
+ updateSize(replicatedSizeMap,
getReplicatedSizeKeyFromTable(MULTIPART_INFO_TABLE), partReplicatedSize, add,
+ "replicated");
+ }
+
/**
* Invokes {@code consumer} with the (unreplicated, replicated) size of each
* embedded part of a legacy MPU. Does nothing for split-schema MPUs.
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/OmTableInsightTask.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/OmTableInsightTask.java
index a4853dbf31d..2e6e0e51548 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/OmTableInsightTask.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/OmTableInsightTask.java
@@ -19,6 +19,7 @@
import static org.apache.hadoop.ozone.om.codec.OMDBDefinition.DELETED_TABLE;
import static
org.apache.hadoop.ozone.om.codec.OMDBDefinition.MULTIPART_INFO_TABLE;
+import static
org.apache.hadoop.ozone.om.codec.OMDBDefinition.MULTIPART_PARTS_TABLE;
import static org.apache.hadoop.ozone.om.codec.OMDBDefinition.OPEN_FILE_TABLE;
import static org.apache.hadoop.ozone.om.codec.OMDBDefinition.OPEN_KEY_TABLE;
@@ -42,6 +43,8 @@
import org.apache.hadoop.hdds.utils.db.TableIterator;
import org.apache.hadoop.hdds.utils.db.cache.TableCache;
import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.helpers.OmMultipartPartInfo;
+import org.apache.hadoop.ozone.om.helpers.OmMultipartPartKey;
import org.apache.hadoop.ozone.recon.ReconServerConfigKeys;
import org.apache.hadoop.ozone.recon.recovery.ReconOMMetadataManager;
import org.apache.hadoop.ozone.recon.spi.ReconGlobalStatsManager;
@@ -61,6 +64,7 @@ public class OmTableInsightTask implements ReconOmTask {
private ReconGlobalStatsManager reconGlobalStatsManager;
private ReconOMMetadataManager reconOMMetadataManager;
private Map<String, OmTableHandler> tableHandlers;
+ private MultipartInfoInsightHandler multipartInfoInsightHandler;
private Collection<String> tables;
private Map<String, Long> objectCountMap;
private Map<String, Long> unReplicatedSizeMap;
@@ -79,7 +83,8 @@ public OmTableInsightTask(ReconGlobalStatsManager
reconGlobalStatsManager,
tableHandlers.put(OPEN_KEY_TABLE, new OpenKeysInsightHandler());
tableHandlers.put(OPEN_FILE_TABLE, new OpenKeysInsightHandler());
tableHandlers.put(DELETED_TABLE, new DeletedKeysInsightHandler());
- tableHandlers.put(MULTIPART_INFO_TABLE, new MultipartInfoInsightHandler());
+ multipartInfoInsightHandler = new MultipartInfoInsightHandler();
+ tableHandlers.put(MULTIPART_INFO_TABLE, multipartInfoInsightHandler);
this.maxKeysInMemory =
reconOMMetadataManager.getOzoneConfiguration().getInt(
ReconServerConfigKeys.OZONE_RECON_TASK_REPROCESS_MAX_KEYS_IN_MEMORY,
ReconServerConfigKeys.OZONE_RECON_TASK_REPROCESS_MAX_KEYS_IN_MEMORY_DEFAULT);
@@ -315,6 +320,10 @@ private void handlePutEvent(OMDBUpdateEvent<String,
Object> event,
} else {
String countKey = getTableCountKeyFromTable(tableName);
objectCountMap.computeIfPresent(countKey, (k, count) -> count + 1L);
+ if (tableName.equals(MULTIPART_PARTS_TABLE)) {
+
multipartInfoInsightHandler.handlePartPutEvent(castToPartEvent(event),
+ unReplicatedSizeMap, replicatedSizeMap);
+ }
}
}
}
@@ -329,6 +338,10 @@ private void handleDeleteEvent(OMDBUpdateEvent<String,
Object> event,
} else {
objectCountMap.computeIfPresent(getTableCountKeyFromTable(tableName),
(k, count) -> count > 0 ? count - 1L : 0L);
+ if (tableName.equals(MULTIPART_PARTS_TABLE)) {
+
multipartInfoInsightHandler.handlePartDeleteEvent(castToPartEvent(event),
+ unReplicatedSizeMap, replicatedSizeMap);
+ }
}
}
}
@@ -342,10 +355,27 @@ private void handleUpdateEvent(OMDBUpdateEvent<String,
Object> event,
// Handle update for only size related tables
tableHandler.handleUpdateEvent(event, tableName, objectCountMap,
unReplicatedSizeMap, replicatedSizeMap);
+ } else if (tableName.equals(MULTIPART_PARTS_TABLE)) {
+
multipartInfoInsightHandler.handlePartUpdateEvent(castToPartEvent(event),
+ unReplicatedSizeMap, replicatedSizeMap);
}
}
}
+ /**
+ * The multipartPartsTable is not registered in {@link #tableHandlers}, so
its events fall
+ * through to the generic {@code tableHandler == null} branch above for
object counting, and are
+ * additionally routed here to update multipartInfoTable's sizes. Its
keys/values are genuinely
+ * {@link OmMultipartPartKey}/{@link OmMultipartPartInfo} at runtime (see
+ * {@code OMDBUpdatesHandler}); erasure makes this cast safe despite the
static
+ * {@code OMDBUpdateEvent<String, Object>} type of {@code event}.
+ */
+ @SuppressWarnings("unchecked")
+ private static OMDBUpdateEvent<OmMultipartPartKey, OmMultipartPartInfo>
castToPartEvent(
+ OMDBUpdateEvent<String, Object> event) {
+ return (OMDBUpdateEvent<OmMultipartPartKey, OmMultipartPartInfo>)
(OMDBUpdateEvent<?, ?>) event;
+ }
+
/**
* Write the updated count and size information to the database.
*
diff --git
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/tasks/TestOmTableInsightTask.java
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/tasks/TestOmTableInsightTask.java
index ef44075d80a..9b5f3b0c1f9 100644
---
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/tasks/TestOmTableInsightTask.java
+++
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/tasks/TestOmTableInsightTask.java
@@ -22,6 +22,7 @@
import static org.apache.hadoop.ozone.om.codec.OMDBDefinition.DELETED_TABLE;
import static org.apache.hadoop.ozone.om.codec.OMDBDefinition.KEY_TABLE;
import static
org.apache.hadoop.ozone.om.codec.OMDBDefinition.MULTIPART_INFO_TABLE;
+import static
org.apache.hadoop.ozone.om.codec.OMDBDefinition.MULTIPART_PARTS_TABLE;
import static org.apache.hadoop.ozone.om.codec.OMDBDefinition.OPEN_FILE_TABLE;
import static org.apache.hadoop.ozone.om.codec.OMDBDefinition.OPEN_KEY_TABLE;
import static org.apache.hadoop.ozone.om.codec.OMDBDefinition.VOLUME_TABLE;
@@ -492,8 +493,9 @@ public void testProcessForCount() {
// Creating events for each table except the deleted table
for (String tableName : omTableInsightTask.getTaskTables()) {
- if (tableName.equals(DELETED_TABLE) ||
tableName.equals(MULTIPART_INFO_TABLE)) {
- continue; // Skipping deleted and multipartInfo tables as they have
separate tests
+ if (tableName.equals(DELETED_TABLE) ||
tableName.equals(MULTIPART_INFO_TABLE)
+ || tableName.equals(MULTIPART_PARTS_TABLE)) {
+ continue; // Skipping deleted, multipartInfo and multipartParts tables
as they have separate tests
}
// Adding 5 PUT events per table
@@ -520,7 +522,8 @@ public void testProcessForCount() {
// Verifying the count in each table
for (String tableName : omTableInsightTask.getTaskTables()) {
- if (tableName.equals(DELETED_TABLE) ||
tableName.equals(MULTIPART_INFO_TABLE)) {
+ if (tableName.equals(DELETED_TABLE) ||
tableName.equals(MULTIPART_INFO_TABLE)
+ || tableName.equals(MULTIPART_PARTS_TABLE)) {
continue;
}
assertEquals(4L, getCountForTable(
@@ -530,7 +533,8 @@ public void testProcessForCount() {
List<OMDBUpdateEvent> additionalEvents = new ArrayList<>();
// Simulating new PUT and DELETE events
for (String tableName : omTableInsightTask.getTaskTables()) {
- if (tableName.equals(DELETED_TABLE) ||
tableName.equals(MULTIPART_INFO_TABLE)) {
+ if (tableName.equals(DELETED_TABLE) ||
tableName.equals(MULTIPART_INFO_TABLE)
+ || tableName.equals(MULTIPART_PARTS_TABLE)) {
continue;
}
// Adding 1 new PUT event
@@ -548,7 +552,8 @@ public void testProcessForCount() {
omTableInsightTask.process(additionalBatch, Collections.emptyMap());
// Verifying the final count in each table
for (String tableName : omTableInsightTask.getTaskTables()) {
- if (tableName.equals(DELETED_TABLE) ||
tableName.equals(MULTIPART_INFO_TABLE)) {
+ if (tableName.equals(DELETED_TABLE) ||
tableName.equals(MULTIPART_INFO_TABLE)
+ || tableName.equals(MULTIPART_PARTS_TABLE)) {
continue;
}
// 5 items expected after processing the additional events.
@@ -750,6 +755,89 @@ public void testProcessForMultipartInfoTable() {
assertEquals(2700L, getReplicatedSizeForTable(MULTIPART_INFO_TABLE));
}
+ /**
+ * Validates the event-driven (O(1) per part event) accounting of
split-schema MPU sizes:
+ * multipartInfoTable PUT caches the parent's replication config,
multipartPartsTable PUT/UPDATE/DELETE
+ * events adjust the multipartInfoTable size totals incrementally, and a
part re-upload (UPDATE, same
+ * part number) nets the old size out and the new size in rather than
cancelling to zero.
+ */
+ @Test
+ public void testProcessForSplitSchemaMPU() throws Exception {
+ String uploadID = UUID.randomUUID().toString();
+ String volumeName = UUID.randomUUID().toString();
+ String bucketName = UUID.randomUUID().toString();
+ String keyName = UUID.randomUUID().toString();
+
+ OmMultipartKeyInfo splitMpu = new OmMultipartKeyInfo.Builder()
+ .setObjectID(1L)
+ .setUploadID(uploadID)
+ .setCreationTime(Time.now())
+ .setReplicationConfig(RatisReplicationConfig.getInstance(
+ HddsProtos.ReplicationFactor.THREE))
+ .setSchemaVersion(OmMultipartKeyInfo.SPLIT_PARTS_TABLE_SCHEMA_VERSION)
+ .build();
+ String multipartKey = reconOMMetadataManager.getMultipartKey(volumeName,
bucketName, keyName, uploadID);
+
+ // MPU initiation: caches the parent's replication config for the part
events below.
+ ArrayList<OMDBUpdateEvent> initEvents = new ArrayList<>();
+ initEvents.add(getOMUpdateEvent(multipartKey, splitMpu,
MULTIPART_INFO_TABLE, PUT, null));
+ omTableInsightTask.process(new OMUpdateEventBatch(initEvents, 0L),
Collections.emptyMap());
+
+ assertEquals(1L, getCountForTable(MULTIPART_INFO_TABLE));
+ assertEquals(0L, getUnReplicatedSizeForTable(MULTIPART_INFO_TABLE));
+ assertEquals(0L, getReplicatedSizeForTable(MULTIPART_INFO_TABLE));
+
+ // 3 parts uploaded (multipartPartsTable PUT), 100 bytes each.
+ OmMultipartPartInfo part1 = buildSplitSchemaPartInfo(volumeName,
bucketName, keyName, uploadID, 1, 100L);
+ OmMultipartPartInfo part2 = buildSplitSchemaPartInfo(volumeName,
bucketName, keyName, uploadID, 2, 100L);
+ OmMultipartPartInfo part3 = buildSplitSchemaPartInfo(volumeName,
bucketName, keyName, uploadID, 3, 100L);
+ ArrayList<OMDBUpdateEvent> partPutEvents = new ArrayList<>();
+ partPutEvents.add(getOMUpdateEvent(OmMultipartPartKey.of(uploadID, 1),
part1, MULTIPART_PARTS_TABLE, PUT, null));
+ partPutEvents.add(getOMUpdateEvent(OmMultipartPartKey.of(uploadID, 2),
part2, MULTIPART_PARTS_TABLE, PUT, null));
+ partPutEvents.add(getOMUpdateEvent(OmMultipartPartKey.of(uploadID, 3),
part3, MULTIPART_PARTS_TABLE, PUT, null));
+ omTableInsightTask.process(new OMUpdateEventBatch(partPutEvents, 0L),
Collections.emptyMap());
+
+ // 3 parts * 100 bytes = 300 bytes unreplicated; RATIS THREE -> 900 bytes
replicated.
+ assertEquals(1L, getCountForTable(MULTIPART_INFO_TABLE));
+ assertEquals(300L, getUnReplicatedSizeForTable(MULTIPART_INFO_TABLE));
+ assertEquals(900L, getReplicatedSizeForTable(MULTIPART_INFO_TABLE));
+
+ // Part 1 re-uploaded (multipartPartsTable UPDATE) with the same part
number, 100 -> 200 bytes.
+ OmMultipartPartInfo newPart1 = buildSplitSchemaPartInfo(volumeName,
bucketName, keyName, uploadID, 1, 200L);
+ ArrayList<OMDBUpdateEvent> partUpdateEvents = new ArrayList<>();
+ partUpdateEvents.add(getOMUpdateEvent(OmMultipartPartKey.of(uploadID, 1),
newPart1, MULTIPART_PARTS_TABLE,
+ UPDATE, part1));
+ omTableInsightTask.process(new OMUpdateEventBatch(partUpdateEvents, 0L),
Collections.emptyMap());
+
+ // 200 + 100 + 100 = 400 bytes unreplicated; RATIS THREE -> 1200 bytes
replicated.
+ assertEquals(400L, getUnReplicatedSizeForTable(MULTIPART_INFO_TABLE));
+ assertEquals(1200L, getReplicatedSizeForTable(MULTIPART_INFO_TABLE));
+
+ // Part 3 removed (multipartPartsTable DELETE).
+ ArrayList<OMDBUpdateEvent> partDeleteEvents = new ArrayList<>();
+ partDeleteEvents.add(getOMUpdateEvent(OmMultipartPartKey.of(uploadID, 3),
part3, MULTIPART_PARTS_TABLE,
+ DELETE, null));
+ omTableInsightTask.process(new OMUpdateEventBatch(partDeleteEvents, 0L),
Collections.emptyMap());
+
+ // 200 + 100 = 300 bytes unreplicated; RATIS THREE -> 900 bytes replicated.
+ assertEquals(300L, getUnReplicatedSizeForTable(MULTIPART_INFO_TABLE));
+ assertEquals(900L, getReplicatedSizeForTable(MULTIPART_INFO_TABLE));
+
+ // MPU aborted: remaining parts removed, followed by the
multipartInfoTable DELETE, matching OM's
+ // write-ordering guarantee that multipartInfoTable writes/deletes precede
multipartPartsTable ones.
+ ArrayList<OMDBUpdateEvent> finalEvents = new ArrayList<>();
+ finalEvents.add(getOMUpdateEvent(OmMultipartPartKey.of(uploadID, 1),
newPart1, MULTIPART_PARTS_TABLE,
+ DELETE, null));
+ finalEvents.add(getOMUpdateEvent(OmMultipartPartKey.of(uploadID, 2),
part2, MULTIPART_PARTS_TABLE,
+ DELETE, null));
+ finalEvents.add(getOMUpdateEvent(multipartKey, splitMpu,
MULTIPART_INFO_TABLE, DELETE, null));
+ omTableInsightTask.process(new OMUpdateEventBatch(finalEvents, 0L),
Collections.emptyMap());
+
+ assertEquals(0L, getCountForTable(MULTIPART_INFO_TABLE));
+ assertEquals(0L, getUnReplicatedSizeForTable(MULTIPART_INFO_TABLE));
+ assertEquals(0L, getReplicatedSizeForTable(MULTIPART_INFO_TABLE));
+ }
+
@Test
public void testReprocessForMultipartInfoTable() throws Exception {
String uploadID = UUID.randomUUID().toString();
@@ -890,6 +978,18 @@ public void
testReprocessForMultipartInfoTableMixedSchema() throws Exception {
*/
private void putSplitSchemaPart(String uploadID, String volumeName, String
bucketName,
String keyName, int partNumber, long dataSize) throws IOException {
+ OmMultipartPartInfo partInfo =
+ buildSplitSchemaPartInfo(volumeName, bucketName, keyName, uploadID,
partNumber, dataSize);
+ reconOMMetadataManager.getMultipartPartsTable().put(
+ OmMultipartPartKey.of(uploadID, partNumber), partInfo);
+ }
+
+ /**
+ * Builds a single split-schema part (an {@link OmMultipartPartInfo}),
without writing it to the
+ * multipartPartsTable. An ETag is set because it is mandatory for
split-schema parts.
+ */
+ private OmMultipartPartInfo buildSplitSchemaPartInfo(String volumeName,
String bucketName,
+ String keyName, String uploadID, int partNumber, long dataSize) {
OmKeyInfo partOmKeyInfo = new OmKeyInfo.Builder()
.setVolumeName(volumeName)
.setBucketName(bucketName)
@@ -907,9 +1007,7 @@ private void putSplitSchemaPart(String uploadID, String
volumeName, String bucke
.addMetadata(OzoneConsts.ETAG, "etag-" + partNumber)
.build();
String partName = reconOMMetadataManager.getMultipartKey(volumeName,
bucketName, keyName, uploadID);
- OmMultipartPartInfo partInfo = OmMultipartPartInfo.from(partName,
partNumber, partOmKeyInfo);
- reconOMMetadataManager.getMultipartPartsTable().put(
- OmMultipartPartKey.of(uploadID, partNumber), partInfo);
+ return OmMultipartPartInfo.from(partName, partNumber, partOmKeyInfo);
}
public PartKeyInfo createPartKeyInfo(String volumeName, String bucketName,
@@ -933,7 +1031,7 @@ public PartKeyInfo createPartKeyInfo(String volumeName,
String bucketName,
}
private OMDBUpdateEvent getOMUpdateEvent(
- String name, Object value,
+ Object name, Object value,
String table,
OMDBUpdateEvent.OMDBUpdateAction action,
Object oldValue) {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]