Add branchRefName to TableAuditEvent - #616
Conversation
Table operations against named Iceberg branches are not currently observable: the existing TableAuditEvent records currentSnapshotId and currentSnapshotTimestampMs but has no signal for which branch ref was written. Add branchRefName to TableAuditEvent, populated in extractSnapshotInfo() from the existing snapshotRefs and jsonSnapshots fields on the request body. The committed branch is identified by matching the last snapshot in jsonSnapshots (Iceberg always appends new snapshots chronologically) to the ref that points to it in snapshotRefs. This correctly handles main branch commits, named branch commits where main did not advance, and the case where no main ref is present at all. This is safe to rely on: every request through putIcebergSnapshots has a non-empty jsonSnapshots (the repository layer gates snapshotRefs processing on jsonSnapshots being present), so the last-snapshot invariant holds for all reachable code paths.
mkuchenbecker
left a comment
There was a problem hiding this comment.
I would update the PR to reflect table properties more strongly as that seems to be as large a change as the branch ref.
|
|
||
| private String branchRefName; | ||
|
|
||
| private Map<String, String> tableProperties; |
There was a problem hiding this comment.
this is a bigger change than the branch ref name.
| if (source == null || source.isEmpty()) { | ||
| return null; | ||
| } | ||
| List<String> allowlist = internalCatalogProperties.getAudit().getTablePropertiesAllowlist(); |
There was a problem hiding this comment.
Where is this defined?
| List<String> allowlist = internalCatalogProperties.getAudit().getTablePropertiesAllowlist(); | ||
| if (allowlist == null || allowlist.isEmpty()) { | ||
| return null; | ||
| } | ||
| Map<String, String> filtered = new HashMap<>(); | ||
| for (String key : allowlist) { | ||
| String value = source.get(key); | ||
| if (value != null) { | ||
| filtered.put(key, value); | ||
| } | ||
| } | ||
| return filtered.isEmpty() ? null : filtered; |
There was a problem hiding this comment.
Optional<Set> allowlist = Optional(internalCatalogProperties.getAudit().getTablePropertiesAllowlist()) // convert to set
allowlist.foreach(allowlist -> source.filter(key -> allowlist.contains(key)))
This can be way more compact I feel if we use stream filtering.
| try { | ||
| Map<String, String> snapshotRefs = requestBody.getSnapshotRefs(); | ||
| if (snapshotRefs == null) { | ||
| List<String> jsonSnapshots = requestBody.getJsonSnapshots(); |
There was a problem hiding this comment.
More of a style thing, but I perfer to cast
mkuchenbecker
left a comment
There was a problem hiding this comment.
what is the status of this pr?
Problem
The Git for Data feature introduces named Iceberg branch refs, but table operation observability is blind to them. Today
TableAuditEventrecordscurrentSnapshotIdandcurrentSnapshotTimestampMsfor the main branch, with no signal for which branch a write went to. Dali and Grid Observability cannot answer "was this commit to main or a named branch?" without ACL-gated access to current table state.Solution
Add
branchRefNametoTableAuditEvent, populated at commit time from the existingsnapshotRefsandjsonSnapshotsfields already present onIcebergSnapshotsRequestBody.How the committed branch is identified: Iceberg appends snapshots chronologically, so the last entry in
jsonSnapshotsis always the newly-committed snapshot. We find the ref insnapshotRefswhose snapshot-id matches it — that ref is the branch being written.This correctly handles:
branchRefName = "main"branchRefName = "<branch>"branchRefName = "<branch>",currentSnapshotId = nullWhy the last-snapshot assumption is safe: Every request reaching
putIcebergSnapshotshas a non-emptyjsonSnapshots— the repository layer (doUpdateSnapshotsIfNeeded) gates allsnapshotRefsprocessing onjsonSnapshotsbeing present. A ref-only update is a silent no-op that never commits, so the last-snapshot invariant holds for all reachable code paths.Changes
TableAuditEvent.java— addString branchRefNameTableAuditAspect.java— populate inextractSnapshotInfo()by matching last snapshot to its ref; no separate pass, no special-casing for mainIcebergSnapshotsApiHandlerAuditTest.java— two new tests: main commit sets"main", named branch commit sets the branch name; existing branch-only test updated to assertbranchRefNameTableAuditModelConstants.java— addbranchRefName("main")to the three commit-path expected eventsDepends on
#601 (adds
tablePropertiestoTableAuditEvent; merge that first)