morningman commented on code in PR #68902:
URL: https://github.com/apache/doris/pull/68902#discussion_r4241474846


##########
fe/fe-connector/fe-connector-iceberg/src/main/java/org/apache/doris/connector/iceberg/IcebergProcedureOps.java:
##########
@@ -249,6 +254,35 @@ private List<ConnectorRewriteGroup> 
planInAuthScopeUntracked(IcebergTableHandle
         return 
groups.stream().map(IcebergProcedureOps::toConnectorRewriteGroup).collect(Collectors.toList());
     }
 
+    /**
+     * Routes the procedure table's {@code io()} through the plugin-side 
Kerberos {@code doAs} — the procedure-path
+     * mirror of {@code IcebergScanPlanProvider.wrapTableForScan} and
+     * {@code IcebergConnectorTransaction.openTransaction}. The {@code 
executeAuthenticated} scope around the body
+     * covers only the calling thread, while iceberg reads and writes metadata 
files on its shared worker pool:
+     * {@code expire_snapshots} reads the expired snapshots' manifest lists 
there after committing (CI:
+     * test_iceberg_hadoop_catalog_kerberos failed "Failed to open input 
stream for file: .../snap-*.avro"),
+     * {@code cherrypick_snapshot} writes the picked files' manifest there, 
and rewrite planning reads the manifests
+     * of a multi-manifest table there. The wrapped FileIO keeps prefix 
listing for {@code remove_orphan_files}
+     * ({@link IcebergAuthenticatedFileIO#withPrefixOperations}).
+     *
+     * <p>Non-Kerberos catalogs ({@code getPluginAuthenticator() == null}) and 
offline tests (plain context /
+     * non-{@link BaseTable} fakes) get the table unchanged. Package-private 
for unit testing.
+     */
+    Table wrapTableForProcedure(Table table) {
+        if (!(context instanceof TcclPinningConnectorContext) || !(table 
instanceof BaseTable)) {
+            return table;
+        }
+        HadoopAuthenticator auth = ((TcclPinningConnectorContext) 
context).getPluginAuthenticator();
+        if (auth == null) {
+            return table;
+        }
+        BaseTable baseTable = (BaseTable) table;
+        TableOperations rawOps = baseTable.operations();
+        return new BaseTable(new IcebergAuthenticatedTableOperations(rawOps,

Review Comment:
   Agreed. The wrap rebuilt a `RESTTable` as a plain `BaseTable`, so with 
server-side scan planning the rewrite planner read the manifests locally 
instead of asking the server.
   
   Fixed in a0d5399d4d6. Rewrite planning now leaves a server-planned table 
unwrapped, so its plan request goes to the REST server as it did before this 
PR, and a zero-group plan returns its zero result without local manifest I/O. 
The check is `IcebergScanPlanning.requiresServerSideScanPlanning`, the same 
condition the scan path rejects on, now shared by both. Procedure execution 
keeps the Kerberos `FileIO`: none of the single-call actions plans a scan.
   
   `IcebergRestScanPlanningTest#kerberosRewritePlanningAsksTheServerForTasks` 
plans `rewrite_data_files` against a real `RESTTable` behind a local HTTP 
server, under a Kerberos context: the plan request reaches the server and no 
local manifest is read. With the previous wrap the test fails on `Unexpected 
local metadata read: .../snap-*.avro`.
   



##########
regression-test/suites/external_table_p0/kerberos/test_iceberg_hadoop_catalog_kerberos.groovy:
##########
@@ -97,6 +97,72 @@ suite("test_iceberg_hadoop_catalog_kerberos", "p0,external") 
{
           'partition_val2'
         );
     """
+    def snapshotsAfterFirstInsert = sql """
+        select snapshot_id from ${test_tbl_name}\$snapshots order by 
committed_at
+    """
+    assert snapshotsAfterFirstInsert.size() == 1
+    String firstSnapshotId = String.valueOf(snapshotsAfterFirstInsert[0][0])
+
+    sql """
+        insert into ${test_tbl_name} values (
+          '2024-05-27 12:34:56',
+          false,
+          456,
+          4567890123456,
+          45.67,
+          89.012,
+          45678.9012,
+          'another example',
+          '2024-05-27',
+          '2024-05-27 14:00:00',
+          'partition_val1',
+          'partition_val2'
+        );
+    """
+    def dataBeforeRollback = sql """select count(1) from ${test_tbl_name}"""
+    assert dataBeforeRollback.get(0).get(0) == 2
+
+    // Rollback must commit metadata with the same Kerberos identity used to 
acquire the table.
+    sql """
+        alter table ${catalog_name}.${database_name}.${test_tbl_name}
+        execute rollback_to_snapshot("snapshot_id" = "${firstSnapshotId}")
+    """
+    def dataAfterRollback = sql """select count(1) from ${test_tbl_name}"""
+    assert dataAfterRollback.get(0).get(0) == 1
+
+    sql """
+        insert into ${test_tbl_name} values (
+          '2024-05-27 12:34:56',
+          false,
+          456,
+          4567890123456,
+          45.67,
+          89.012,
+          45678.9012,
+          'another example',
+          '2024-05-27',
+          '2024-05-27 14:00:00',
+          'partition_val1',
+          'partition_val2'
+        );
+    """
+
+    def snapshotsBeforeExpire = sql """
+        select snapshot_id from ${test_tbl_name}\$snapshots order by 
committed_at
+    """
+    assert snapshotsBeforeExpire.size() == 3
+
+    // The action must reuse the catalog's Kerberos identity while committing 
new metadata.
+    sql """
+        alter table ${catalog_name}.${database_name}.${test_tbl_name}
+        execute expire_snapshots("retain_last" = "1")
+    """
+
+    def snapshotsAfterExpire = sql """
+        select snapshot_id from ${test_tbl_name}\$snapshots order by 
committed_at
+    """
+    assert snapshotsAfterExpire.size() == 1
+
     def dataResult = sql """select count(1) from ${test_tbl_name} """
-    assert dataResult.get(0).get(0) == 1
+    assert dataResult.get(0).get(0) == 2

Review Comment:
   Agreed that `COUNT(1)` alone can be answered from the manifests. Addressed 
in a0d5399d4d6: after `expire_snapshots` the suite now reads `col2, col7` 
ordered by `col2` and checks that exactly the two retained rows come back (the 
first insert and the insert made after the rollback). That opens both retained 
ORC files, so a cleanup that deleted a live file, or kept the wrong one, fails 
the case.
   
   I kept the check as an inline assertion rather than `qt_`. This suite has no 
`.out` file on master or on branch-4.x, it runs only in the External pipeline's 
Kerberos docker environment, and a runner-generated `.out` cannot be produced 
outside that environment. The expected rows are fixed by the suite's own 
inserts.
   



-- 
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