Skip to content

UniqApacheHLL fixes based on feedback - #2545

Open
UnamedRus wants to merge 9 commits into
antalya-26.8from
feature/antalya-26.8/uniq-apache-hll-extended
Open

UnamedRus wants to merge 9 commits into
antalya-26.8from
feature/antalya-26.8/uniq-apache-hll-extended

Conversation

@UnamedRus

@UnamedRus UnamedRus commented Oct 12, 2026 •

Copy link
Copy Markdown
Collaborator

Changelog category (leave one):

  • Improvement

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

Add new functions addVarUIntLengthPrefix, removeVarUIntLengthPrefix, and toVarUInt to add or strip the length prefix so raw Apache DataSketches can be read as uniqApacheHLL states and exported back. New optional third parameter estimator for uniqApacheHLL with values 'DEFAULT' or 'COMPOSITE'. 'COMPOSITE' gives a result not dependent on the order of inserts and merges.

UnamedRus and others added 2 commits October 12, 2026 20:15
Brings the implementation of ClickHouse#124667 to this branch:
- the third parameter `estimator` (`'DEFAULT'` or `'COMPOSITE'`), the second computes the estimate from the registers of the sketch only, so it does not depend on the order of the inserts and of the merges;
- a state that is read keeps the sketch as it was written, and a mixed state is merged in the order in which it is folded;
- states of any parameters have one normalized state type;
- the bytes of a `UUID` do not depend on the byte order of the host;
- the function is marked as order dependent and is not registered on big-endian platforms;
- the documentation tells how to hash `UInt8`, `UInt16` and `UInt32` like the C++ library.

Related: ClickHouse#124667

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: UnamedRus <dtitmoav@gmail.com>
…Int`

A sketch that another system writes, for example Spark into Parquet, has no length in front of it, while the state of `uniqApacheHLL` stores its sketch as a `VarUInt` length and the bytes. `CAST` of such a sketch to `AggregateFunction(uniqApacheHLL, ...)` fails with `CORRUPTED_DATA`, and `toString` of a state gives bytes that the other system cannot read.

`addVarUIntLengthPrefix` puts the length of a string in front of it, `removeVarUIntLengthPrefix` takes it off and throws an exception when the length is not complete or is not the number of the bytes that follow, and `toVarUInt` encodes one unsigned number. The length is read as the `RowBinary` reader reads it.

Related: ClickHouse#124667

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: UnamedRus <dtitmoav@gmail.com>
@github-actions

github-actions Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Workflow [PR], commit [1677e65]

UnamedRus and others added 4 commits October 12, 2026 20:40
…o it

A state can hold a union and a sketch of inserts that came after a merge, for example when the rows of the tail of a block are added to a state that has already merged the lookup tables of the block, as the aggregation by a `UInt8` key does. `merge` took the new sketches first and folded the pending sketch at its end, so the older rows came after the newer ones. As the HIP estimate and the bytes of the sketch depend on this order, the pending rows are now folded into the union before the sketches are taken.

The result of the default estimator can still differ with the size of the blocks, since the lookup tables merge the rows in another order; the composite estimator does not, and a test checks it.

Related: ClickHouse#124667

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: UnamedRus <dtitmoav@gmail.com>
Related: ClickHouse#124667

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: UnamedRus <dtitmoav@gmail.com>
The constant exists in the `VarInt.h` of upstream master only, so the function did not compile on this branch. It is defined in the file under another name, so that it does not clash when the branch merges upstream.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: UnamedRus <dtitmoav@gmail.com>
@svb-alt
svb-alt requested a review from xieandrew October 20, 2026 14:17
@DimensionWieldr

Copy link
Copy Markdown
Collaborator

PR #2545 CI Triage

Head 0ec719f6 on antalya-26.8, run 39221861489. 68 non-green jobs. None of them are a uniqApacheHLL regression. x86 aggregate parts 1, 2, and 3 all passed. The shared header change in this pull request is a comment only: stateIsIndependentOfNullability() still defaults to false.

Compared with the previous head 207b968 (run 38416356716), the same suites were already red. Three jobs are new on this run, and all three are environment failures.

The CI database was not queried. The rate comparison is this pull request’s two heads.

Summary

Category What Jobs
PR-caused regression none 0
Pre-existing settings snapshot gap, aarch64 t-test snapshots, OAuth, swarms, Azure allowlist, every CAS job the stable set from 207b968
Infrastructure runner drop, upload stall, Kerberos KDC, parser binary lookup, Grype CVEs, two 3h30 timeouts 8
Cascade parent rows behind those roots, and every Kerberos scenario behind the KDC —

What this pull request actually ran

x86 aggregate_functions_1, _2, and _3 succeeded. On aarch64, parts 1 and 2 failed only studentTTest, welchTTest, and analysisOfVariance. No uniqApacheHLL scenario is in those failure lists. aarch64 part 3 was cancelled at the 3h30 job limit, so aarch64 state tests did not finish. Stateless tests on amd (debug, asan, tsan, msan) and the fast test passed.

Pre-existing (same on 207b968)

  • Settings, both architectures. 1855 default-value scenarios each. SnapshotNotFoundError for default_values.py.default values>=26.8_antalya.snapshot. The suite appends _antalya for an Antalya build (settings/tests/default_values.py). The file in the regression tree is default values>=26.8.snapshot, without that suffix. Version string is 26.8.27.20001.altinityantalya.
  • aarch64 aggregate parts 1 and 2. About 494 leaf scenarios: studentTTest (412), welchTTest (75), analysisOfVariance (7), plus three finalizeAggregation merges in part 2. SnapshotError against steps.py.*>=26.8.aarch64.snapshot. x86 snapshots for the same functions matched. Parent paths (/aggregate functions, /part 1, /part 2) are cascade.
  • OAuth, both architectures. Expected HTTP 500, got 403 ACCESS_DENIED (Not enough privileges, grant CREATE TEMPORARY TABLE).
  • Swarms, both architectures. Code: 279 ALL_CONNECTION_TRIES_FAILED on s3Cluster('swarm', ...).
  • S3 Azure, both architectures. Code: 491 URL "http://azurite:10000" is not allowed, remote_url_allow_hosts.
  • Every CAS, CAS S3-cache, and tiered-storage CAS job, both architectures. Server exits in about four minutes: Code: 137 unknown metadata storage type: cas. This pull request does not change the build flags.

Infrastructure

  • Stateless tests (arm_binary, sequential). The runner lost communication during Run. No test log and no artifact were published. This job passed on 207b968.
  • x86 functions. No scenario failed. The job died on Upload progress stalled. Passed on 207b968.
  • x86 Kerberos. Kinit: Cannot contact any KDC for realm 'EXAMPLE.COM'. The other Kerberos rows are cascade of that. Passed on 207b968. aarch64 Kerberos passed on this run.
  • Parser memory check. Error [Resolve master binary]. Same on 207b968.
  • Grype. Keeper image: 4 high/critical, including CVE-2026-84782, CVE-2026-84784, CVE-2026-85091, CVE-2026-72897. Alpine server image: 1 high/critical. The non-alpine server scan passed. Same on 207b968.
  • x86 lightweight delete and aarch64 aggregate part 3. Both hit The job has exceeded the maximum execution time of 3h30m0s and were cancelled. The lightweight-delete timeout also happened on 207b968.

Recommendations

  1. The uniqApacheHLL changes are good to verify. The red jobs are the 26.8 suite gaps and environment failures above.
  2. aarch64 aggregate part 3 never finished, so aarch64 state coverage for this function was not produced. x86 part 3 did pass.
  3. Settings on Antalya 26.8 will stay red until default values>=26.8_antalya.snapshot exists. That file is in the regression suite, not in this pull request.


AggregateFunctionProperties properties;
auto function = AggregateFunctionFactory::instance().get("uniqApacheHLL", NullsAction::EMPTY, normalized_argument_types, {}, properties);
return std::make_shared<DataTypeAggregateFunction>(function, normalized_argument_types, Array{});

@DimensionWieldr DimensionWieldr Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

From AI audit:

getNormalizedStateType makes every lg_k / storage type / estimator spelling compare equal, and that is not safe for this state.

array, if, and a squashed UNION ALL only CAST when the types differ. Once these types compare equal, that cast is skipped and concatenation goes through ColumnAggregateFunction::insertFrom / ensureOwnership, which merges each sketch into an empty state of whichever function survives (the first common type). HllSketchData::merge builds that union at the surviving lg_k, and write then persists get_result(target_type). A sketch built at lg_k = 14 placed next to one built at lg_k = 4 is permanently downsampled; hex(toString(...)) no longer round-trips, and a later estimate is the coarser one.

CAST itself would have kept the sketch, because read no longer folds it into a union. The tests only check toTypeName and small cardinalities, which stay exact after the resolution drop.

This is new relative to #2398. That PR already ignores parameters in haveSameStateRepresentationImpl, so an explicit uniqApacheHLLMerge(8) of a higher-resolution state downsamples on purpose. It does not override getNormalizedStateType, so uniqApacheHLL(8) and uniqApacheHLL(14, 'HLL_6') stay different types and this concatenation path does not run.

The estimator is the parameter that does not change the sketch. lg_k and the storage type are applied by merge and write, so they should stay part of the state type.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Addressed this on #2544 (the 26.6 version of this PR) since that one should be prioritized. Now getNormalizedStateType only compares equal for any estimator and not any lg_k and storage type. Please put further review comments on that PR.

@zvonand

zvonand commented Oct 20, 2026

Copy link
Copy Markdown
Member

@UnamedRus pls either add a changelog entry OR change category to "not for changelog"

@svb-alt svb-alt added antalya antalya-26.8 Session label (releasy session config) labels Oct 22, 2026
@alsugiliazova alsugiliazova mentioned this pull request Oct 23, 2026
10 of 30 tasks
Signed-off-by: Andrew Xie <dev@xie.is>

This branch has not been deployed

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

Labels

antalya antalya-26.8 Session label (releasy session config)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants