@@ -189,8 +189,9 @@ use crate::catalog::{BuiltinTableUpdate, Catalog, OpenCatalogResult};
189189use crate :: client:: { Client , Handle } ;
190190use crate :: command:: { Command , ExecuteResponse } ;
191191use crate :: config:: {
192- ClusterEvalContext , ReplicaEvalContext , ScopedParameters , ScopedParametersScope ,
193- SynchronizedParameters , SystemParameterFrontend , SystemParameterSyncConfig ,
192+ ClusterEvalContext , ClusterScopeContext , ReplicaEvalContext , ReplicaScopeContext ,
193+ ScopedParameters , ScopedParametersScope , SynchronizedParameters , SystemParameterFrontend ,
194+ SystemParameterSyncConfig ,
194195} ;
195196use crate :: coord:: appends:: {
196197 BuiltinTableAppendCompletion , BuiltinTableAppendNotify , DeferredOp , GroupCommitPermit ,
@@ -2270,30 +2271,85 @@ impl Coordinator {
22702271 }
22712272 }
22722273
2273- /// Evaluates the scoped overrides for freshly-created objects from explicit
2274- /// eval contexts and returns an [`Op::UpdateScopedSystemParameters`] to fold
2275- /// into the same transaction that creates them.
2274+ /// Evaluates scoped overrides for objects created by `ops` and returns an
2275+ /// [`Op::UpdateScopedSystemParameters`] to fold into the same transaction.
22762276 ///
2277- /// The objects are not yet in the catalog, so the contexts are built from
2278- /// plan data and pre-allocated ids. Folding the op into the create
2279- /// transaction makes its committed diff drive the replica-scoped controller
2280- /// push, as a catalog implication, before `create_replica`. A new replica's
2281- /// first configuration then carries its overrides rather than the env-wide
2282- /// values. Render-frozen flags (e.g. the column-paged batcher, chosen at
2283- /// arrangement-build time) make a later push too late, which is why this
2284- /// happens in the create transaction rather than the next sync tick.
2277+ /// The objects are not yet in the catalog, so this derives their contexts
2278+ /// from the concrete create ops and pre-allocated ids. Centralizing the fold
2279+ /// here makes create-time configuration an invariant of coordinator-applied
2280+ /// catalog ops, independent of which component produced them. The committed
2281+ /// diff drives the replica-scoped controller push before `create_replica`.
2282+ /// Render-frozen flags make a later push too late.
22852283 ///
2286- /// Returns `None` when the shared frontend is not yet installed (e.g. before
2287- /// LaunchDarkly connects), or when no override applies. The new objects then
2288- /// resolve to the environment-wide value, and the periodic sync loop remains
2289- /// the authoritative full-state reconciler.
2284+ /// Returns `None` when no scoped object is created or the shared frontend is
2285+ /// not yet installed. An installed frontend produces an op even when no
2286+ /// override applies, so a final DDL-transaction evaluation can clear a value
2287+ /// staged by an earlier statement. The periodic sync loop remains the
2288+ /// authoritative full-state reconciler.
22902289 ///
22912290 /// [`Op::UpdateScopedSystemParameters`]: crate::catalog::Op::UpdateScopedSystemParameters
2292- fn scoped_overrides_create_op (
2293- & self ,
2294- clusters : & [ ClusterEvalContext ] ,
2295- replicas : & [ ReplicaEvalContext ] ,
2296- ) -> Option < crate :: catalog:: Op > {
2291+ fn scoped_overrides_create_op ( & self , ops : & [ crate :: catalog:: Op ] ) -> Option < crate :: catalog:: Op > {
2292+ let mut created_clusters = BTreeMap :: new ( ) ;
2293+ let mut clusters = Vec :: new ( ) ;
2294+ for op in ops {
2295+ let crate :: catalog:: Op :: CreateCluster { id, name, .. } = op else {
2296+ continue ;
2297+ } ;
2298+ let cluster = ClusterScopeContext {
2299+ id : id. to_string ( ) ,
2300+ name : name. clone ( ) ,
2301+ is_builtin : id. is_system ( ) ,
2302+ } ;
2303+ created_clusters. insert ( * id, cluster. clone ( ) ) ;
2304+ clusters. push ( ClusterEvalContext {
2305+ cluster_id : * id,
2306+ cluster,
2307+ } ) ;
2308+ }
2309+
2310+ let mut replicas = Vec :: new ( ) ;
2311+ for op in ops {
2312+ let crate :: catalog:: Op :: CreateClusterReplica {
2313+ cluster_id,
2314+ replica_id,
2315+ name,
2316+ config,
2317+ ..
2318+ } = op
2319+ else {
2320+ continue ;
2321+ } ;
2322+ let ReplicaLocation :: Managed ( location) = & config. location else {
2323+ continue ;
2324+ } ;
2325+ let cluster = created_clusters. get ( cluster_id) . cloned ( ) . or_else ( || {
2326+ self . catalog ( )
2327+ . try_get_cluster ( * cluster_id)
2328+ . map ( |cluster| ClusterScopeContext {
2329+ id : cluster_id. to_string ( ) ,
2330+ name : cluster. name . clone ( ) ,
2331+ is_builtin : cluster_id. is_system ( ) ,
2332+ } )
2333+ } ) ?;
2334+ replicas. push ( ReplicaEvalContext {
2335+ cluster_id : * cluster_id,
2336+ replica_id : * replica_id,
2337+ replica : ReplicaScopeContext {
2338+ id : replica_id. to_string ( ) ,
2339+ name : name. clone ( ) ,
2340+ is_builtin : cluster_id. is_system ( ) ,
2341+ size : location. size . clone ( ) ,
2342+ size_family : location. allocation . family ( ) . to_string ( ) ,
2343+ cluster_id : cluster_id. to_string ( ) ,
2344+ cluster_name : cluster. name . clone ( ) ,
2345+ } ,
2346+ cluster,
2347+ } ) ;
2348+ }
2349+
2350+ if clusters. is_empty ( ) && replicas. is_empty ( ) {
2351+ return None ;
2352+ }
22972353 let frontend = self . scoped_frontend . clone ( ) ?;
22982354 let catalog = self . catalog ( ) ;
22992355 let system_config = catalog. system_config ( ) ;
@@ -2315,19 +2371,15 @@ impl Coordinator {
23152371 let mut evaluated = ScopedParameters :: default ( ) ;
23162372 if !cluster_param_names. is_empty ( ) && !clusters. is_empty ( ) {
23172373 evaluated. cluster =
2318- frontend. pull_cluster_overrides ( & params, & cluster_param_names, clusters) ;
2374+ frontend. pull_cluster_overrides ( & params, & cluster_param_names, & clusters) ;
23192375 }
23202376 if !replica_param_names. is_empty ( ) && !replicas. is_empty ( ) {
23212377 evaluated. replica =
2322- frontend. pull_replica_overrides ( & params, & replica_param_names, replicas) ;
2378+ frontend. pull_replica_overrides ( & params, & replica_param_names, & replicas) ;
23232379 }
2324- if evaluated. is_empty ( ) {
2325- return None ;
2326- }
2327-
2328- // Prune only within the objects being created. They have no prior rows,
2329- // so nothing is removed, and this op never touches another object whose
2330- // override a concurrent reconcile may be writing.
2380+ // Prune only within the objects this transaction creates. A later
2381+ // statement in a DDL transaction can replace an earlier folded value,
2382+ // but this never touches an unrelated object's override.
23312383 let prune_scope = ScopedParametersScope {
23322384 clusters : clusters. iter ( ) . map ( |cluster| cluster. cluster_id ) . collect ( ) ,
23332385 replicas : replicas. iter ( ) . map ( |replica| replica. replica_id ) . collect ( ) ,
0 commit comments