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>
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>
CI pre-sets send_logs_level to warning, so the previous :-error default did not suppress IcebergMetadata v1/v2 schema fallback Warnings on stderr. Co-authored-by: Cursor <cursoragent@cursor.com>
A single-value insert made allow_experimental_iceberg_read_optimization skip SchemaConverter, so the unmapped field_id check never ran. https://altinity-build-artifacts.s3.amazonaws.com/json.html?PR=2183&sha=c6e46a613d2c141e7a9acef06b85fbf0794e029a&name_0=PR&name_1=Stateless%20tests%20(amd_debug,%20parallel) #2183 Co-authored-by: Cursor <cursoragent@cursor.com>
3fff4be to
5a7c982
Compare
Export extractDeletionVectorPayload / roaring deserialize from PuffinBlockInputFormat and drop the duplicated codec path in PuffinDeletionVectorReader. Co-authored-by: Cursor <cursoragent@cursor.com>
Docs already disallow column-scoped DVs; enforce empty fields in both the SQL Puffin and Iceberg bind validators. Co-authored-by: Cursor <cursoragent@cursor.com>
Shrinking const count chunks without a filter broke file-row mapping for any later row-number consumer; record the same mask the dense path uses. 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>
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: