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


##########
fe/fe-core/src/main/java/org/apache/doris/datasource/paimon/source/PaimonScanNode.java:
##########
@@ -190,6 +202,182 @@ protected void doInitialize() throws UserException {
         }
     }
 
+    /**
+     * Build the Paimon table object that is serialized to the BE.
+     *
+     * <p>Every table loaded from a metastore-backed Paimon catalog (HMS / 
DLF) carries a Paimon
+     * {@code HiveCatalogLoader} in its {@link 
org.apache.paimon.table.CatalogEnvironment}. The BE
+     * only reads — via FE-resolved splits and the object store — and never 
needs the catalog, yet
+     * deserializing that loader forces the whole Hive metastore stack onto 
the BE classpath:
+     * {@code HiveConf}, the metastore API, and, when a system table resolves 
its latest snapshot,
+     * even the metastore client (DLF's {@code ProxyMetaStoreClient} and its 
REST stack). So we
+     * serialize a catalog-less table to the BE:
+     * <ul>
+     *   <li>data table: drop the catalog loader. A {@link FileStoreTable} is 
fully defined by
+     *       fileIO / location / schema / catalogEnvironment, and its dynamic 
options (time travel,
+     *       incremental) are merged into the schema by {@code copy(...)}, so 
rebuilding from
+     *       fileIO / location / schema preserves everything except the 
catalog loader.</li>
+     *   <li>system table (e.g. {@code $snapshots}): rebuild it over a 
catalog-less data table so
+     *       {@code SnapshotManager#latestSnapshotId} lists the snapshot 
directory on the filesystem
+     *       instead of calling the metastore. The base table is the one the 
FE-side wrapper was
+     *       built over, and for the system tables that pick their snapshot on 
the BE ({@link
+     *       #resolvesSnapshotOnBackend}) what the catalog would have done 
there is done here
+     *       instead: see {@link #authorizeDeferredScan} and {@link 
#pinCatalogSnapshot}. Every
+     *       other system table reads what the FE already planned, so it is 
handed over
+     *       untouched.</li>
+     * </ul>
+     */
+    private Table getPaimonTableForBackend() {
+        Table paimonTable = source.getPaimonTable();
+        if (paimonTable instanceof FileStoreTable) {
+            return dropCatalogLoader((FileStoreTable) paimonTable);
+        }
+        if (!(source.getExternalTable() instanceof PaimonSysExternalTable)) {
+            return paimonTable;
+        }
+        PaimonSysExternalTable sysTable = (PaimonSysExternalTable) 
source.getExternalTable();
+        // The very same base table the FE-side wrapper was built over, so 
that the BE never sees a
+        // different schema generation than the one this query was planned 
with.
+        FileStoreTable dataTable = sysTable.getSysBaseTable();
+        if (dataTable == null) {
+            return paimonTable;
+        }
+        String sysTableType = sysTable.getSysTableType();
+        if (PAIMON_FILES_SYSTEM_TABLE_TYPE.equalsIgnoreCase(sysTableType)) {
+            authorizeDeferredScan(dataTable);
+        }
+        FileStoreTable baseForBackend = dropCatalogLoader(dataTable);
+        if (resolvesSnapshotOnBackend(sysTableType)) {
+            baseForBackend = pinCatalogSnapshot(baseForBackend, dataTable);

Review Comment:
   The mechanism is real, but neither remedy is available through paimon's API, 
and this is not a regression from the pin. Documented as a Known gap on 
`pinCatalogSnapshot` in e63a97be480 instead of changed.
   
   **Why the marker set cannot be bound to the pin.** 
`FilesTable.FilesScan#innerPlan` (`FilesTable:189-217`) builds its markers from 
`fileStoreTable.newSnapshotReader().partitions()`. That resolves as 
`SnapshotReaderImpl#partitions:415` -> `scan.listPartitions()` -> 
`AbstractFileStoreScan#readManifests:414` -> 
`ManifestsReader#read(specifiedSnapshot = null, ..):114-122`, which falls 
through to `snapshotManager.latestSnapshot()`. `SnapshotReaderImpl` never reads 
`scan.snapshot-id` out of the `CoreOptions` it is handed - a snapshot is only 
ever set by an explicit `withSnapshot(..)` (`:168-176`), and `FilesScan` does 
not call it. So no table level option, on either the wrapper or the base table, 
can move the FE marker set; "use the same captured bound for FE marker 
generation" is not expressible here. The second suggestion is not either: 
`FilesSplit` is a `private static` nested class of `FilesTable`, so Doris 
cannot construct a snapshot independent marker.
   
   **Why it is not introduced by the pin.** `$files` was already a two-phase 
plan with two independent snapshot resolutions. Before this change the BE 
re-planned each marker at read time against a catalog-ful table 
(`FilesRead#createReader` -> `FilesSplit#splits` -> 
`storeTable.newScan().plan()`), i.e. the marker set came from the FE at 
split-generation time and the file list from a snapshot resolved strictly 
later, across a wider window than init-to-finalize. The same hybrid was 
therefore observable before, in the opposite direction; the pin only moves 
which side of the window the mismatch falls on, and narrows it.
   
   So the observable behaviour is unchanged in kind and improved in window 
size, and closing it properly needs a change in paimon (`FilesScan` honoring 
`scan.snapshot-id`, or exposing the marker type), not in Doris. Recorded next 
to the existing `$snapshots` / `$buckets` and fallback-branch gaps, with the 
exact call chain, so the next reader does not have to re-derive it.
   
   For the record on scope: `$partitions` is not affected - `PartitionsScan` 
emits a single stateless `SingletonSplit` and the BE reader plans the whole 
table, so there is no FE-side marker set to skew.



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