Skip to content

Antalya 26.1: Remote initiator improvements#1577

Open
ianton-ru wants to merge 9 commits intoantalya-26.1from
feature/antalya-26.1/remote_initiator_improvements
Open

Antalya 26.1: Remote initiator improvements#1577
ianton-ru wants to merge 9 commits intoantalya-26.1from
feature/antalya-26.1/remote_initiator_improvements

Conversation

@ianton-ru
Copy link
Copy Markdown

Changelog category (leave one):

  • New Feature

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

Different improvement for remote initiator

Documentation entry for user-facing changes

With remote initiator feature queries like

SELECT * FROM iceberg(...) SETTINGS object_storage_cluster='swarm', object_storage_remote_initiator=1

rewrites as

SELECT * FROM remote('remote_host', icebergCluster('swarm', ...)

'remote_host' is a random host from 'swarm' cluster
See #756

Current PR introduces the next improvements:

  1. Partially solved object_storage_remote_initiator auth works incorrectly #1570 - uses username and password if access to cluster requires it. Throws exception if cluster uses common secret, this should be solved in future PRs.
  2. Solved object_storage_remote_initiator with different cluster name #1571 - new setting object_storage_remote_initiator_cluster allows to choose remote_host from different cluster, not only from swarm
  3. remote query did not work with additional setting inside function, like remote('remote_host', iceberg(..., SETTINGS iceberg_metadata_file_path='path/to/metadata.json')). Now must work correctly.
  4. In query remote('remote_host', icebergCluster('remote_cluster', ...)) cluster remote_cluster can be defined only on remote_host and unknown on current initial host. Removed cluster check on early stage, this allows to execute such queries.

CI/CD Options

Exclude tests:

  • Fast test
  • Integration Tests
  • Stateless tests
  • Stateful tests
  • Performance tests
  • All with ASAN
  • All with TSAN
  • All with MSAN
  • All with UBSAN
  • All with Coverage
  • All with Aarch64
  • 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)
  • Parquet (1.5h)
  • RBAC (1.5h)
  • SSL Server (1h)
  • S3 (2h)
  • S3 Export (2h)
  • Swarms (30m)
  • Tiered Storage (2h)

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 25, 2026

Workflow [PR], commit [259fb32]

@ianton-ru
Copy link
Copy Markdown
Author

@codex review

@ianton-ru
Copy link
Copy Markdown
Author

Audit: PR #1577 — Antalya 26.1: Remote initiator improvements

Source: Altinity/ClickHouse#1577
Base: antalya-26.1
Reviewed revision: branch including commit d7c4beebbdb (Remove unused header) and prior feature commits.


Confirmed defects

None. No confirmed defects in reviewed scope.

(Earlier revision briefly introduced an unused #include <Common/logger_useful.h> in QueryAnalyzer.cpp; commit d7c4beebbdb removes it.)


Coverage summary

Area Notes
Scope reviewed FunctionNode SETTINGS handling (QueryTreeBuilder, FunctionNode hash / clone / equal / toASTImpl), QueryAnalyzer::resolveTableFunctionTableFunctionNode bridge, StorageDistributed::buildQueryTreeDistributed, IStorageCluster::{read, convertToRemote} (initiator cluster, secret guard, URI decode, user/password remote), ITableFunctionCluster cluster-presence check removal, Settings / SettingsChangesHistory, integration tests under tests/integration/test_s3_cluster/.
Categories failed None.
Categories passed SETTINGS propagation for nested table functions; initiator cluster selection (object_storage_remote_initiator_cluster); host decode and auth branches; fail-closed on cluster secret (NOT_IMPLEMENTED); deferred cluster resolution for remote-only definitions; recursion guard via object_storage_remote_initiator = false on copied context; SettingsChangesHistory updates; integration scenarios (secret error, split initiator vs object-storage cluster).
Assumptions / limits Pre-existing static pcg64 RNG in convertToRemote may be a concurrency concern under parallel queries; not introduced by this PR. Poco::URI::decode on full Address::toString() not exhaustively validated for every exotic address encoding; aligned with escapeForFileName / dotted-host tests.

Audit metadata

  • Method: Static review per workspace audit-review standard (call graph, transitions, fault categories, concurrency and C++ hazard pass).
  • Output rule: Confirmed defects only; hypotheticals folded into assumptions/limits.

AI-generated audit note.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a0d1972000

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +354 to +358
auto remote_initiator_cluster_name = settings[Setting::object_storage_remote_initiator_cluster].value;
if (remote_initiator_cluster_name.empty())
remote_initiator_cluster_name = cluster_name_from_settings;
auto remote_initiator_cluster = getClusterImpl(context, remote_initiator_cluster_name);
auto storage_and_context = convertToRemote(remote_initiator_cluster, context, remote_initiator_cluster_name, query_to_send);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Strip initiator-only cluster setting before forwarding query

When object_storage_remote_initiator_cluster is set, the query forwarded via remote(...) still carries that setting even though convertToRemote only clears object_storage_remote_initiator. This makes remote execution depend on remote nodes understanding a setting that is only needed on the initiator; in mixed-version/rolling-upgrade clusters, older remote hosts can fail with unknown-setting errors before execution. The forwarded AST settings should drop object_storage_remote_initiator_cluster together with object_storage_remote_initiator.

Useful? React with 👍 / 👎.

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.

@ianton-ru does it make sense? it looks like it does

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

object_storage_remote_initiator_cluster does nothing without ``object_storage_remote_initiator`. Make sense to remove just for less garbage in sub-query.

Prewhere filter
Prewhere filter column: less(multiply(2, b), 100)
Filter column: and(indexHint(greater(plus(i, 40), 0)), equals(a, 0)) (removed)
Filter column: and(equals(a, 0), indexHint(greater(plus(i, 40), 0))) (removed)
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Argument order depends on hash, hash was changes (see FunctionNode::updateTreeHashImpl)

@svb-alt svb-alt requested a review from arthurpassos March 26, 2026 12:33
if (settings[Setting::object_storage_remote_initiator])
{
auto storage_and_context = convertToRemote(cluster, context, cluster_name_from_settings, query_to_send);
auto remote_initiator_cluster_name = settings[Setting::object_storage_remote_initiator_cluster].value;
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.

Please add a comment explaining what this code block does. It took me a while to understand it by just reading the code.

I suggest something like:

/// In case the current node is not supposed to initiate the clustered query
/// Sends this query to a remote initiator using the `remote` table function
if (settings[Setting::object_storage_remote_initiator])
{
      /// Re-writes queries in the form of:
      /// Input: SELECT * FROM iceberg(...) SETTINGS object_storage_cluster='swarm', object_storage_remote_initiator=1
     /// Output: SELECT * FROM remote('remote_host', icebergCluster('swarm', ...)
     /// Where `remote_host` is a random host from the cluster which will execute the query
     /// This means the initiator node belongs to the same cluster that will execute the query
     /// In case remote_initiator_cluster_name is set, the initiator might be set to a different cluster
}

if (shard_addresses.size() != 1)
throw Exception(ErrorCodes::LOGICAL_ERROR, "Size of shard {} in cluster {} is not equal 1", shard_num, cluster_name_from_settings);
auto host_name = shard_addresses[0].toString();
std::string host_name;
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.

why?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Address here in encoded format foo%2Ebar instead of foo.bar. This wasn't catched in tests before I add a host with dot in name.

auto remote_query = makeASTFunction(remote_function_name, make_intrusive<ASTLiteral>(host_name), table_expression->table_function);
boost::intrusive_ptr<ASTFunction> remote_query;

if (shard_addresses[0].user_specified)
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.

A comment please

throw Exception(ErrorCodes::CLUSTER_DOESNT_EXIST, "Requested cluster '{}' not found", cluster_name);
/// Remove check cluster existing here
/// In query like
/// remote('remote_host', xxxCluster('remote_cluster', ...))
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.

What if the query is not remote? Can't we check for that?

/// If cluster not exists, query falls later

Where and with which exception? It would be good to avoid any network calls before failing

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Cluster name is not a network node name, it's an internal ClickHouse name. Query falls later when tries to get hosts from cluster. Network calls can't be made without hosts.

But it's hard to understand here is cluster function inside 'remote' or not.

Comment on lines +354 to +358
auto remote_initiator_cluster_name = settings[Setting::object_storage_remote_initiator_cluster].value;
if (remote_initiator_cluster_name.empty())
remote_initiator_cluster_name = cluster_name_from_settings;
auto remote_initiator_cluster = getClusterImpl(context, remote_initiator_cluster_name);
auto storage_and_context = convertToRemote(remote_initiator_cluster, context, remote_initiator_cluster_name, query_to_send);
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.

@ianton-ru does it make sense? it looks like it does

@arthurpassos
Copy link
Copy Markdown
Collaborator

The changes look ok, but I think it needs more documentation. I also wonder if we can keep the 'cluster exists' check by wrapping that check in a `if (!is_remote0'

Copy link
Copy Markdown
Collaborator

@arthurpassos arthurpassos left a comment

Choose a reason for hiding this comment

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

LGTM

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants