dimas-b commented on code in PR #1285: URL: https://github.com/apache/polaris/pull/1285#discussion_r2096312445
########## service/common/src/main/java/org/apache/polaris/service/catalog/iceberg/CatalogHandlerUtils.java: ########## @@ -433,39 +446,174 @@ protected TableMetadata commit(TableOperations ops, UpdateTableRequest request) 2.0 /* exponential */) .onlyRetryOn(CommitFailedException.class) .run( - taskOps -> { + (taskOps) -> { TableMetadata base = isRetry.get() ? taskOps.refresh() : taskOps.current(); - isRetry.set(true); - // validate requirements + TableMetadata.Builder metadataBuilder = TableMetadata.buildFrom(base); + TableMetadata newBase = base; try { - request.requirements().forEach(requirement -> requirement.validate(base)); + request.requirements().forEach((requirement) -> requirement.validate(base)); } catch (CommitFailedException e) { - // wrap and rethrow outside of tasks to avoid unnecessary retry - throw new ValidationFailureException(e); + if (!isRollbackCompactionEnabled()) { + throw new ValidationFailureException(e); + } + UpdateRequirement.AssertRefSnapshotID assertRefSnapshotId = + findAssertRefSnapshotID(request); + MetadataUpdate.SetSnapshotRef setSnapshotRef = findSetSnapshotRefUpdate(request); + + if (assertRefSnapshotId == null || setSnapshotRef == null) { + // This implies the request was not trying to add a snapshot. + throw new ValidationFailureException(e); + } + + // snapshot-id the client expects the table current_snapshot_id + long expectedCurrentSnapshotId = assertRefSnapshotId.snapshotId(); + // table current_snapshot_id. + long currentSnapshotId = base.currentSnapshot().snapshotId(); + List<MetadataUpdate> metadataUpdates = + generateUpdatesToRemoveNoopSnapshot( + base, + currentSnapshotId, + expectedCurrentSnapshotId, + setSnapshotRef.name()); + + if (metadataUpdates == null || metadataUpdates.isEmpty()) { + // Nothing can be done as this implies that there were not all + // No-op snapshots (REPLACE) between expectedCurrentSnapshotId and + // currentSnapshotId. hence re-throw the exception caught. + throw new ValidationFailureException(e); + } + + // Set back the ref we wanted to set, back to the snapshot-id + // the client is expecting the table to be at. + metadataBuilder.setBranchSnapshot( + expectedCurrentSnapshotId, setSnapshotRef.name()); + + // apply the remove snapshots update in the current metadata. + // NOTE: we need to setRef to expectedCurrentSnapshotId first and then apply + // remove, as otherwise the remove will drop the reference. + // NOTE: we can skip removing the now orphan base. Its not a hard requirement. + // just something good to do, and not leave for Remove Orphans. + metadataUpdates.forEach((update -> update.applyTo(metadataBuilder))); + // Ref rolled back update correctly to snapshot to be committed parent now. + newBase = metadataBuilder.build(); + // move the lastSequenceNumber back, to apply snapshot properly on the + // current-metadata Seq number are considered increasing monotonically + // snapshot over snapshot, the client generates the manifest list and hence + // the sequence number can't be changed for a snapshot the only possible option + // then is to change the sequenceNumber tracked by metadata.json + Class<?> clazz = newBase.getClass(); + try { + Field field = clazz.getDeclaredField("lastSequenceNumber"); + field.setAccessible(true); + // this should point to the sequence number that current tip of the + // branch belongs to, as the new commit will be applied on top of this. + field.set(newBase, newBase.currentSnapshot().sequenceNumber()); Review Comment: Why not use the `Builder`, transfer snapshots manually, and let the builder figure out the sequence number. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: issues-unsubscr...@polaris.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org