Iceberg deletion vector support (attempt #2) - #2183
Conversation
totalRows was aggregating optional column value_counts, which can disagree with row counts for nested fields; fail closed on negative or overflowing record_count instead. Co-authored-by: Cursor <cursoragent@cursor.com>
…deletion-vectors-read-2
…arser. Related: Altinity#2179 Related: Altinity#2183 Co-authored-by: Cursor <cursoragent@cursor.com>
Footer reads lost their profile event when the Iceberg path moved onto the shared `Puffin` format reader, which halved `PuffinFilesRead` in `04263_iceberg_puffin_files_cache`. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Aside from my own tests, I'm attaching an audit review for this PR, please check if any of these make sense and need fixing - I've tried to make it as easily readable as possible. Audit Review — PR #2183
High severity1.
|
ClickHouse mutations write parquet position-delete files that readers must ignore for data files with a DV, so fail closed instead. Only DELETE manifests are scanned. Co-authored-by: Cursor <cursoragent@cursor.com>
Wire appendReadBufferWithAbsoluteSizeLimit into the SQL footer fallback so crafted pipes cannot grow memory past the DV+footer ceiling. Co-authored-by: Cursor <cursoragent@cursor.com>
Match the Iceberg deletion-vector reader: call roaring_bitmap_internal_validate so untrusted files cannot be used with broken CRoaring invariants. Co-authored-by: Cursor <cursoragent@cursor.com>
Guard totalRows accumulation with addOverflow so a wrapped UInt64 sum falls back to a real scan instead of returning a wrong count. Co-authored-by: Cursor <cursoragent@cursor.com>
puffin_files_cache_size=0 still entered the cache miss path and disabled filesystem cache; skip that path when the LRU accepts no entries. Co-authored-by: Cursor <cursoragent@cursor.com>
LRU/SLRU treat max_count=0 as no entry-count limit, not disabled. Co-authored-by: Cursor <cursoragent@cursor.com>
Use the underscore form as the GRANT alias instead of a spaced self-alias, matching parquet/iceberg metadata cache privileges. Co-authored-by: Cursor <cursoragent@cursor.com>
The Iceberg path already accounted for blob I/O; the SQL Puffin format path only counted footer reads. Co-authored-by: Cursor <cursoragent@cursor.com>
Offsets follow the row-group layout; rejecting a stale file-level count broke otherwise readable ParquetV3 files on every read path. Co-authored-by: Cursor <cursoragent@cursor.com>
The helper classifies DV vs parquet deletes for callers such as mutation rejection; totalRows fail-closes on any live position deletes. Update comments and gtest names that implied totalRows wiring. Co-authored-by: Cursor <cursoragent@cursor.com>
Empty etag is already handled before tryCreateKey; treat a later nullopt as LOGICAL_ERROR instead of repeating the uncached path. Co-authored-by: Cursor <cursoragent@cursor.com>
Wait for insert-token refcount >= 2 instead of sleeping 50ms before clear, which raced when the producer finished before the waiter joined. Co-authored-by: Cursor <cursoragent@cursor.com>
They do not belong in the rendezvous hashing gtest; keep them next to ClusterFunctionReadTask under Interpreters/tests. Co-authored-by: Cursor <cursoragent@cursor.com>
Protocol < 2 omitted data-lake schema evolution silently; reject the task instead, matching excluded_rows / Iceberg deletes / bucket checks. Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the manifest record_count fallthrough for deletes and missing equality summary, but avoid opening every manifest on typical append-only tables again. Co-authored-by: Cursor <cursoragent@cursor.com>
Per-row-group spans stay on the bucketed path so tasks count only assigned groups without changing plain Parquet COUNT. Co-authored-by: Cursor <cursoragent@cursor.com>
Format version 3+ already rejects DELETE/UPDATE, and DVs do not exist on valid v2 tables, so the per-mutation DELETE-manifest walk was pure overhead. Co-authored-by: Cursor <cursoragent@cursor.com>
That virtual column exists only on StorageURL; it is never requested here, so the guard was always false. Co-authored-by: Cursor <cursoragent@cursor.com>
Avoid wiping the whole memo on insert; document concurrent miss stampede behavior. Co-authored-by: Cursor <cursoragent@cursor.com>
Workers receive excluded_rows bitmaps with tasks and do not re-read Puffin blobs. Co-authored-by: Cursor <cursoragent@cursor.com>
Spark writes file-scoped DVs with fields=[2147483645]; keep rejecting true column-scoped lists. Add DV+equality and icebergCluster bucket-split coverage. Co-authored-by: Cursor <cursoragent@cursor.com>
…lds. Align the `Puffin` format docs with `validateDeletionVectorV1Fields` after Spark file-scoped DVs were allowed. Co-authored-by: Cursor <cursoragent@cursor.com>
Reuse requireDeletionVectorV1Properties from the SQL Puffin format and a single checkDeletionVectorBlobReadLimits helper so bind/read paths stop duplicating validation. Co-authored-by: Cursor <cursoragent@cursor.com>
It was only used by the dropped Iceberg mutation DV scan; drop the API, iterator wrapper, dead include, and gtest. Co-authored-by: Cursor <cursoragent@cursor.com>
With snapshot-summary totalRows restored, optimize_count_from_files=0 alone still answered from Iceberg metadata; also set optimize_trivial_count_query=0 so the test forces Parquet decoding. Co-authored-by: Cursor <cursoragent@cursor.com>
Iceberg does not chain another row-number consumer after a DV on this path, so skip Filter/rb_range materialization and restore the cheap rb_range_cardinality + cloneResized fast path. Co-authored-by: Cursor <cursoragent@cursor.com>
…deletion-vectors-read-2 Resolve conflicts by keeping deletion-vector read paths and count fail-closed behavior, while adopting multistorage path resolution from antalya-26.6. Co-authored-by: Cursor <cursoragent@cursor.com>
DV tables often report total-equality-deletes=0 while still having position deletes; the summary path can under-count when a DV supersedes parquet position deletes, so fall through to the real scan / need_only_count path. Co-authored-by: Cursor <cursoragent@cursor.com>
Manifest column byte sizes and cross-manifest totals now reject negative or overflowing sums instead of wrapping, matching the totalRows contract. Co-authored-by: Cursor <cursoragent@cursor.com>
Footer memo no longer gets a second full copy of puffin_files_cache_size; its weight is charged into PuffinFilesCacheBytes/Files and trimmed when DV entries grow so resident usage cannot reach ~2x the configured maximum. Co-authored-by: Cursor <cursoragent@cursor.com>
|
I've run into these three issues in my tests after the latest changes:
The first one seems to be directly related to deletion vectors. The other two are not entirely deletion-vector-related, but they were triggered by the latest changes in this PR. |
A tiny non-zero puffin_files_cache_size previously took the cached path, disabled filesystem cache, paid an etag HEAD, then immediately evicted. Fall back to the uncached loader when the minimum entry weight exceeds the budget. Co-authored-by: Cursor <cursoragent@cursor.com>
Snapshot summary can keep total-position-deletes after deletes are already applied into rewritten data files; add regression coverage that the COUNT shortcut stays closed and count() matches the scan. Co-authored-by: Cursor <cursoragent@cursor.com>
Register a scheme-less absolute path and a flat delete file so ClickHouse remaps onto object storage after upload instead of LocalObjectStorage. Co-authored-by: Cursor <cursoragent@cursor.com>
Assert the snapshot-summary shortcut stays off when DVs or equality deletes are live, and that count() still matches a full scan. Co-authored-by: Cursor <cursoragent@cursor.com>
Poisoned or incrementally incorrect total-records must not become SELECT count(); keep summary only for a mismatch warning. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@Selfeer All three issues about wrong |
mkmkme
left a comment
There was a problem hiding this comment.
I didn't have time for a proper human review. But multiple rounds of review with AI ended up in the place where AI no longer has any complaints about the code. Approving this one. But will need to read it later myself.
PR #2183 CI Triage — Iceberg deletion vector support (attempt #2)
Bottom lineNo CI failure is a functional regression caused by this PR's code. The PR's own feature tests (stateless Summary
Detailed analysis1.
|
|
Latest regression run for delete vectors is fully green now after last changes, will upload the logs a bit later - the PR seems good to be merged. |
Changelog category (leave one):
Changelog entry (a user-readable short description of the changes that goes to CHANGELOG.md):
Iceberg deletion vectors support
Documentation entry for user-facing changes
Goal
Add read support for Iceberg v3 Puffin deletion vectors (
deletion-vector-v1) so ClickHouse applies DV bitmaps when reading Iceberg tables (local / object storage / cluster), without writing DVs.Also expose SQL input formats
Puffin/PuffinMetadatafor inspecting Puffin files, and a process-global Puffin files cache for parsed DV bitmaps.High-level architecture
Shared Puffin parsing / DV deserialize lives under:
PuffinFilePuffinDeletionVectorReaderPuffinFilesCacheIcebergDeletionVectorrecord_countPuffinBlockInputFormatPuffin/PuffinMetadatainput_format_allow_seeks = 0).Feature behavior (what users get)
content = 2/ deletion vectors).data − deletesarithmetic.excluded_rowsor delete metadata (no silent drop of deletes).SYSTEM DROP PUFFIN FILES CACHE(spaced form; underscore alias accepted) clears the cache; gated by access control.use_puffin_files_cacheand related server/cache size settings (seeSettings/ docs).Safety / fail-closed decisions (intentional)
Reviewers should treat these as product decisions, not accidental omissions:
(content_offset, content_size)matchingreferenced_data_file+ cardinality.< data_file.record_count.isEtagUsableAsCacheKey).excluded_rowsis present.Explicitly out of scope / deferred (workspace rule): Poco JSON
Int64wrap of2^63/2^63+1— do not treat as a defect to fix in this PR.Tests (where to look)
Unit / gtest
CacheBase/ LRU:getOrSetWithOutcome*Stateless
allow_seeks=0, stdin pipe, error fixtures undertests/queries/0_stateless/data_puffin/SYSTEM DROP PUFFIN FILES CACHEparsing / privilegesIntegration
tests/integration/test_storage_iceberg_with_spark/test_deletion_vectors.pydata_minio/(dv_puffin_*), generatorgenerate_iceberg_dv_fixture.pyDocs touched
Puffin/PuffinMetadataformatsSYSTEM DROP PUFFIN FILES CACHECI/CD Options
Exclude tests:
Regression jobs to run: