wombatu-kun opened a new issue, #19431:
URL: https://github.com/apache/hudi/issues/19431

   ### Problem
   
   `HoodieHiveSyncClient` and `AWSGlueCatalogSyncClient` both memoize the 
metastore table in a per-instance `initialTableByName` map, filled lazily by 
`getInitialTable`. It was added in HUDI-9365 ("Reduce overhead of Hive and AWS 
Glue sync tools") to avoid repeated `getTable` calls during a sync. In both 
clients exactly three reads go through it: `getLastCommitTimeSynced`, 
`getLastCommitCompletionTimeSynced` and `getTableLocation`.
   
   Neither client invalidates that entry when it mutates the table. In 
`HoodieHiveSyncClient` eight methods call `alter_table` or `dropTable` 
(`updateTableProperties`, `updateSerdeProperties`, `createOrReplaceTable`, 
`updateLastReplicatedTimeStamp`, `deleteLastReplicatedTimeStamp`, 
`updateLastCommitTimeSynced`, `updateHoodieWriterVersion`, `dropTable`) and 
none of them touch the map. So within a single sync run the client can hand 
back a `last_commit_time_sync` or a table location that it has itself already 
overwritten.
   
   The two clients then diverge, by accident rather than by design. 
`AWSGlueCatalogSyncClient.tableExists` performs a real `GetTable` and re-puts 
the result into `initialTableByName`, and `HiveSyncTool.syncHoodieTable` calls 
`tableExists` as its very first step, so on Glue the entry is refreshed 
immediately before every cached read. `HoodieHiveSyncClient.tableExists` 
returns the metastore client's boolean and never populates the map, so on Hive 
the entry survives from the first `getTableLocation` of the run until the 
client is closed.
   
   ### Why it is latent today rather than live
   
   The one path that exercised the divergence was `HiveSyncTool.doSync()` under 
the default `ALL` strategy with 
`hoodie.datasource.hive_sync.skip_ro_suffix=true`. `initTableNameVars` makes 
`roTableName` the bare table name, so the same metastore table was synced twice 
in one run, first as read-optimized and then again by the "sync origin table" 
step. On Hive the second call read the pre-write snapshot, `isAlreadySynced` 
returned false, and `updateSerdeProperties` rewrote the input format to 
`HoodieParquetRealtimeInputFormat`; the refreshed entry on Glue would have made 
the same sequence short-circuit instead. That is what #16637 and #12011 report, 
and the open PR #19427 fixes it by removing the redundant second sync.
   
   With #19427 in, I could not find any remaining path in the Hive sync code 
that reads a cached field after writing it. `GlobalHiveSyncTool` reads 
replication timestamps live rather than through `getInitialTable`, 
`recreateAndSyncHiveTable` never re-reads after replacing the table, and every 
other entry point builds a fresh `HiveSyncTool` per sync. So this is currently 
an inconsistency between two implementations of the same interface rather than 
a reproducible failure.
   
   ### The design question
   
   Which contract is `getInitialTable` meant to have? The two answers imply 
opposite patches, and I do not think the code settles it.
   
   1. **A per-run snapshot**, as the name suggests: the table as it was when 
this sync started. Under this reading `isAlreadySynced` is asking "was this 
table already up to date before I began", which is a reasonable question, 
`HoodieHiveSyncClient` is correct as written, and the defect is 
`AWSGlueCatalogSyncClient.tableExists` quietly breaking the snapshot on every 
call.
   2. **A cache of current state.** Under this reading Glue is correct and 
`HoodieHiveSyncClient` should invalidate or refresh the entry in the methods 
that mutate the fields it serves.
   
   ### Proposal
   
   Pick one of the two readings, make both clients honor it, and record the 
choice in a comment on `getInitialTable`, because the next person who syncs one 
table twice in a run will hit whichever half is wrong. If (2) is chosen, the 
smallest change is a private `invalidate(tableName)` called from 
`updateLastCommitTimeSynced`, `createOrReplaceTable` and `dropTable`, the three 
mutators that change the cached fields, which keeps HUDI-9365's 
one-fetch-per-table behavior on the common path. Either way a client-level test 
that reads, writes and reads again would pin the chosen semantics.
   
   Happy to send the patch once the direction is settled.
   
   ### Appendix: how this surfaced
   
   Reviewing PR #19427. Its regression test syncs once against an empty 
metastore, which is the one case where the redundant real-time sync is skipped 
anyway by the `isAlreadySynced` guard, so the test passes with the production 
change reverted. Adding a second commit and another sync round makes it fail 
with `expected: <org.apache.hudi.hadoop.HoodieParquetInputFormat> but was: 
<org.apache.hudi.hadoop.realtime.HoodieParquetRealtimeInputFormat>`. Working 
out why one round behaves differently from two is what surfaced the cache.
   


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