Skip to content

Antalya 26.6: Backport of #98178 Iceberg compaction using optimize - #2193

Merged
zvonand merged 15 commits into
antalya-26.6from
iceberg_manifest_compaction_antalya_26_6
Sep 14, 2026
Merged

zvonand merged 15 commits into
antalya-26.6from
iceberg_manifest_compaction_antalya_26_6

Conversation

@subkanthi

@subkanthi subkanthi commented Aug 8, 2026 •

Copy link
Copy Markdown
Collaborator

Changelog category (leave one):

  • New Feature

Changelog entry (a user-readable short description of the changes that goes to CHANGELOG.md):

Add support for iceberg compaction of manifest files using optimize command.

Documentation entry for user-facing changes

Adds OPTIMIZE TABLE ... MANIFEST to trigger manifest-only compaction for Iceberg tables, backport of ClickHouse#98178
This PR covers rewriting manifest files. The default value is 30, but can be overwritten using iceberg_manifest_min_count_to_compact. The setting is the threshold: compaction runs only if the current snapshot's manifest list contains strictly more than this many manifest files. Setting this value to 0 means "always compact"

CI/CD Options

Exclude tests:

  • Fast test
  • Integration Tests
  • Stateless tests
  • Stateful tests
  • Performance tests
  • Aarch64 tests
  • All with ASAN
  • All with TSAN
  • All with MSAN
  • All with UBSAN
  • All with Coverage
  • All Regression
  • Disable CI Cache

Regression jobs to run:

  • Fast suites (mostly <1h)
  • Aggregate Functions (2h)
  • Alter (1.5h)
  • Benchmark (30m)
  • ClickHouse Keeper (1h)
  • Iceberg (2h)
  • LDAP (1h)
  • OAuth (5m)
  • Parquet (1.5h)
  • RBAC (1.5h)
  • SSL Server (1h)
  • S3 (2h)
  • S3 Export (2h)
  • Swarms (30m)
  • Tiered Storage (2h)

@subkanthi subkanthi changed the title Port of iceberg compaction from upstream antalya 26.6: Port of iceberg compaction from upstream Aug 8, 2026
@github-actions

github-actions Bot commented Aug 8, 2026 •

Copy link
Copy Markdown

Workflow [PR], commit [c10fa77]

@subkanthi
subkanthi force-pushed the iceberg_manifest_compaction_antalya_26_6 branch from fc76726 to 9626fa1 Compare August 12, 2026 19:49
@subkanthi subkanthi changed the title antalya 26.6: Port of iceberg compaction from upstream Antalya 26.6: Backport of 98178 Iceberg compaction using optimize Aug 16, 2026
@subkanthi
subkanthi marked this pull request as ready for review August 16, 2026 16:13
@subkanthi

Copy link
Copy Markdown
Collaborator Author
OPTIMIZE TABLE iceberg_trino_test.`default.optimize_manifest_fieldid` MANIFEST
SETTINGS
    allow_experimental_iceberg_compaction = 1,
    iceberg_manifest_min_count_to_compact = 2,
    allow_insert_into_iceberg = 1,
    write_full_path_in_iceberg_metadata = 1;

test_storage_iceberg_with_trino/test.py::test_optimize_manifest_trino_field_ids
[gw0] [100%] PASSED test_storage_iceberg_with_trino/test.py::test_optimize_manifest_trino_field_ids

  • generated report log file: /root/Documents/ClickHouse/ci/tmp/pytest_parallel.jsonl -
    ======================== 8 passed in 340.20s (0:05:40) =========================
    Run command: [sudo iptables -D DOCKER-USER 1 ||:]
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    Ok [Integration tests (amd_tsan, 1/6)]
    | Failures: 0/8
    ++++++++++++++++++++

@subkanthi

subkanthi commented Aug 19, 2026 •

Copy link
Copy Markdown
Collaborator Author

Multiple inserts to create manifests


Ubuntu-2404-noble-amd64-base :) insert into ice.`flowers.sample` values(14, false, 14.0);

INSERT INTO ice.`flowers.sample` FORMAT Values

Query id: 3efe4235-c9fc-4801-8388-e8424d9052c0

Ok.

1 row in set. Elapsed: 1.471 sec. 

Ubuntu-2404-noble-amd64-base :) insert into ice.`flowers.sample` values(15, false, 15.0);

INSERT INTO ice.`flowers.sample` FORMAT Values

Query id: e5c02b18-8a7c-4988-b406-6c76ef9ce1e3

Ok.

1 row in set. Elapsed: 4.284 sec. 

Ubuntu-2404-noble-amd64-base :) insert into ice.`flowers.sample` values(16, false, 16.0);

INSERT INTO ice.`flowers.sample` FORMAT Values

Query id: 579f1ff8-0e8c-4090-8401-4f8ad65cb85c

Ok.

1 row in set. Elapsed: 1.161 sec. 

Ubuntu-2404-noble-amd64-base :) insert into ice.`flowers.sample` values(17, false, 17.0);

INSERT INTO ice.`flowers.sample` FORMAT Values

Query id: 3ab42808-b5b5-4e00-894a-7da86685436e

Ok.

1 row in set. Elapsed: 1.293 sec. 

Ubuntu-2404-noble-amd64-base :) insert into ice.`flowers.sample` values(18, false, 18.0);

INSERT INTO ice.`flowers.sample` FORMAT Values

Query id: 1f0f3745-2df9-46b8-a2f3-24e80eebdc4b

Ok.

1 row in set. Elapsed: 0.722 sec. 

BEFORE:

ice files flowers.sample
2026-08-20 00:15:36 [main/1725085] INFO o.a.i.r.auth.AuthManagers > Loading AuthManager implementation: org.apache.iceberg.rest.auth.NoopAuthManager
Snapshots: flowers.sample
└── Snapshot 8262575200555583623, schema 4: s3://bucket1/flowers/sample/metadata/snap-8262575200555583623-2-2fc15c6b-7e72-4ded-8f47-9381d60aa78f.avro
    ├── Manifest: s3://bucket1/flowers/sample/metadata/58901361-d4dd-402c-8990-905b76fc8422.avro
    │   └── Datafile: s3://bucket1/flowers/sample/data/data-f53c47ab-8d0a-4b79-8edc-fbf960bce414.parquet
    ├── Manifest: s3://bucket1/flowers/sample/metadata/c2200427-403f-493a-8737-e98f10c820f3.avro
    │   └── Datafile: s3://bucket1/flowers/sample/data/data-6c3bcbcd-9f3a-4d8e-a2aa-e89dba45933d.parquet
    ├── Manifest: s3://bucket1/flowers/sample/metadata/16e42c94-0f1b-4fcb-96a5-90b3aa890676.avro
    │   └── Datafile: s3://bucket1/flowers/sample/data/data-9eca5943-09c3-423c-ae48-5fe3b89aad21.parquet
    ├── Manifest: s3://bucket1/flowers/sample/metadata/6794aab6-3dc9-4945-8528-31ed4023bf2f.avro
    │   └── Datafile: s3://bucket1/flowers/sample/data/data-20d9a7a8-bab8-4fa5-a665-d6d0552e73b7.parquet
    ├── Manifest: s3://bucket1/flowers/sample/metadata/685e041f-c818-48dc-955e-bdbe747e7afa.avro
    │   └── Datafile: s3://bucket1/flowers/sample/data/data-6200eb02-c3cf-4481-a1d6-8a62b748d9b1.parquet
    ├── Manifest: s3://bucket1/flowers/sample/metadata/120a6ca5-5ef0-4766-9cc8-b7eb4a06e986.avro
    │   └── Datafile: s3://bucket1/flowers/sample/data/1783515818468-5385203953de32f1e4f96effd36253b8cd6971f796a62acaf5bb9d7f45dd4249.parquet
    ├── Manifest: s3://bucket1/flowers/sample/metadata/d8fe3175-908e-45eb-b6f8-04587c794da7.avro
    │   ├── Datafile: s3://bucket1/flowers/sample/data/data-c26f7933-272c-4d98-bafb-1103038d7132.parquet
    │   ├── Datafile: s3://bucket1/flowers/sample/data/data-62238d2a-14af-4f85-a0b1-acd7c5b98294.parquet
    │   └── Datafile: s3://bucket1/flowers/sample/data/data-fa9aaac5-1043-4075-8a89-3c32735882ac.parquet
    └── Manifest: s3://bucket1/flowers/sample/metadata/c89ca381-e73f-468b-aebd-62b08815d002.avro
        └── Datafile: (failed to read: Cannot read a delete manifest with a ManifestReader: GenericManifestFile{content=DELETES, path=s3://bucket1/flowers/sample/metadata/c89ca381-e73f-468b-aebd-62b08815d002.avro, length=2944, partition_spec_id=0, added_snapshot_id=1745025533079389269, added_data_files_count=1, added_rows_count=1, existing_data_files_count=0, existing_rows_count=0, deleted_data_files_count=0, deleted_rows_count=0, partitions=null, key_metadata=null, sequence_number=2, min_sequence_number=2, first_row_id=null})

Ubuntu-2404-noble-amd64-base :) OPTIMIZE TABLE ice.`flowers.sample` MANIFEST
SETTINGS
    allow_experimental_iceberg_compaction = 1,
    iceberg_manifest_min_count_to_compact = 1,
    allow_insert_into_iceberg = 1,
    write_full_path_in_iceberg_metadata = 1;

AFTER

 files flowers.sample
2026-08-20 00:18:22 [main/1725551] INFO o.a.i.r.auth.AuthManagers > Loading AuthManager implementation: org.apache.iceberg.rest.auth.NoopAuthManager
Snapshots: flowers.sample
└── Snapshot 6210131662371618023, schema 4: s3://bucket1/flowers/sample/metadata/snap-6210131662371618023-2-53278c2e-c4b1-4fe3-92e1-199dad3bb964.avro
    ├── Manifest: s3://bucket1/flowers/sample/metadata/9b93d3ca-18c4-4bec-a754-3ef9c4e367c7.avro
    │   └── Datafile: s3://bucket1/flowers/sample/data/1783515818468-5385203953de32f1e4f96effd36253b8cd6971f796a62acaf5bb9d7f45dd4249.parquet
    ├── Manifest: s3://bucket1/flowers/sample/metadata/7d6b19df-decc-45b1-878d-4633ca419368.avro
    │   ├── Datafile: s3://bucket1/flowers/sample/data/data-f53c47ab-8d0a-4b79-8edc-fbf960bce414.parquet
    │   ├── Datafile: s3://bucket1/flowers/sample/data/data-6c3bcbcd-9f3a-4d8e-a2aa-e89dba45933d.parquet
    │   ├── Datafile: s3://bucket1/flowers/sample/data/data-9eca5943-09c3-423c-ae48-5fe3b89aad21.parquet
    │   ├── Datafile: s3://bucket1/flowers/sample/data/data-20d9a7a8-bab8-4fa5-a665-d6d0552e73b7.parquet
    │   ├── Datafile: s3://bucket1/flowers/sample/data/data-6200eb02-c3cf-4481-a1d6-8a62b748d9b1.parquet
    │   ├── Datafile: s3://bucket1/flowers/sample/data/data-c26f7933-272c-4d98-bafb-1103038d7132.parquet
    │   ├── Datafile: s3://bucket1/flowers/sample/data/data-62238d2a-14af-4f85-a0b1-acd7c5b98294.parquet
    │   └── Datafile: s3://bucket1/flowers/sample/data/data-fa9aaac5-1043-4075-8a89-3c32735882ac.parquet
    └── Manifest: s3://bucket1/flowers/sample/metadata/c89ca381-e73f-468b-aebd-62b08815d002.avro
        └── Datafile: (failed to read: Cannot read a delete manifest with a ManifestReader: GenericManifestFile{content=DELETES, path=s3://bucket1/flowers/sample/metadata/c89ca381-e73f-468b-aebd-62b08815d002.avro, length=2944, partition_spec_id=0, added_snapshot_id=1745025533079389269, added_data_files_count=1, added_rows_count=1, existing_data_files_count=0, existing_rows_count=0, deleted_data_files_count=0, deleted_rows_count=0, partitions=null, key_metadata=null, sequence_number=2, min_sequence_number=2, first_row_id=null})

@subkanthi

Copy link
Copy Markdown
Collaborator Author

@blau-ai

@blau-ai

blau-ai commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

CI triage for #2193

Verdict: 7 red checks — 0 caused by this PR's code. 6 are flaky/infra/pre-existing; 1 is the expected consequence of adding a new setting and is fixed in the clickhouse-regression repo (snapshot update), not here. None of the failing tests touch the Iceberg/OPTIMIZE code paths this PR changes.

Head SHA analyzed: 9200f13.


Not PR-caused (flaky / infra / pre-existing)

1. Stateless tests (amd_debug, parallel) — 3 sub-failures, all cleared by CI's own diagnosis:

  • 00071_merge_tree_optimize_aio — reproducible only with randomized settings (68/68 pass without randomization; CI verdict: "Confirmed: the failure is caused by randomized settings"). It's a MergeTree AIO test, not the Iceberg OPTIMIZE ... MANIFEST path. Flaky.
  • 02456_keeper_retries_during_insert — "All reruns passed… not reproducible"; transient UNKNOWN_STATUS_OF_INSERT (quorum timeout). Flaky.
  • 00163_column_oriented_formats — "All reruns passed… not reproducible"; Timeout! Killing process group. Flaky (see CI: stateless tests time out due to network latency between our runners and the S3 test-data bucket #2227).

2. Stateless tests (amd_debug, distributed plan, s3 storage, parallel)

3. SQLLogic test — 6 new failures vs 10,520 fixed. Every new failure is Code: 241 … (total) memory limit exceeded … RSS 25.85 GiB on random/select/slt_good_* SELECT queries — memory-pressure flakiness on the runner, unrelated to OPTIMIZE/Iceberg.

4. Regression release settings — 1 of the 2 failing scenarios:

  • max_alter_threads — snapshot expects auto(16), server reports auto(8). This is auto(<#cpu>); the snapshot was recorded on a 16-core box, this runner has 8. Hardware-dependent, not PR-related.

5. Regression release tiered_storage_cas — every failure is MetadataStorageFactory: unknown metadata storage type: cas. (UNKNOWN_ELEMENT_IN_CONFIG). The cas metadata-storage feature isn't available in this build; the CAS regression jobs were only just added to the pipeline (7419377). Independent of this diff (the PR touches no disk/metadata-storage config). Infra/build-config.

6. Grype Scan (…-alpine) — 1 High: CVE-2026-14456 in the Alpine base image. Container base-image CVE, nothing to do with the C++ changes here.

7. PR — aggregate gate; red only because of the above.


PR-related, but no code fix needed here

Regression release settings — the other failing scenario is iceberg_manifest_min_count_to_compact, reported as a SnapshotNotFoundError (name not present in the stored snapshot; actual value default=30).

This is the new setting this PR adds (src/Core/Settings.cpp, UInt64, default 30). The default_values regression test compares every setting against a stored snapshot, and this new name isn't in it yet. The actual default (30) is correct — this is the normal "new setting → update the snapshot" bookkeeping, not a bug in the PR.

Concrete fix (in Altinity/clickhouse-regression, not this repo): add an entry for iceberg_manifest_min_count_to_compact (default 30) to
settings/tests/snapshots/default_values.py.default values>=26.6_antalya.snapshot, typically by re-recording the 26.6 settings snapshot. I can't push there — it's outside my write scope — so flagging for whoever maintains the regression snapshots.


Suggested next steps

  • Stateless + SQLLogic: safe to re-run — all diagnosed non-reproducible / randomized-settings / memory-pressure.
  • settings / tiered_storage_cas / Grype: environmental (snapshot bookkeeping, missing cas build feature, base-image CVE) — handle at the regression/pipeline level, not in this PR.
  • Nothing in the PR's C++ diff needs changing for these failures.

One coverage note (not a failure): all Integration tests jobs — including this PR's own test_manifest_compaction.py — were skipped in this pipeline, so the new Iceberg-compaction integration tests didn't actually execute here. Worth a targeted integration run to confirm the feature before merge.

🤖 automated CI triage · evidence from praktika result_pr.json, regression report.html, and Grype results for 9200f13

/*added_data_files=*/added_files,
/*added_delete_files=*/added_delete_files,
/*added_position_deletes=*/num_deleted_rows,
/*added_equality_deletes=*/0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In original PR ClickHouse#98178 this block replaces lines below (sum_with_parent_snapshot(...)), here these lines still there.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed sum_with_parent_snapshot block

@subkanthi
subkanthi requested a review from ianton-ru August 30, 2026 20:43
ianton-ru
ianton-ru previously approved these changes Aug 31, 2026
@subkanthi subkanthi added verified Approved for release and removed verified Approved for release labels Sep 9, 2026
@subkanthi
subkanthi requested a review from ianton-ru September 10, 2026 14:11
@subkanthi subkanthi changed the title Antalya 26.6: Backport of 98178 Iceberg compaction using optimize Antalya 26.6: Backport of #98178 Iceberg compaction using optimize Sep 10, 2026
@zvonand

zvonand commented Sep 14, 2026

Copy link
Copy Markdown
Member

@blau-ai

@blau-ai

blau-ai commented Sep 14, 2026

Copy link
Copy Markdown
Collaborator

CI triage for c10fa77

Verdict: 4 red checks / ~32 failing scenarios — none point to a code defect in this PR.
All actual test failures are infrastructure or pre-existing branch issues. The only failure that is even attributable to this PR is a settings-snapshot gap in the external regression repo (expected whenever a new setting is added; it is not a bug and is not fixed here).

Check Failing Classification PR-caused?
Stateless tests (amd_debug, sequential) 3 Infra — test-dataset host unreachable / TOO_SLOW ❌ No
Stateless tests (amd_binary, cas s3 storage, parallel) 10 Infra — same host timeout + runner-overload test timeouts ❌ No
Regression release swarms 14 Pre-existing — regression suite uses a setting this binary doesn't have ❌ No
Regression release settings 5 Snapshot lag; 1 is this PR's new setting, 4 are other branch settings ⚠️ 1 expected (not a defect)

1–2. Stateless tests — infrastructure outage (not PR)

Every failing stateless test operates on the shared stateful dataset (test.hits / test.visits), and every failure is a connection or slowness error against the dataset host, not a wrong result:

Code: 1000. DB::Exception: Timeout: connect timed out: 65.108.242.32:6000. (POCO_EXCEPTION)
  in query: SELECT sum(cityHash64(*)) FROM test.hits ...        # 00167_read_bytes_from_fs
  in query: INSERT INTO test.hits_1m SELECT * FROM test.hits ...# 00157_cache_dictionary
Code: 160. DB::Exception: Estimated query execution time (38048s) is too long. Maximum: 900. (TOO_SLOW)
  in query: INSERT INTO test.hits_log SELECT ... FROM test.hits # 00077_log_tinylog_stripelog

The CAS-S3 suite shows the same signature: connect timed out: 65.108.242.32:6000 (00020_distinct_order_by_distributed, 00054_merge_tree_partitions), TOO_SLOW (00178_quantile_ddsketch), and Timeout! Killing process group on the heavy TPC-DS queries (04033_tpc_ds_q56/q61/q71/q81/q86/q94, 00152_insert_different_granularity) — a runner that couldn't reach the dataset host and was overloaded.

None of these tests touch Iceberg or anything in this diff. Action: safe to re-run once the dataset host is healthy.

3. Regression release swarms — pre-existing (not PR)

All 14 failures are the same error in one feature (/swarms/feature/fallback to local if empty); the other 11 swarm features pass:

Code: 552. DB::Exception: Unrecognized option '--object_storage_cluster_fallback_to_local_if_empty'. (UNRECOGNIZED_ARGUMENTS)

The clickhouse-regression suite is exercising a setting (object_storage_cluster_fallback_to_local_if_empty) that does not exist in this build (26.6.4.20001.altinityantalya) — i.e. the regression suite is ahead of what this branch ships. This PR neither adds nor removes that setting (its only change to StorageObjectStorageCluster is an additive getCatalog() accessor that delegates to pure_storage), so it cannot be the cause. This will fail identically for any PR on antalya-26.6 until the branch gains that setting or the suite is pinned. Action: pre-existing; track against the branch, not this PR.

4. Regression release settings — snapshot lag (1 expected, 4 pre-existing)

The default values test compares each setting against a recorded snapshot (default_values.py.default values>=26.6_antalya.snapshot). All 5 failures are SnapshotNotFoundError — the setting is simply absent from the snapshot, not a wrong default:

✘ analyzer_compatibility_multiple_joins_qualify_column_names   (pre-existing branch setting)
✘ filesystem_cache_wait_for_concurrent_download_timeout_milliseconds (pre-existing)
✘ iceberg_manifest_min_count_to_compact                        ← added by THIS PR
✘ statistics_max_set_size_for_exact_selectivity_estimation     (pre-existing)
✘ throw_on_hive_partitioning_resolution_failure                (pre-existing)

iceberg_manifest_min_count_to_compact (UInt64, default 30) is the new setting this PR adds in Settings.cpp / SettingsChangesHistory.cpp, so its snapshot miss is a direct consequence of the PR — but it is expected behaviour, not a defect: this test fails for every newly-added setting until the snapshot is regenerated. The other 4 are unrelated new settings on antalya-26.6 with the same snapshot lag.

Concrete fix (external repo, not this PR): add iceberg_manifest_min_count_to_compact to the settings snapshot in Altinity/clickhouse-regression (settings/tests/snapshots/default_values.py.default values>=26.6_antalya.snapshot) — ideally in the same PR/batch that adds the other four branch settings. No change to this ClickHouse PR is warranted, so I have not pushed anything.


Caveat: the feature's own tests did not run here

Integration and unit tests were all skipped in this workflow config (excluded asan/tsan/msan/arm tags, and the amd integration/unit jobs show SKIPPED). That means this PR's own coverage — tests/integration/test_storage_iceberg_with_spark/test_manifest_compaction.py, test_database_iceberg::test_optimize_manifest_with_catalog, and the gtest_iceberg_* unit tests — was not exercised by this run. The red checks are all unrelated to the compaction code, but the compaction code isn't validated by them either. Consider triggering an integration-test run (label/re-run with the iceberg integration jobs enabled) before merge.

Health check

The changed C++ is contained (Iceberg metadata/compaction, an additive OPTIMIZE … MANIFEST-style parser path, one new UInt64 setting, and an additive cluster accessor) and builds cleanly — every Build job is green, as are Fast test, Stateless amd_debug parallel, s3 storage, cas storage, Stress, AST/BuzzHouse fuzzers, SQLLogic and SQLStorm. No failure in this run implicates the PR's logic.

(Analysis from CI artifacts only — I can't build or run ClickHouse in this environment; correctness is ultimately confirmed by a clean CI run.)

@zvonand
zvonand merged commit 8aa94ea into antalya-26.6 Sep 14, 2026
402 of 411 checks passed
@Selfeer

Selfeer commented Sep 15, 2026

Copy link
Copy Markdown
Collaborator

@subkanthi I know it's a backport but still can you have a look if these make sense for this PR.

PR #2193 audit findings

Iceberg manifest compaction via OPTIMIZE TABLE ... MANIFEST.

High: Commit-failure cleanup can delete manifests after the new snapshot is already visible

After the compacted metadata is published, a later catalog failure (or an exception in the same try block) still runs cleanup(), which deletes the new manifest files and manifest list. The published snapshot continues to point at those paths, so subsequent readers can fail to plan or scan the table.

This happens in two commit layouts:

  • Non-transactional catalog (Glue) or filesystem + version-hint: writeMetadataFileAndVersionHint writes vN.metadata.json and updates version-hint.text first. If catalog->updateMetadata then throws or returns false, cleanup() removes the files that vN already references. Listing-based / version-hint readers pick up the new metadata and see a broken snapshot; the catalog pointer may still name the previous metadata.
  • Transactional REST catalog: the storage-side metadata write is skipped, but RestCatalog::updateMetadata treats HTTP 5xx / 408 as a retryable false (“commit state unknown”). If the catalog actually applied the replace snapshot, cleanup() still deletes the live manifests that snapshot now names.

cleanup() only removes rewritten manifests and the new manifest list. It does not delete or roll back the metadata file or version hint, and it does not check whether the catalog commit already succeeded.


Medium: Manifest-list partition bounds are dropped for common Iceberg partition types

The rewrite recomputes each compacted manifest-list entry’s partitions[*].lower_bound / upper_bound only when canDumpIcebergStats accepts the partition type. That helper still allows only a subset of types (Int32, Int64, dates/times, String, decimals). dumpFieldToBytes already serializes UInt8/UInt16/UInt32/UInt64 and Float32/Float64, but those types never reach it.

ClickHouse’s partition-transform result types hit the rejected set on ordinary tables:

  • bucket[N] → UInt32 (icebergBucket)
  • year → UInt16 (toYearNumSinceEpoch)
  • month → UInt32 (toMonthNumSinceEpoch)
  • day / hour → UInt32
  • identity float / double → Float32 / Float64

After compaction those summaries keep null bounds. Spark (and any reader that prunes from manifest-list partition stats) cannot prune those partitions and must open extra manifests. Row data is unchanged, but the rewritten metadata no longer matches the source manifests.

A narrower extra failure: isNaNPartitionValue always does field.safeGet<Float64>() even for Float32, so a NaN float partition can throw during the rewrite instead of recording contains_nan.

The bucket-partition integration test only round-trips rows through Spark; it does not assert non-null lower_bound / upper_bound on the rewritten manifest list.


Low: Rewritten data manifests drop optional per-file fields the parser never reads

Manifest-only rewrite copies column_sizes, value_counts, null_value_counts, and lower/upper bounds, plus file_format, sort_order_id, and entry lineage. It does not round-trip other optional Iceberg data-file fields that exist in the Avro schema, notably nan_value_counts and split_offsets.

Those fields are not loaded by AvroForIcebergDeserializer, so they cannot be written back. Spark readers of a compacted snapshot lose NaN column counts and file split offsets. Query results stay correct; scan planning can be coarser (one split per file, weaker NaN stats).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

antalya antalya-26.6 verified Approved for release verified-with-issues Verified by QA and issues found.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants