Skip to content

fix: optimistic delete guard prevents stale DROP from overwriting renamed Glue table #141

Merged
jamespfaulkner merged 2 commits into
mainfrom
fix/glue-optimistic-delete
Jul 3, 2026
Merged

fix: optimistic delete guard prevents stale DROP from overwriting renamed Glue table #141
jamespfaulkner merged 2 commits into
mainfrom
fix/glue-optimistic-delete

Conversation

@jamespfaulkner

Copy link
Copy Markdown
Contributor

Summary

  • Replaces unconditional delete() calls in GlueTableService with a new deleteIfUnchanged() method that guards against a race condition in multi-partition Kafka (DroneFly) deployments
  • Before issuing DeleteTable, fetches the current Glue state and compares transient_lastDdlTime and metadata_location against the HMS event; skips the delete with a WARN log if either differs
  • Prevents a stale DROP event from undoing a concurrent Iceberg rename that landed on a different Kafka partition and was processed first

Fixes Bug 1 from #140. Bug 2 (orphaned _iceberg entry) requires a separate change to the isIcebergPredicate guard in onAlterTable and is not addressed here.

How it works

When a DROP and a RENAME touch the same table name via different Kafka partitions, the RENAME pod may process first and write a new transient_lastDdlTime to Glue. When the DROP pod runs, deleteIfUnchanged fetches the current Glue entry and sees the timestamp no longer matches the HMS event — skipping the delete and leaving the renamed table intact.

The two events land on different partitions because KafkaMessageSender hashes qualifiedTableName to select a partition, and KafkaMetaStoreEventListener uses the old table name for ALTER events. So DROP db.table keys on db.table and RENAME db.table_iceberg → db.table keys on db.table_iceberg — different strings, different partitions, different consumer pods, no ordering guarantee between them.

Safe in direct-HMS deployments: HMS does not update transient_lastDdlTime on DROP, so the event value always matches the last-synced Glue value and the delete proceeds normally.

Caveat: if a prior sync failed (transient Glue error), params will diverge and the delete will be skipped, leaving an orphan. An orphan is intentionally preferred over incorrectly deleting a table that has since been overwritten by a rename.

Test plan

  • GlueTableServiceTest — new test class covering all deleteIfUnchanged branches: match deletes, each identity param mismatch skips, EntityNotFoundException skips, null param maps on either side, diverging non-null values
  • Existing ApiaryGlueSyncTest passes unchanged
  • mvn test -pl hive-event-listeners/apiary-gluesync-listener

🤖 Generated with Claude Code

jamespfaulkner and others added 2 commits July 3, 2026 09:34
…named tables in Glue

Replaces unconditional delete() calls with deleteIfUnchanged() in GlueTableService.
Before deleting a Glue table, fetches the current state and compares transient_lastDdlTime
and metadata_location against the HMS event. If either differs the delete is skipped with
a WARN log, preventing a stale DROP event from undoing a concurrent Iceberg rename that
landed on a different Kafka partition and was processed first.

Fixes: #140 (Bug 1 only — the
orphaned old Iceberg entry requires a separate fix to the isIcebergPredicate guard).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
onDropTable, onDropTableThatDoesntExistInGlue, and onAlterHiveTable_RenameTable
now call deleteIfUnchanged which issues a GetTable before DeleteTable. Added
getTable stubs returning an empty Glue table so the identity checks pass and
the delete proceeds as the tests expect.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@jamespfaulkner jamespfaulkner marked this pull request as ready for review July 3, 2026 09:08
@jamespfaulkner jamespfaulkner requested a review from a team as a code owner July 3, 2026 09:08
@jamespfaulkner jamespfaulkner merged commit 60ce1bf into main Jul 3, 2026
1 check passed
@jamespfaulkner jamespfaulkner deleted the fix/glue-optimistic-delete branch July 3, 2026 12:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants