jerryshao commented on PR #13351:
URL: https://github.com/apache/gravitino/pull/13351#issuecomment-5754470736

   **Verdict:** blocking issues — the lazy capability → `ops()` resolution 
escapes the catalog's isolated classloader, and `getTableObjectsByName` now 
costs two extra metastore round-trips per table.
   
   ### Findings
   
   1. 
`catalogs/catalog-hive/src/main/java/org/apache/gravitino/catalog/hive/HiveCatalog.java:91`
 — `HiveCatalogCapability` resolves the metastore version through `ops()`, and 
that resolution can now run **outside** the catalog's `IsolatedClassLoader`. 
`TableNormalizeDispatcher.createTable` 
(core/src/main/java/org/apache/gravitino/catalog/TableNormalizeDispatcher.java:79-82)
 obtains the `Capability` inside `doWithCatalog(...)` but calls 
`applyCapabilities(columns, capability)` after returning, i.e. under the server 
classloader; `CapabilityHelpers.applyColumnNotNull` 
(core/src/main/java/org/apache/gravitino/catalog/CapabilityHelpers.java:570-575)
 then calls `columnNotNull()`, which reaches 
`HiveCatalogCapability.requireHive3` → `hiveVersion.get()` → 
`HiveCatalog.hiveVersion()` → `BaseCatalog.ops()` → 
`HiveCatalogOperations.initialize(...)` + 
`clientPool.run(HiveClient::hiveVersion)` 
(HiveCatalogOperations.java:1105-1124). So on the first `createTable` after a 
restart, the wh
 ole Hive ops stack (Hadoop `Configuration`, Kerberos login, 
`HiveClientFactory`, the HMS connection) is constructed with the wrong TCCL — 
exactly what `CatalogManager.initCatalogWrapper` avoids by preloading 
`properties()`/`capability()` inside the isolated loader 
(core/src/main/java/org/apache/gravitino/catalog/CatalogManager.java:1821-1827: 
"Preload properties() and capability() inside the IsolatedClassLoader so that 
AppClassLoader can read them later without needing the isolated context"). A 
second consequence: an HMS outage now surfaces as a connection failure from 
column validation rather than from the operation itself. Suggested fix: resolve 
and cache the version inside the isolated context — e.g. in 
`HiveCatalogOperations.initialize()`, with the capability reading only the 
cached value — instead of letting the capability trigger ops creation. 
(verified by: read the dispatch chain `TableNormalizeDispatcher` → 
`CapabilityHelpers` → `HiveCatalogCapability` → `HiveCat
 alog.hiveVersion()` → `BaseCatalog.ops()` in this checkout; not reproduced 
against a running server, so please confirm whether Hive ops initialization 
tolerates the app classloader.)
   
   2. 
`catalogs/hive-metastore3-libs/src/main/java/org/apache/gravitino/hive/client/hive3/HiveShimV3.java:344`
 — `getTableObjectsByName` calls `loadColumnConstraints` per returned table, 
and each call makes two RPCs (`getNotNullConstraints`, `getDefaultConstraints`, 
lines 391/401). `HudiHMSBackendOps.listTables` 
(catalogs/catalog-lakehouse-hudi/src/main/java/org/apache/gravitino/catalog/lakehouse/hudi/backend/hms/HudiHMSBackendOps.java:147-153)
 calls it for every table in a schema and only uses `t.name()` plus properties, 
so listing a 500-table Hudi schema on a Hive 3 HMS goes from 2 calls to ~1001 
sequential round-trips. `HiveCatalogOperations` already avoids this API for 
exactly this reason (HiveCatalogOperations.java:418-424, "getTableObjectsByName 
materializes every table and is slow on large databases"). Suggested fix: skip 
constraint loading in the batch path (or make it opt-in), so only single-table 
`getTable` pays for it. (verified by: read both call sites and the constrain
 t-loading helper in this checkout.)
   
   3. 
`catalogs/hive-metastore3-libs/src/main/java/org/apache/gravitino/hive/client/hive3/HiveShimV3.java:367`
 — the `close()` override drops the null guard that the base class has 
(`HiveShim.close()`, 
catalogs/hive-metastore-common/src/main/java/org/apache/gravitino/hive/client/HiveShim.java:321-325).
 The override adds nothing else; deleting it keeps the safer inherited 
behavior. (verified by: compared both method bodies.)
   
   4. `build.gradle.kts:355` — the root `subprojects {}` block returns early 
for `:catalogs:hive-metastore2-libs` and `:catalogs:hive-metastore3-libs`, 
which skips error-prone, the `-Xlint:*`/`-Werror` compiler args 
(build.gradle.kts:475-491) and jacoco for those modules. That exclusion was 
harmless while the modules only repackaged dependency jars; this PR moves ~575 
lines of production logic (`HiveShimV3`, `HiveShimV2`) into them, so the new 
code is the only shim code not covered by the project's static analysis, and 
its tests do not appear in the coverage report. Suggested fix: narrow the early 
return to the publishing/packaging parts and keep the java quality config. 
(verified by: read the early return and the error-prone/`-Werror` configuration 
it skips.)
   
   5. Open question — 
`catalogs/hive-metastore-common/src/main/java/org/apache/gravitino/hive/converter/HiveColumnDefaultValueConverter.java:202-207`
 — string defaults are escaped/unescaped with backslashes (`'it\'s'`). 
Gravitino-written values round-trip (that is what `CatalogHive3IT` asserts), 
but a `DEFAULT` written by Hive DDL with SQL doubling (`'it''s'`) is read back 
as the literal `it''s`, and it is not obvious that Hive's own parser accepts 
the backslash form in the constraint text Gravitino writes. Could you confirm 
against a real Hive 3 `CREATE TABLE ... DEFAULT` for a string containing a 
quote?
   
   ### Tests
   
   Unit coverage for the new pieces is good (`TestHiveShimV3`, 
`TestHiveColumnDefaultValueConverter`, `TestHiveCatalogCapability`), and 
`CatalogHive3IT` covers create/rename/property-alter round-trips through HMS. 
Gaps:
   
   - No test creates a `NOT NULL`/`DEFAULT` constraint on a **partition** 
column. `CatalogHive3IT.checkColumnConstraintsOnCreate` 
(catalogs/catalog-hive/src/test/java/org/apache/gravitino/catalog/hive/integration/test/CatalogHive3IT.java:56-87)
 uses `Transforms.EMPTY_TRANSFORM`, and in `checkColumnConstraintsOnAlter` 
(line 130) the partition column stays nullable with no default — yet 
`buildColumnConstraints` (HiveShimV3.java:463-499) iterates all columns 
including partition keys, which HMS stores outside the storage descriptor. One 
IT for a partitioned table with a non-nullable partition column would close 
this.
   - `TestHiveCatalog.testCapabilityWithCustomOperations` 
(catalogs/catalog-hive/src/test/java/org/apache/gravitino/catalog/hive/TestHiveCatalog.java:126-130)
 sets `ops-impl` to `HiveCatalogOperations` itself, so `ops instanceof 
HiveCatalogOperations` is true and the `HIVE2` fallback in 
HiveCatalog.java:93-99 never runs; the assertion passes only because the test 
HMS is Hive 2. Use a custom `CatalogOperations` class to actually exercise the 
fallback.
   - `TestHiveShimV3.testAlterTableDropsAndRecreatesConstraints` 
(catalogs/hive-metastore3-libs/src/test/java/org/apache/gravitino/hive/client/hive3/TestHiveShimV3.java:165-185)
 verifies that drop/alter/add all happened but not their order, which is the 
invariant that makes the sequence safe. `InOrder` would pin it down.
   
   ### Nits
   
   - `HiveShimV3.constraintName` (HiveShimV3.java:501-510) regenerates a random 
constraint name on every alter, so constraint names are not stable across 
alters; worth a line in the docs if users may reference them.
   - `HiveCatalog.hiveVersion()` (HiveCatalog.java:93-99) downgrades silently 
to `HIVE2` at `LOG.debug` level; a user on Hive 3 with a custom `ops-impl` 
would get "the connected Hive Metastore version is HIVE2", which is misleading 
— `LOG.warn` with the reason would help.
   
   ---
   _Generated by [Claude Code](https://claude.ai/code)_


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

Reply via email to