@@ -600,6 +600,9 @@ pub trait ConfigObj: DIService {
600600 /// partition coalesce (the hash aggregate ignores input order, so the per-row merge is wasted).
601601 fn coalesce_under_hash_aggregate ( & self ) -> bool ;
602602
603+ /// Router-side merge strategy for distributed value-ordered top-k.
604+ fn topk_aggregate_strategy ( & self ) -> TopKAggregateStrategy ;
605+
603606 fn allow_decimal128 ( & self ) -> bool ;
604607
605608 fn enable_remove_orphaned_remote_files ( & self ) -> bool ;
@@ -762,6 +765,7 @@ pub struct ConfigObjImpl {
762765 pub group_by_limit_factor : usize ,
763766 pub group_by_limit_per_partition : bool ,
764767 pub coalesce_under_hash_aggregate : bool ,
768+ pub topk_aggregate_strategy : TopKAggregateStrategy ,
765769 pub allow_decimal128 : bool ,
766770 pub enable_remove_orphaned_remote_files : bool ,
767771 pub enable_startup_warmup : bool ,
@@ -1116,6 +1120,10 @@ impl ConfigObj for ConfigObjImpl {
11161120 self . coalesce_under_hash_aggregate
11171121 }
11181122
1123+ fn topk_aggregate_strategy ( & self ) -> TopKAggregateStrategy {
1124+ self . topk_aggregate_strategy
1125+ }
1126+
11191127 fn allow_decimal128 ( & self ) -> bool {
11201128 self . allow_decimal128
11211129 }
@@ -1291,6 +1299,43 @@ pub async fn init_test_logger() {
12911299 }
12921300}
12931301
1302+ /// Router-side merge strategy for distributed value-ordered top-k (`SELECT ... GROUP BY x ORDER BY
1303+ /// agg(...) LIMIT k`). Selected by `CUBESTORE_TOPK_STRATEGY`.
1304+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
1305+ pub enum TopKAggregateStrategy {
1306+ /// Original streaming NRA merge with per-row state (default).
1307+ Streaming ,
1308+ /// Same streaming NRA merge (keeps early termination, bounded router memory), but vectorized.
1309+ VectorizedStreaming ,
1310+ /// ClickHouse-style full re-aggregation on the router + fetch-limited sort. Drops early
1311+ /// termination, so the router materializes every distinct group.
1312+ FullMerge ,
1313+ }
1314+
1315+ /// Parses [`TopKAggregateStrategy`] from an env var. Lenient: an unset or unrecognized value falls
1316+ /// back to the default (`Streaming`) with a warning rather than panicking -- a malformed perf toggle
1317+ /// must never take a node down.
1318+ fn env_topk_strategy ( name : & str ) -> TopKAggregateStrategy {
1319+ match env:: var ( name) {
1320+ Err ( _) => TopKAggregateStrategy :: Streaming ,
1321+ Ok ( v) => match v. trim ( ) . to_ascii_lowercase ( ) . as_str ( ) {
1322+ "" | "streaming" | "default" | "v1" => TopKAggregateStrategy :: Streaming ,
1323+ "vectorized" | "vectorized_streaming" | "v2" => {
1324+ TopKAggregateStrategy :: VectorizedStreaming
1325+ }
1326+ "full_merge" | "full-merge" | "fullmerge" => TopKAggregateStrategy :: FullMerge ,
1327+ other => {
1328+ log:: warn!(
1329+ "unknown {} value '{}', using default (streaming)" ,
1330+ name,
1331+ other
1332+ ) ;
1333+ TopKAggregateStrategy :: Streaming
1334+ }
1335+ } ,
1336+ }
1337+ }
1338+
12941339fn env_bool ( name : & str , default : bool ) -> bool {
12951340 env:: var ( name)
12961341 . ok ( )
@@ -1846,6 +1891,7 @@ impl Config {
18461891 group_by_limit_factor : env_parse_lenient ( "CUBESTORE_GROUP_BY_LIMIT_FACTOR" , 0 ) ,
18471892 group_by_limit_per_partition : env_flag ( "CUBESTORE_GROUP_BY_LIMIT_PER_PARTITION" ) ,
18481893 coalesce_under_hash_aggregate : env_flag ( "CUBESTORE_COALESCE_UNDER_HASH_AGGREGATE" ) ,
1894+ topk_aggregate_strategy : env_topk_strategy ( "CUBESTORE_TOPK_STRATEGY" ) ,
18491895 allow_decimal128 : env_bool ( "CUBESTORE_ALLOW_DECIMAL128" , false ) ,
18501896 enable_remove_orphaned_remote_files : env_bool (
18511897 "CUBESTORE_ENABLE_REMOVE_ORPHANED_REMOTE_FILES" ,
@@ -2105,6 +2151,7 @@ impl Config {
21052151 group_by_limit_factor : 2 ,
21062152 group_by_limit_per_partition : false ,
21072153 coalesce_under_hash_aggregate : false ,
2154+ topk_aggregate_strategy : TopKAggregateStrategy :: Streaming ,
21082155 allow_decimal128 : false ,
21092156 enable_remove_orphaned_remote_files : false ,
21102157 enable_startup_warmup : true ,
0 commit comments