@@ -70,6 +70,7 @@ use crate::catalog::{
7070 system_object_type_to_audit_object_type,
7171} ;
7272use crate :: coord:: ConnMeta ;
73+ use crate :: coord:: catalog_implications:: parsed_state_updates:: ParsedStateUpdate ;
7374use crate :: coord:: cluster_scheduling:: SchedulingDecision ;
7475use crate :: util:: ResultExt ;
7576
@@ -327,6 +328,8 @@ impl ReplicaCreateDropReason {
327328
328329pub struct TransactionResult {
329330 pub builtin_table_updates : Vec < BuiltinTableUpdate > ,
331+ /// Parsed catalog updates from which we will derive catalog implications.
332+ pub catalog_updates : Vec < ParsedStateUpdate > ,
330333 pub audit_events : Vec < VersionedEvent > ,
331334}
332335
@@ -421,6 +424,7 @@ impl Catalog {
421424
422425 let temporary_ids = self . temporary_ids ( & ops, temporary_drops) ?;
423426 let mut builtin_table_updates = vec ! [ ] ;
427+ let mut catalog_updates = vec ! [ ] ;
424428 let mut audit_events = vec ! [ ] ;
425429 let mut storage = self . storage ( ) . await ;
426430 let mut tx = storage
@@ -435,6 +439,7 @@ impl Catalog {
435439 ops,
436440 temporary_ids,
437441 & mut builtin_table_updates,
442+ & mut catalog_updates,
438443 & mut audit_events,
439444 & mut tx,
440445 & self . state ,
@@ -470,6 +475,7 @@ impl Catalog {
470475
471476 Ok ( TransactionResult {
472477 builtin_table_updates,
478+ catalog_updates,
473479 audit_events,
474480 } )
475481 }
@@ -491,10 +497,40 @@ impl Catalog {
491497 mut ops : Vec < Op > ,
492498 temporary_ids : BTreeSet < CatalogItemId > ,
493499 builtin_table_updates : & mut Vec < BuiltinTableUpdate > ,
500+ parsed_catalog_updates : & mut Vec < ParsedStateUpdate > ,
494501 audit_events : & mut Vec < VersionedEvent > ,
495502 tx : & mut Transaction < ' _ > ,
496503 state : & CatalogState ,
497504 ) -> Result < Option < CatalogState > , AdapterError > {
505+ // We come up with new catalog state, builtin state updates, and parsed
506+ // catalog updates (for deriving catalog implications) in two phases:
507+ //
508+ // 1. We (cow)-clone catalog state as `preliminary_state` and apply ops
509+ // one-by-one. This will give us the full list of updates to apply to
510+ // the catalog, which will allow us to apply it in one batch, which
511+ // in turn will allow the apply machinery to consolidate the updates.
512+ // 2. We do one final apply call with all updates, which gives us the
513+ // final builtin table updates and parsed catalog updates.
514+ //
515+ // The reason is that the loop that is working off ops first does a
516+ // transact_op to derive the state updates for that op, and then calls
517+ // apply_updates on the catalog state. And successive ops might expect
518+ // the catalog state to reflect the modified state _after_ applying
519+ // previous ops.
520+ //
521+ // We want to, however, have one final apply_state that takes all the
522+ // accumulated updates to derive the required controller updates and the
523+ // builtin table updates.
524+ //
525+ // We won't win any DDL throughput benchmarks, but so far that's not
526+ // what we're optimizing for and there would probably be other
527+ // bottlenecks before we hit this one as a bottleneck.
528+ //
529+ // We could work around this by refactoring how the interplay of
530+ // transact_op and apply_updates works, but that's a larger undertaking.
531+ let mut preliminary_state = Cow :: Borrowed ( state) ;
532+
533+ // The final state that we will return, if modified.
498534 let mut state = Cow :: Borrowed ( state) ;
499535
500536 let dry_run_ops = match ops. last ( ) {
@@ -512,6 +548,8 @@ impl Catalog {
512548 let mut storage_collections_to_drop = BTreeSet :: new ( ) ;
513549 let mut storage_collections_to_register = BTreeMap :: new ( ) ;
514550
551+ let mut updates = Vec :: new ( ) ;
552+
515553 for op in ops {
516554 let ( weird_builtin_table_update, temporary_item_updates) = Self :: transact_op (
517555 oracle_write_ts,
@@ -520,7 +558,7 @@ impl Catalog {
520558 & temporary_ids,
521559 audit_events,
522560 tx,
523- & * state ,
561+ & * preliminary_state ,
524562 & mut storage_collections_to_create,
525563 & mut storage_collections_to_drop,
526564 & mut storage_collections_to_register,
@@ -543,25 +581,35 @@ impl Catalog {
543581 // separately for updating state and builtin tables.
544582 // TODO(jkosh44) Some more thought needs to be given as to how temporary tables work
545583 // in a multi-subscriber catalog world.
546- let op_id = tx. op_id ( ) . into ( ) ;
584+ let upper = tx. upper ( ) ;
547585 let temporary_item_updates =
548586 temporary_item_updates
549587 . into_iter ( )
550588 . map ( |( item, diff) | StateUpdate {
551589 kind : StateUpdateKind :: TemporaryItem ( item) ,
552- ts : op_id ,
590+ ts : upper ,
553591 diff,
554592 } ) ;
555593
556- let mut updates: Vec < _ > = tx. get_and_commit_op_updates ( ) ;
557- updates. extend ( temporary_item_updates) ;
558- if !updates. is_empty ( ) {
559- let op_builtin_table_updates = state. to_mut ( ) . apply_updates ( updates) ?;
560- let op_builtin_table_updates = state
561- . to_mut ( )
562- . resolve_builtin_table_updates ( op_builtin_table_updates) ;
563- builtin_table_updates. extend ( op_builtin_table_updates) ;
594+ let mut op_updates: Vec < _ > = tx. get_and_commit_op_updates ( ) ;
595+ op_updates. extend ( temporary_item_updates) ;
596+ if !op_updates. is_empty ( ) {
597+ let ( _op_builtin_table_updates, _op_catalog_updates) =
598+ preliminary_state
599+ . to_mut ( )
600+ . apply_updates ( op_updates. clone ( ) ) ?;
564601 }
602+ updates. append ( & mut op_updates) ;
603+ }
604+
605+ if !updates. is_empty ( ) {
606+ let ( op_builtin_table_updates, op_catalog_updates) =
607+ state. to_mut ( ) . apply_updates ( updates. clone ( ) ) ?;
608+ let op_builtin_table_updates = state
609+ . to_mut ( )
610+ . resolve_builtin_table_updates ( op_builtin_table_updates) ;
611+ builtin_table_updates. extend ( op_builtin_table_updates) ;
612+ parsed_catalog_updates. extend ( op_catalog_updates) ;
565613 }
566614
567615 if dry_run_ops. is_empty ( ) {
@@ -578,11 +626,13 @@ impl Catalog {
578626
579627 let updates = tx. get_and_commit_op_updates ( ) ;
580628 if !updates. is_empty ( ) {
581- let op_builtin_table_updates = state. to_mut ( ) . apply_updates ( updates) ?;
629+ let ( op_builtin_table_updates, op_catalog_updates) =
630+ state. to_mut ( ) . apply_updates ( updates. clone ( ) ) ?;
582631 let op_builtin_table_updates = state
583632 . to_mut ( )
584633 . resolve_builtin_table_updates ( op_builtin_table_updates) ;
585634 builtin_table_updates. extend ( op_builtin_table_updates) ;
635+ parsed_catalog_updates. extend ( op_catalog_updates) ;
586636 }
587637
588638 match state {
@@ -1146,15 +1196,31 @@ impl Catalog {
11461196 ) ) ) ;
11471197 }
11481198 let oid = tx. allocate_oid ( & temporary_oids) ?;
1199+
1200+ let schema_id = name. qualifiers . schema_spec . clone ( ) . into ( ) ;
1201+ let item_type = item. typ ( ) ;
1202+ let ( create_sql, global_id, versions) = item. to_serialized ( ) ;
1203+
11491204 let item = TemporaryItem {
11501205 id,
11511206 oid,
1152- name : name. clone ( ) ,
1153- item : item. clone ( ) ,
1207+ global_id,
1208+ schema_id,
1209+ name : name. item . clone ( ) ,
1210+ create_sql,
1211+ conn_id : item. conn_id ( ) . cloned ( ) ,
11541212 owner_id,
1155- privileges : PrivilegeMap :: from_mz_acl_items ( privileges) ,
1213+ privileges : privileges. clone ( ) ,
1214+ extra_versions : versions,
11561215 } ;
11571216 temporary_item_updates. push ( ( item, StateDiff :: Addition ) ) ;
1217+
1218+ info ! (
1219+ "create temporary {} {} ({})" ,
1220+ item_type,
1221+ state. resolve_full_name( & name, None ) ,
1222+ id
1223+ ) ;
11581224 } else {
11591225 if let Some ( temp_id) =
11601226 item. uses ( )
0 commit comments