Gabriel39 commented on code in PR #66627:
URL: https://github.com/apache/doris/pull/66627#discussion_r3758740537


##########
fe/fe-connector/fe-connector-iceberg/src/main/java/org/apache/doris/connector/iceberg/IcebergNestedColumnEvolution.java:
##########
@@ -87,10 +96,75 @@ public static void addColumn(Table table, 
ConnectorColumnPath path, IcebergColum
 
     /** Drops the nested field at {@code path}; its parent must resolve to a 
struct that contains the leaf. */
     public static void dropColumn(Table table, ConnectorColumnPath path) {
-        ResolvedColumnPath resolvedPath = 
validateNestedStructFieldPath(table.schema(), path, "drop");
-        UpdateSchema updateSchema = table.updateSchema();
-        updateSchema.deleteColumn(resolvedPath.getFullPath());
-        updateSchema.commit();
+        dropColumnWithPartitionSpecFence(table, path, true);
+    }
+
+    static void dropTopLevelColumn(Table table, String columnName) {
+        dropColumnWithPartitionSpecFence(table, 
ConnectorColumnPath.of(columnName), false);
+    }
+
+    private static void dropColumnWithPartitionSpecFence(
+            Table table, ConnectorColumnPath path, boolean nested) {
+        TableOperations operations = ((HasTableOperations) table).operations();
+        TableMetadata initial = operations.refresh();
+        // A commit conflict must rerun resolution and retained-spec 
validation against refreshed metadata.
+        Tasks.foreach(operations)
+                .retry(initial.propertyAsInt(
+                        TableProperties.COMMIT_NUM_RETRIES, 
TableProperties.COMMIT_NUM_RETRIES_DEFAULT))
+                .exponentialBackoff(
+                        
initial.propertyAsInt(TableProperties.COMMIT_MIN_RETRY_WAIT_MS,
+                                
TableProperties.COMMIT_MIN_RETRY_WAIT_MS_DEFAULT),
+                        
initial.propertyAsInt(TableProperties.COMMIT_MAX_RETRY_WAIT_MS,
+                                
TableProperties.COMMIT_MAX_RETRY_WAIT_MS_DEFAULT),
+                        
initial.propertyAsInt(TableProperties.COMMIT_TOTAL_RETRY_TIME_MS,
+                                
TableProperties.COMMIT_TOTAL_RETRY_TIME_MS_DEFAULT),
+                        2.0)
+                .onlyRetryOn(CommitFailedException.class)
+                .run(ops -> commitDropAttempt(ops, table.name(), path, 
nested));
+    }
+
+    private static void commitDropAttempt(
+            TableOperations operations, String tableName, ConnectorColumnPath 
path, boolean nested) {
+        TableMetadata base = operations.refresh();
+        ResolvedColumnPath resolvedPath = nested
+                ? validateNestedStructFieldPath(base.schema(), path, "drop")
+                : resolveColumnPath(base.schema(), path, "drop");
+        validateNotUsedByRetainedPartitionSpec(base, resolvedPath);
+
+        Table attemptTable = new BaseTable(operations.temp(base), tableName);
+        Schema updatedSchema = attemptTable.updateSchema()
+                .deleteColumn(resolvedPath.getFullPath()).apply();
+        int fenceSpecId = 
base.specs().stream().mapToInt(PartitionSpec::specId).max().orElse(-1) + 1;
+        String fenceFieldName = "_doris_schema_drop_fence_" + 
(base.lastAssignedPartitionId() + 1);
+        PartitionSpec fenceSpec = PartitionSpec.builderFor(base.schema())
+                .withSpecId(fenceSpecId)
+                .alwaysNull(resolvedPath.getFullPath(), fenceFieldName)
+                .build();
+        TableMetadata.Builder builder = 
TableMetadata.buildFrom(base).addPartitionSpec(fenceSpec);
+        new 
MetadataUpdate.RemovePartitionSpecs(Set.of(fenceSpecId)).applyTo(builder);

Review Comment:
   Fixed in 6848a1685f5 by removing the client-predicted add/remove spec 
transaction. Iceberg REST cannot assert the spec-ID namespace, so schema DROP 
now fails closed for REST operations before commit; direct catalogs use their 
atomic metadata CAS. This prevents both concurrent-spec deletion and a 
surviving fence.



##########
fe/fe-connector/fe-connector-iceberg/src/main/java/org/apache/doris/connector/iceberg/IcebergNestedColumnEvolution.java:
##########
@@ -87,10 +96,75 @@ public static void addColumn(Table table, 
ConnectorColumnPath path, IcebergColum
 
     /** Drops the nested field at {@code path}; its parent must resolve to a 
struct that contains the leaf. */
     public static void dropColumn(Table table, ConnectorColumnPath path) {
-        ResolvedColumnPath resolvedPath = 
validateNestedStructFieldPath(table.schema(), path, "drop");
-        UpdateSchema updateSchema = table.updateSchema();
-        updateSchema.deleteColumn(resolvedPath.getFullPath());
-        updateSchema.commit();
+        dropColumnWithPartitionSpecFence(table, path, true);
+    }
+
+    static void dropTopLevelColumn(Table table, String columnName) {
+        dropColumnWithPartitionSpecFence(table, 
ConnectorColumnPath.of(columnName), false);
+    }
+
+    private static void dropColumnWithPartitionSpecFence(
+            Table table, ConnectorColumnPath path, boolean nested) {
+        TableOperations operations = ((HasTableOperations) table).operations();
+        TableMetadata initial = operations.refresh();
+        // A commit conflict must rerun resolution and retained-spec 
validation against refreshed metadata.
+        Tasks.foreach(operations)
+                .retry(initial.propertyAsInt(
+                        TableProperties.COMMIT_NUM_RETRIES, 
TableProperties.COMMIT_NUM_RETRIES_DEFAULT))
+                .exponentialBackoff(
+                        
initial.propertyAsInt(TableProperties.COMMIT_MIN_RETRY_WAIT_MS,
+                                
TableProperties.COMMIT_MIN_RETRY_WAIT_MS_DEFAULT),
+                        
initial.propertyAsInt(TableProperties.COMMIT_MAX_RETRY_WAIT_MS,
+                                
TableProperties.COMMIT_MAX_RETRY_WAIT_MS_DEFAULT),
+                        
initial.propertyAsInt(TableProperties.COMMIT_TOTAL_RETRY_TIME_MS,
+                                
TableProperties.COMMIT_TOTAL_RETRY_TIME_MS_DEFAULT),
+                        2.0)
+                .onlyRetryOn(CommitFailedException.class)
+                .run(ops -> commitDropAttempt(ops, table.name(), path, 
nested));
+    }
+
+    private static void commitDropAttempt(
+            TableOperations operations, String tableName, ConnectorColumnPath 
path, boolean nested) {
+        TableMetadata base = operations.refresh();
+        ResolvedColumnPath resolvedPath = nested
+                ? validateNestedStructFieldPath(base.schema(), path, "drop")
+                : resolveColumnPath(base.schema(), path, "drop");
+        validateNotUsedByRetainedPartitionSpec(base, resolvedPath);
+
+        Table attemptTable = new BaseTable(operations.temp(base), tableName);
+        Schema updatedSchema = attemptTable.updateSchema()
+                .deleteColumn(resolvedPath.getFullPath()).apply();
+        int fenceSpecId = 
base.specs().stream().mapToInt(PartitionSpec::specId).max().orElse(-1) + 1;
+        String fenceFieldName = "_doris_schema_drop_fence_" + 
(base.lastAssignedPartitionId() + 1);
+        PartitionSpec fenceSpec = PartitionSpec.builderFor(base.schema())
+                .withSpecId(fenceSpecId)
+                .alwaysNull(resolvedPath.getFullPath(), fenceFieldName)
+                .build();
+        TableMetadata.Builder builder = 
TableMetadata.buildFrom(base).addPartitionSpec(fenceSpec);
+        new 
MetadataUpdate.RemovePartitionSpecs(Set.of(fenceSpecId)).applyTo(builder);
+        builder.setCurrentSchema(updatedSchema, base.lastColumnId());

Review Comment:
   Fixed in 6848a1685f5. Non-REST DROP now goes through Iceberg's standard 
SchemaUpdate.commit(), preserving its schema-linked property and name-mapping 
transformations. Tests cover metrics, Parquet bloom-filter, and Parquet 
column-stats property cleanup.



-- 
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: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to