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>
Iceberg tables can store DV blobs alongside indexes/sketches; reject only invalid DV metadata, not non-DV entries. Co-authored-by: Cursor <cursoragent@cursor.com>
Same bucket/prefix on different S3 endpoints must not share deletion-vector cache entries. Co-authored-by: Cursor <cursoragent@cursor.com>
Protocol versions below Iceberg metadata support omit iceberg_info entirely, so workers must not silently drop schema IDs and file format even when delete lists are empty. Co-authored-by: Cursor <cursoragent@cursor.com>
Puffin v1 requires these footer fields to be unknown placeholders; accept only the specified values in parse and Iceberg bind. Co-authored-by: Cursor <cursoragent@cursor.com>
Row policies and PREWHERE reduce emitted rows while the cache key is file identity only; treat them like filter DAGs in FormatFilterInfo::hasFilter. Co-authored-by: Cursor <cursoragent@cursor.com>
Match the Iceberg reader fail-closed order so SQL FORMAT Puffin does not I/O or allocate up to 2 GiB when footer cardinality exceeds the materialization ceiling. Co-authored-by: Cursor <cursoragent@cursor.com>
Use false as previous_value so SET compatibility can disable the new default-on Puffin files cache on older Antalya versions. Co-authored-by: Cursor <cursoragent@cursor.com>
…deletion-vectors-read-2
|
Test |
Adding CLEAR_ENCRYPTION_HEADERS_CACHE (SYSTEM DROP ENCRYPTION HEADERS CACHE) pushed the last enumerator RESET_DDL_WORKER from ordinal 127 to 128, outside magic_enum's default reflection range [-128, 127]. ParserSystemQuery matches SYSTEM keywords via magic_enum::enum_values, so RESET_DDL_WORKER silently dropped out of the value list: SYSTEM RESET DDL WORKER stopped parsing and its access check was never reached, making 04401_system_reset_ddl_worker_access fail with both the unprivileged and on-cluster queries reported as NOT denied. Specialize magic_enum::customize::enum_range<ASTSystemQuery::Type> to cover every value (min = 0, max = 512), matching the fix used by other recent SYSTEM-command additions (e.g. ClickHouse#109639).
|
In upstream fix is in commit 2dd1e2cbfb93798aaa7eb81b6bb4c2f6a77a33f7, cherry-picked here |
Iceberg v3 writers must not add position-delete files; fail closed until deletion-vector writes are implemented. Co-authored-by: Cursor <cursoragent@cursor.com>
Equality deletes still demote the fast path; count-from-files cache stays fail-closed separately so DV count can use Parquet metadata plus bitmap cardinality. Co-authored-by: Cursor <cursoragent@cursor.com>
Coalesced multi-DV Puffin files shared one footer parse per file instead of reparsing the full footer on every deletion-vector slice miss. Co-authored-by: Cursor <cursoragent@cursor.com>
Empty deletion vectors no longer weigh one byte; long unique keys are bounded by the configured byte limit even when max entries is unlimited. Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the sibling CacheBase footer LRU and its metrics with a count-bounded mutex map so coalesced multi-DV files still parse once. Co-authored-by: Cursor <cursoragent@cursor.com>
Clear and disable footer memoization when the cache size is 0, and bound retained footers by the same approximate byte budget as DVs. Co-authored-by: Cursor <cursoragent@cursor.com>
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: