Skip to main content

mz_catalog/durable/
objects.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! The current types used to represent catalog data stored on disk. These objects generally fall
11//! into two categories.
12//!
13//! The key-value objects are a one-to-one mapping of the protobuf objects used to save catalog
14//! data durably. They can be converted to and from protobuf via the [`mz_proto::RustType`] trait.
15//! These objects should not be exposed anywhere outside the [`crate::durable`] module.
16//!
17//! The other type of objects combine the information from keys and values into a single struct,
18//! but are still a direct representation of the data stored on disk. They can be converted to and
19//! from the key-value objects via the [`DurableType`] trait. These objects are used to pass
20//! information to other modules in this crate and other catalog related code.
21//!
22//! All non-catalog code should interact with the objects in [`crate::memory::objects`] and never
23//! directly interact with the objects in this module.
24//!
25//! As an example, [`DatabaseKey`] and [`DatabaseValue`] are key-value objects, while [`Database`]
26//! is the non-key-value counterpart.
27
28pub mod serialization;
29pub(crate) mod state_update;
30
31use std::cmp::Ordering;
32use std::collections::BTreeMap;
33use std::time::Duration;
34
35use mz_audit_log::VersionedEvent;
36use mz_controller::clusters::ReplicaLogging;
37use mz_controller_types::{ClusterId, ReplicaId};
38use mz_persist_types::ShardId;
39use mz_repr::adt::mz_acl_item::{AclMode, MzAclItem};
40use mz_repr::network_policy_id::NetworkPolicyId;
41use mz_repr::role_id::RoleId;
42use mz_repr::{CatalogItemId, GlobalId, RelationVersion};
43use mz_sql::catalog::{
44    CatalogItemType, DefaultPrivilegeAclItem, DefaultPrivilegeObject, ObjectType, RoleAttributes,
45    RoleMembership, RoleVars,
46};
47use mz_sql::names::{CommentObjectId, DatabaseId, SchemaId};
48use mz_sql::plan::{AutoScalingStrategy, ClusterSchedule, NetworkPolicyRule, OnTimeoutAction};
49#[cfg(test)]
50use proptest_derive::Arbitrary;
51
52use crate::builtin::RUNTIME_ALTERABLE_FINGERPRINT_SENTINEL;
53use crate::durable::Epoch;
54use crate::durable::objects::serialization::proto;
55
56// Structs used to pass information to outside modules.
57
58/// A trait for representing `Self` as a key-value pair of type
59/// `(Key, Value)` for the purpose of storing this value durably.
60///
61/// To encode a key-value pair, use [`DurableType::into_key_value`].
62///
63/// To decode a key-value pair, use [`DurableType::from_key_value`].
64///
65/// This trait is based on [`RustType`], however it is meant to
66/// convert the types used in [`RustType`] to a more consumable and
67/// condensed type.
68///
69/// [`RustType`]: mz_proto::RustType
70pub trait DurableType: Sized {
71    type Key;
72    type Value;
73
74    /// Consume and convert `Self` into a `(Key, Value)` key-value pair.
75    fn into_key_value(self) -> (Self::Key, Self::Value);
76
77    /// Consume and convert a `(Key, Value)` key-value pair back into a
78    /// `Self` value.
79    fn from_key_value(key: Self::Key, value: Self::Value) -> Self;
80
81    // TODO(jkosh44) Would be great to not clone, since this is always used for lookups which only
82    // needs a reference. In practice, we currently almost always use this method to clone a single
83    // 64-bit integer, so it's not a huge deal.
84    /// Produce a `Key` from self. This may involve cloning/copying required fields.
85    fn key(&self) -> Self::Key;
86}
87
88#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
89pub struct Database {
90    pub id: DatabaseId,
91    pub oid: u32,
92    pub name: String,
93    pub owner_id: RoleId,
94    pub privileges: Vec<MzAclItem>,
95}
96
97impl DurableType for Database {
98    type Key = DatabaseKey;
99    type Value = DatabaseValue;
100
101    fn into_key_value(self) -> (Self::Key, Self::Value) {
102        (
103            DatabaseKey { id: self.id },
104            DatabaseValue {
105                oid: self.oid,
106                name: self.name,
107                owner_id: self.owner_id,
108                privileges: self.privileges,
109            },
110        )
111    }
112
113    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
114        Self {
115            id: key.id,
116            oid: value.oid,
117            name: value.name,
118            owner_id: value.owner_id,
119            privileges: value.privileges,
120        }
121    }
122
123    fn key(&self) -> Self::Key {
124        DatabaseKey { id: self.id }
125    }
126}
127
128#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
129pub struct Schema {
130    pub id: SchemaId,
131    pub oid: u32,
132    pub name: String,
133    pub database_id: Option<DatabaseId>,
134    pub owner_id: RoleId,
135    pub privileges: Vec<MzAclItem>,
136}
137
138impl DurableType for Schema {
139    type Key = SchemaKey;
140    type Value = SchemaValue;
141
142    fn into_key_value(self) -> (Self::Key, Self::Value) {
143        (
144            SchemaKey { id: self.id },
145            SchemaValue {
146                oid: self.oid,
147                database_id: self.database_id,
148                name: self.name,
149                owner_id: self.owner_id,
150                privileges: self.privileges,
151            },
152        )
153    }
154
155    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
156        Self {
157            id: key.id,
158            oid: value.oid,
159            name: value.name,
160            database_id: value.database_id,
161            owner_id: value.owner_id,
162            privileges: value.privileges,
163        }
164    }
165
166    fn key(&self) -> Self::Key {
167        SchemaKey { id: self.id }
168    }
169}
170
171#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
172pub struct Role {
173    pub id: RoleId,
174    pub oid: u32,
175    pub name: String,
176    pub attributes: RoleAttributes,
177    pub membership: RoleMembership,
178    pub vars: RoleVars,
179}
180
181impl DurableType for Role {
182    type Key = RoleKey;
183    type Value = RoleValue;
184
185    fn into_key_value(self) -> (Self::Key, Self::Value) {
186        (
187            RoleKey { id: self.id },
188            RoleValue {
189                oid: self.oid,
190                name: self.name,
191                attributes: self.attributes,
192                membership: self.membership,
193                vars: self.vars,
194            },
195        )
196    }
197
198    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
199        Self {
200            id: key.id,
201            oid: value.oid,
202            name: value.name,
203            attributes: value.attributes,
204            membership: value.membership,
205            vars: value.vars,
206        }
207    }
208
209    fn key(&self) -> Self::Key {
210        RoleKey { id: self.id }
211    }
212}
213
214#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
215pub struct RoleAuth {
216    pub role_id: RoleId,
217    pub password_hash: Option<String>,
218    pub updated_at: u64,
219}
220
221impl DurableType for RoleAuth {
222    type Key = RoleAuthKey;
223    type Value = RoleAuthValue;
224
225    fn into_key_value(self) -> (Self::Key, Self::Value) {
226        (
227            RoleAuthKey {
228                role_id: self.role_id,
229            },
230            RoleAuthValue {
231                password_hash: self.password_hash,
232                updated_at: self.updated_at,
233            },
234        )
235    }
236
237    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
238        Self {
239            role_id: key.role_id,
240            password_hash: value.password_hash,
241            updated_at: value.updated_at,
242        }
243    }
244
245    fn key(&self) -> Self::Key {
246        RoleAuthKey {
247            role_id: self.role_id,
248        }
249    }
250}
251
252#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
253pub struct NetworkPolicy {
254    pub name: String,
255    pub id: NetworkPolicyId,
256    pub oid: u32,
257    pub rules: Vec<NetworkPolicyRule>,
258    pub owner_id: RoleId,
259    pub(crate) privileges: Vec<MzAclItem>,
260}
261
262impl DurableType for NetworkPolicy {
263    type Key = NetworkPolicyKey;
264    type Value = NetworkPolicyValue;
265
266    fn into_key_value(self) -> (Self::Key, Self::Value) {
267        (
268            NetworkPolicyKey { id: self.id },
269            NetworkPolicyValue {
270                oid: self.oid,
271                name: self.name,
272                rules: self.rules,
273                owner_id: self.owner_id,
274                privileges: self.privileges,
275            },
276        )
277    }
278
279    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
280        Self {
281            id: key.id,
282            oid: value.oid,
283            name: value.name,
284            rules: value.rules,
285            owner_id: value.owner_id,
286            privileges: value.privileges,
287        }
288    }
289
290    fn key(&self) -> Self::Key {
291        NetworkPolicyKey { id: self.id }
292    }
293}
294
295#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
296pub struct Cluster {
297    pub id: ClusterId,
298    pub name: String,
299    pub owner_id: RoleId,
300    pub privileges: Vec<MzAclItem>,
301    pub config: ClusterConfig,
302}
303
304impl DurableType for Cluster {
305    type Key = ClusterKey;
306    type Value = ClusterValue;
307
308    fn into_key_value(self) -> (Self::Key, Self::Value) {
309        (
310            ClusterKey { id: self.id },
311            ClusterValue {
312                name: self.name,
313                owner_id: self.owner_id,
314                privileges: self.privileges,
315                config: self.config,
316            },
317        )
318    }
319
320    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
321        Self {
322            id: key.id,
323            name: value.name,
324            owner_id: value.owner_id,
325            privileges: value.privileges,
326            config: value.config,
327        }
328    }
329
330    fn key(&self) -> Self::Key {
331        ClusterKey { id: self.id }
332    }
333}
334
335#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
336pub struct ClusterConfig {
337    pub variant: ClusterVariant,
338    pub workload_class: Option<String>,
339}
340
341#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
342pub enum ClusterVariant {
343    Managed(ClusterVariantManaged),
344    Unmanaged,
345}
346
347#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
348pub struct ClusterVariantManaged {
349    pub size: String,
350    pub availability_zones: Vec<String>,
351    pub logging: ReplicaLogging,
352    pub replication_factor: u32,
353    pub optimizer_feature_overrides: BTreeMap<String, String>,
354    pub schedule: ClusterSchedule,
355    /// User-configured autoscaling policy, distinct from the in-flight runtime
356    /// records below.
357    pub auto_scaling_strategy: Option<AutoScalingStrategy>,
358    /// Latest graceful reconfiguration record, if one has been written.
359    pub reconfiguration: Option<ReconfigurationState>,
360    /// In-flight hydration burst the controller is running.
361    pub burst: Option<BurstState>,
362}
363
364/// The latest graceful reconfiguration: the config shape the cluster is moving
365/// to or most recently moved toward, plus its deadline and terminal state.
366///
367/// `ALTER` writes this record with [`ReconfigurationStatus::InProgress`] and
368/// returns. The realized config (`cluster.size`, ...) is advanced by the
369/// controller only at cut-over. When the reconfiguration settles, the controller
370/// retains the record with a terminal status so readers can inspect the latest
371/// outcome without reconstructing it from the audit log.
372#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
373pub struct ReconfigurationState {
374    pub target: ReconfigurationTarget,
375    pub deadline: mz_repr::Timestamp,
376    /// The action the controller applies if `deadline` passes before the
377    /// target hydrates. Success takes precedence: a hydrated target cuts over
378    /// regardless of this field.
379    pub on_timeout: OnTimeoutAction,
380    pub status: ReconfigurationStatus,
381}
382
383/// The lifecycle status of the latest graceful reconfiguration.
384#[derive(Clone, Copy, Debug, PartialOrd, PartialEq, Eq, Ord)]
385pub enum ReconfigurationStatus {
386    /// The controller is converging the cluster onto the target shape.
387    InProgress,
388    /// The realized config reached the target shape.
389    Finalized,
390    /// The deadline fired under rollback and the realized config stayed put.
391    TimedOut,
392    /// The user retargeted the reconfiguration back to the realized shape.
393    Cancelled,
394    /// The controller could not create the target replicas within the budget.
395    ResourceExhausted,
396}
397
398impl ReconfigurationState {
399    /// Whether this record should still drive target-replica convergence.
400    pub fn is_in_progress(&self) -> bool {
401        matches!(self.status, ReconfigurationStatus::InProgress)
402    }
403}
404
405/// The full config shape a reconfiguration is moving the cluster to, so a
406/// combined size + replication-factor + availability-zone change is one record.
407#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
408pub struct ReconfigurationTarget {
409    pub size: String,
410    pub replication_factor: u32,
411    pub availability_zones: Vec<String>,
412    pub logging: ReplicaLogging,
413}
414
415/// An active hydration burst the controller is running.
416#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
417pub struct BurstState {
418    pub burst_size: String,
419    pub linger_duration: Duration,
420    /// When the steady-state replicas were first observed hydrated. Absent
421    /// until that observation; the linger countdown runs from this point.
422    pub steady_hydrated_at: Option<mz_repr::Timestamp>,
423}
424
425#[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq)]
426pub struct IntrospectionSourceIndex {
427    pub cluster_id: ClusterId,
428    pub name: String,
429    pub item_id: CatalogItemId,
430    pub index_id: GlobalId,
431    pub oid: u32,
432}
433
434impl DurableType for IntrospectionSourceIndex {
435    type Key = ClusterIntrospectionSourceIndexKey;
436    type Value = ClusterIntrospectionSourceIndexValue;
437
438    fn into_key_value(self) -> (Self::Key, Self::Value) {
439        (
440            ClusterIntrospectionSourceIndexKey {
441                cluster_id: self.cluster_id,
442                name: self.name,
443            },
444            ClusterIntrospectionSourceIndexValue {
445                catalog_id: self
446                    .item_id
447                    .try_into()
448                    .expect("cluster introspection source index mapping must be an Introspection Source Index ID"),
449                global_id: self
450                    .index_id
451                    .try_into()
452                    .expect("cluster introspection source index mapping must be a Introspection Source Index ID"),
453                oid: self.oid,
454            },
455        )
456    }
457
458    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
459        Self {
460            cluster_id: key.cluster_id,
461            name: key.name,
462            item_id: value.catalog_id.into(),
463            index_id: value.global_id.into(),
464            oid: value.oid,
465        }
466    }
467
468    fn key(&self) -> Self::Key {
469        ClusterIntrospectionSourceIndexKey {
470            cluster_id: self.cluster_id,
471            name: self.name.clone(),
472        }
473    }
474}
475
476#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
477pub struct ClusterReplica {
478    pub cluster_id: ClusterId,
479    pub replica_id: ReplicaId,
480    pub name: String,
481    pub config: ReplicaConfig,
482    pub owner_id: RoleId,
483}
484
485impl DurableType for ClusterReplica {
486    type Key = ClusterReplicaKey;
487    type Value = ClusterReplicaValue;
488
489    fn into_key_value(self) -> (Self::Key, Self::Value) {
490        (
491            ClusterReplicaKey {
492                id: self.replica_id,
493            },
494            ClusterReplicaValue {
495                cluster_id: self.cluster_id,
496                name: self.name,
497                config: self.config,
498                owner_id: self.owner_id,
499            },
500        )
501    }
502
503    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
504        Self {
505            cluster_id: value.cluster_id,
506            replica_id: key.id,
507            name: value.name,
508            config: value.config,
509            owner_id: value.owner_id,
510        }
511    }
512
513    fn key(&self) -> Self::Key {
514        ClusterReplicaKey {
515            id: self.replica_id,
516        }
517    }
518}
519
520// The on-disk replica configuration does not match the in-memory replica configuration, so we need
521// separate structs. As of writing this comment, it is mainly due to the fact that we don't persist
522// the replica allocation.
523#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
524pub struct ReplicaConfig {
525    pub location: ReplicaLocation,
526    pub logging: ReplicaLogging,
527}
528
529impl From<mz_controller::clusters::ReplicaConfig> for ReplicaConfig {
530    fn from(config: mz_controller::clusters::ReplicaConfig) -> Self {
531        Self {
532            location: config.location.into(),
533            logging: config.compute.logging,
534        }
535    }
536}
537
538#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
539pub enum ReplicaLocation {
540    Unmanaged {
541        storagectl_addrs: Vec<String>,
542        computectl_addrs: Vec<String>,
543    },
544    Managed {
545        size: String,
546        /// The availability zones the replica was provisioned under.
547        ///
548        /// For a replica of a managed cluster this is the cluster's
549        /// `AVAILABILITY ZONES` pool at provision time; the cluster controller
550        /// compares it against a cluster's target `availability_zones` to tell
551        /// realized- from target-shape replicas (including an
552        /// `AVAILABILITY ZONES` divergence). For a replica of an unmanaged
553        /// cluster it is the user-pinned `AVAILABILITY ZONE`, as a zero- or
554        /// one-element list. Empty when no zones constrain placement.
555        availability_zones: Vec<String>,
556        internal: bool,
557        billed_as: Option<String>,
558        pending: bool,
559    },
560}
561
562impl From<mz_controller::clusters::ReplicaLocation> for ReplicaLocation {
563    fn from(loc: mz_controller::clusters::ReplicaLocation) -> Self {
564        match loc {
565            mz_controller::clusters::ReplicaLocation::Unmanaged(
566                mz_controller::clusters::UnmanagedReplicaLocation {
567                    storagectl_addrs,
568                    computectl_addrs,
569                },
570            ) => Self::Unmanaged {
571                storagectl_addrs,
572                computectl_addrs,
573            },
574            mz_controller::clusters::ReplicaLocation::Managed(
575                mz_controller::clusters::ManagedReplicaLocation {
576                    allocation: _,
577                    size,
578                    availability_zones,
579                    billed_as,
580                    internal,
581                    pending,
582                },
583            ) => ReplicaLocation::Managed {
584                size,
585                availability_zones,
586                internal,
587                billed_as,
588                pending,
589            },
590        }
591    }
592}
593
594#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
595pub struct Item {
596    pub id: CatalogItemId,
597    pub oid: u32,
598    pub global_id: GlobalId,
599    pub schema_id: SchemaId,
600    pub name: String,
601    pub create_sql: String,
602    pub owner_id: RoleId,
603    pub privileges: Vec<MzAclItem>,
604    pub extra_versions: BTreeMap<RelationVersion, GlobalId>,
605}
606
607impl Item {
608    pub fn item_type(&self) -> CatalogItemType {
609        item_type(&self.create_sql)
610    }
611}
612
613impl DurableType for Item {
614    type Key = ItemKey;
615    type Value = ItemValue;
616
617    fn into_key_value(self) -> (Self::Key, Self::Value) {
618        (
619            ItemKey { id: self.id },
620            ItemValue {
621                oid: self.oid,
622                global_id: self.global_id,
623                schema_id: self.schema_id,
624                name: self.name,
625                create_sql: self.create_sql,
626                owner_id: self.owner_id,
627                privileges: self.privileges,
628                extra_versions: self.extra_versions,
629            },
630        )
631    }
632
633    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
634        Self {
635            id: key.id,
636            oid: value.oid,
637            global_id: value.global_id,
638            schema_id: value.schema_id,
639            name: value.name,
640            create_sql: value.create_sql,
641            owner_id: value.owner_id,
642            privileges: value.privileges,
643            extra_versions: value.extra_versions,
644        }
645    }
646
647    fn key(&self) -> Self::Key {
648        ItemKey { id: self.id }
649    }
650}
651
652#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
653pub struct SourceReferences {
654    pub source_id: CatalogItemId,
655    pub updated_at: u64,
656    pub references: Vec<SourceReference>,
657}
658
659#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
660#[cfg_attr(test, derive(Arbitrary))]
661pub struct SourceReference {
662    pub name: String,
663    pub namespace: Option<String>,
664    pub columns: Vec<String>,
665}
666
667impl DurableType for SourceReferences {
668    type Key = SourceReferencesKey;
669    type Value = SourceReferencesValue;
670
671    fn into_key_value(self) -> (Self::Key, Self::Value) {
672        (
673            SourceReferencesKey {
674                source_id: self.source_id,
675            },
676            SourceReferencesValue {
677                updated_at: self.updated_at,
678                references: self.references,
679            },
680        )
681    }
682
683    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
684        Self {
685            source_id: key.source_id,
686            updated_at: value.updated_at,
687            references: value.references,
688        }
689    }
690
691    fn key(&self) -> Self::Key {
692        SourceReferencesKey {
693            source_id: self.source_id,
694        }
695    }
696}
697
698/// A newtype wrapper for [`CatalogItemId`] that is only for the "system" namespace.
699#[derive(Debug, Copy, Clone, Ord, PartialOrd, PartialEq, Eq)]
700pub struct SystemCatalogItemId(u64);
701
702impl TryFrom<CatalogItemId> for SystemCatalogItemId {
703    type Error = &'static str;
704
705    fn try_from(val: CatalogItemId) -> Result<Self, Self::Error> {
706        match val {
707            CatalogItemId::System(x) => Ok(SystemCatalogItemId(x)),
708            CatalogItemId::IntrospectionSourceIndex(_) => Err("introspection_source_index"),
709            CatalogItemId::User(_) => Err("user"),
710            CatalogItemId::Transient(_) => Err("transient"),
711        }
712    }
713}
714
715impl From<SystemCatalogItemId> for CatalogItemId {
716    fn from(val: SystemCatalogItemId) -> Self {
717        CatalogItemId::System(val.0)
718    }
719}
720
721/// A newtype wrapper for [`CatalogItemId`] that is only for the "introspection source index" namespace.
722#[derive(Debug, Copy, Clone, Ord, PartialOrd, PartialEq, Eq)]
723pub struct IntrospectionSourceIndexCatalogItemId(u64);
724
725impl TryFrom<CatalogItemId> for IntrospectionSourceIndexCatalogItemId {
726    type Error = &'static str;
727
728    fn try_from(val: CatalogItemId) -> Result<Self, Self::Error> {
729        match val {
730            CatalogItemId::System(_) => Err("system"),
731            CatalogItemId::IntrospectionSourceIndex(x) => {
732                Ok(IntrospectionSourceIndexCatalogItemId(x))
733            }
734            CatalogItemId::User(_) => Err("user"),
735            CatalogItemId::Transient(_) => Err("transient"),
736        }
737    }
738}
739
740impl From<IntrospectionSourceIndexCatalogItemId> for CatalogItemId {
741    fn from(val: IntrospectionSourceIndexCatalogItemId) -> Self {
742        CatalogItemId::IntrospectionSourceIndex(val.0)
743    }
744}
745
746/// A newtype wrapper for [`GlobalId`] that is only for the "system" namespace.
747#[derive(Debug, Copy, Clone, Ord, PartialOrd, PartialEq, Eq)]
748pub struct SystemGlobalId(u64);
749
750impl TryFrom<GlobalId> for SystemGlobalId {
751    type Error = &'static str;
752
753    fn try_from(val: GlobalId) -> Result<Self, Self::Error> {
754        match val {
755            GlobalId::System(x) => Ok(SystemGlobalId(x)),
756            GlobalId::IntrospectionSourceIndex(_) => Err("introspection_source_index"),
757            GlobalId::User(_) => Err("user"),
758            GlobalId::Transient(_) => Err("transient"),
759            GlobalId::Explain => Err("explain"),
760        }
761    }
762}
763
764impl From<SystemGlobalId> for GlobalId {
765    fn from(val: SystemGlobalId) -> Self {
766        GlobalId::System(val.0)
767    }
768}
769
770/// A newtype wrapper for [`GlobalId`] that is only for the "introspection source index" namespace.
771#[derive(Debug, Copy, Clone, Ord, PartialOrd, PartialEq, Eq)]
772pub struct IntrospectionSourceIndexGlobalId(u64);
773
774impl TryFrom<GlobalId> for IntrospectionSourceIndexGlobalId {
775    type Error = &'static str;
776
777    fn try_from(val: GlobalId) -> Result<Self, Self::Error> {
778        match val {
779            GlobalId::System(_) => Err("system"),
780            GlobalId::IntrospectionSourceIndex(x) => Ok(IntrospectionSourceIndexGlobalId(x)),
781            GlobalId::User(_) => Err("user"),
782            GlobalId::Transient(_) => Err("transient"),
783            GlobalId::Explain => Err("explain"),
784        }
785    }
786}
787
788impl From<IntrospectionSourceIndexGlobalId> for GlobalId {
789    fn from(val: IntrospectionSourceIndexGlobalId) -> Self {
790        GlobalId::IntrospectionSourceIndex(val.0)
791    }
792}
793
794#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
795pub struct SystemObjectDescription {
796    pub schema_name: String,
797    pub object_type: CatalogItemType,
798    pub object_name: String,
799}
800
801#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
802pub struct SystemObjectUniqueIdentifier {
803    pub catalog_id: CatalogItemId,
804    pub global_id: GlobalId,
805    pub fingerprint: String,
806}
807
808impl SystemObjectUniqueIdentifier {
809    pub fn runtime_alterable(&self) -> bool {
810        self.fingerprint == RUNTIME_ALTERABLE_FINGERPRINT_SENTINEL
811    }
812}
813
814/// Functions can share the same name as any other catalog item type
815/// within a given schema.
816/// For example, a function can have the same name as a type, e.g.
817/// 'date'.
818/// As such, system objects are keyed in the catalog storage by the
819/// tuple (schema_name, object_type, object_name), which is guaranteed
820/// to be unique.
821#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
822pub struct SystemObjectMapping {
823    pub description: SystemObjectDescription,
824    pub unique_identifier: SystemObjectUniqueIdentifier,
825}
826
827impl DurableType for SystemObjectMapping {
828    type Key = GidMappingKey;
829    type Value = GidMappingValue;
830
831    fn into_key_value(self) -> (Self::Key, Self::Value) {
832        (
833            GidMappingKey {
834                schema_name: self.description.schema_name,
835                object_type: self.description.object_type,
836                object_name: self.description.object_name,
837            },
838            GidMappingValue {
839                catalog_id: self
840                    .unique_identifier
841                    .catalog_id
842                    .try_into()
843                    .expect("catalog_id to be in the system namespace"),
844                global_id: self
845                    .unique_identifier
846                    .global_id
847                    .try_into()
848                    .expect("collection_id to be in the system namespace"),
849                fingerprint: self.unique_identifier.fingerprint,
850            },
851        )
852    }
853
854    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
855        Self {
856            description: SystemObjectDescription {
857                schema_name: key.schema_name,
858                object_type: key.object_type,
859                object_name: key.object_name,
860            },
861            unique_identifier: SystemObjectUniqueIdentifier {
862                catalog_id: value.catalog_id.into(),
863                global_id: value.global_id.into(),
864                fingerprint: value.fingerprint,
865            },
866        }
867    }
868
869    fn key(&self) -> Self::Key {
870        GidMappingKey {
871            schema_name: self.description.schema_name.clone(),
872            object_type: self.description.object_type.clone(),
873            object_name: self.description.object_name.clone(),
874        }
875    }
876}
877
878#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
879pub struct DefaultPrivilege {
880    pub object: DefaultPrivilegeObject,
881    pub acl_item: DefaultPrivilegeAclItem,
882}
883
884impl DurableType for DefaultPrivilege {
885    type Key = DefaultPrivilegesKey;
886    type Value = DefaultPrivilegesValue;
887
888    fn into_key_value(self) -> (Self::Key, Self::Value) {
889        (
890            DefaultPrivilegesKey {
891                role_id: self.object.role_id,
892                database_id: self.object.database_id,
893                schema_id: self.object.schema_id,
894                object_type: self.object.object_type,
895                grantee: self.acl_item.grantee,
896            },
897            DefaultPrivilegesValue {
898                privileges: self.acl_item.acl_mode,
899            },
900        )
901    }
902
903    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
904        Self {
905            object: DefaultPrivilegeObject {
906                role_id: key.role_id,
907                database_id: key.database_id,
908                schema_id: key.schema_id,
909                object_type: key.object_type,
910            },
911            acl_item: DefaultPrivilegeAclItem {
912                grantee: key.grantee,
913                acl_mode: value.privileges,
914            },
915        }
916    }
917
918    fn key(&self) -> Self::Key {
919        DefaultPrivilegesKey {
920            role_id: self.object.role_id,
921            database_id: self.object.database_id,
922            schema_id: self.object.schema_id,
923            object_type: self.object.object_type,
924            grantee: self.acl_item.grantee,
925        }
926    }
927}
928
929#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
930pub struct Comment {
931    pub object_id: CommentObjectId,
932    pub sub_component: Option<usize>,
933    pub comment: String,
934}
935
936impl DurableType for Comment {
937    type Key = CommentKey;
938    type Value = CommentValue;
939
940    fn into_key_value(self) -> (Self::Key, Self::Value) {
941        (
942            CommentKey {
943                object_id: self.object_id,
944                sub_component: self.sub_component,
945            },
946            CommentValue {
947                comment: self.comment,
948            },
949        )
950    }
951
952    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
953        Self {
954            object_id: key.object_id,
955            sub_component: key.sub_component,
956            comment: value.comment,
957        }
958    }
959
960    fn key(&self) -> Self::Key {
961        CommentKey {
962            object_id: self.object_id,
963            sub_component: self.sub_component,
964        }
965    }
966}
967
968#[derive(Debug, Clone, PartialEq, Eq)]
969pub struct IdAlloc {
970    pub name: String,
971    pub next_id: u64,
972}
973
974impl DurableType for IdAlloc {
975    type Key = IdAllocKey;
976    type Value = IdAllocValue;
977
978    fn into_key_value(self) -> (Self::Key, Self::Value) {
979        (
980            IdAllocKey { name: self.name },
981            IdAllocValue {
982                next_id: self.next_id,
983            },
984        )
985    }
986
987    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
988        Self {
989            name: key.name,
990            next_id: value.next_id,
991        }
992    }
993
994    fn key(&self) -> Self::Key {
995        IdAllocKey {
996            name: self.name.clone(),
997        }
998    }
999}
1000
1001#[derive(Debug, Clone, PartialEq, Eq)]
1002pub struct Config {
1003    pub key: String,
1004    pub value: u64,
1005}
1006
1007impl DurableType for Config {
1008    type Key = ConfigKey;
1009    type Value = ConfigValue;
1010
1011    fn into_key_value(self) -> (Self::Key, Self::Value) {
1012        (
1013            ConfigKey { key: self.key },
1014            ConfigValue { value: self.value },
1015        )
1016    }
1017
1018    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
1019        Self {
1020            key: key.key,
1021            value: value.value,
1022        }
1023    }
1024
1025    fn key(&self) -> Self::Key {
1026        ConfigKey {
1027            key: self.key.clone(),
1028        }
1029    }
1030}
1031
1032#[derive(Debug, Clone)]
1033pub struct Setting {
1034    pub name: String,
1035    pub value: String,
1036}
1037
1038impl DurableType for Setting {
1039    type Key = SettingKey;
1040    type Value = SettingValue;
1041
1042    fn into_key_value(self) -> (Self::Key, Self::Value) {
1043        (
1044            SettingKey { name: self.name },
1045            SettingValue { value: self.value },
1046        )
1047    }
1048
1049    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
1050        Self {
1051            name: key.name,
1052            value: value.value,
1053        }
1054    }
1055
1056    fn key(&self) -> Self::Key {
1057        SettingKey {
1058            name: self.name.clone(),
1059        }
1060    }
1061}
1062
1063#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
1064pub struct SystemConfiguration {
1065    pub name: String,
1066    pub value: String,
1067}
1068
1069impl DurableType for SystemConfiguration {
1070    type Key = ServerConfigurationKey;
1071    type Value = ServerConfigurationValue;
1072
1073    fn into_key_value(self) -> (Self::Key, Self::Value) {
1074        (
1075            ServerConfigurationKey { name: self.name },
1076            ServerConfigurationValue { value: self.value },
1077        )
1078    }
1079
1080    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
1081        Self {
1082            name: key.name,
1083            value: value.value,
1084        }
1085    }
1086
1087    fn key(&self) -> Self::Key {
1088        ServerConfigurationKey {
1089            name: self.name.clone(),
1090        }
1091    }
1092}
1093
1094/// A single cluster-coherent scoped system-parameter override: parameter `name`
1095/// has value `value` on the cluster `cluster_id`.
1096///
1097/// This is the in-memory shape of the durable `cluster_system_configurations`
1098/// collection that backs cluster-coherent scoped feature flags. The collection
1099/// — keyed by `(ClusterId, name)` — is the analog of `system_configurations`
1100/// (`ALTER SYSTEM`), but for per-cluster values; it is written solely by the
1101/// system-parameter sync loop, and the coordinator's in-memory working copy is
1102/// maintained from it on every catalog update.
1103#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
1104pub struct ClusterSystemConfiguration {
1105    pub cluster_id: ClusterId,
1106    pub name: String,
1107    pub value: String,
1108}
1109
1110impl DurableType for ClusterSystemConfiguration {
1111    type Key = ClusterSystemConfigurationKey;
1112    type Value = ClusterSystemConfigurationValue;
1113
1114    fn into_key_value(self) -> (Self::Key, Self::Value) {
1115        (
1116            ClusterSystemConfigurationKey {
1117                cluster_id: self.cluster_id,
1118                name: self.name,
1119            },
1120            ClusterSystemConfigurationValue { value: self.value },
1121        )
1122    }
1123
1124    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
1125        Self {
1126            cluster_id: key.cluster_id,
1127            name: key.name,
1128            value: value.value,
1129        }
1130    }
1131
1132    fn key(&self) -> Self::Key {
1133        ClusterSystemConfigurationKey {
1134            cluster_id: self.cluster_id,
1135            name: self.name.clone(),
1136        }
1137    }
1138}
1139
1140/// A single replica-local scoped system-parameter override: parameter `name`
1141/// has value `value` on the replica `replica_id`.
1142///
1143/// This is the in-memory shape of the durable `replica_system_configurations`
1144/// collection that backs replica-local scoped feature flags. The collection —
1145/// keyed by `(ReplicaId, name)` — is the analog of `system_configurations`
1146/// (`ALTER SYSTEM`), but for per-replica values; it is written solely by the
1147/// system-parameter sync loop, and the coordinator's in-memory working copy is
1148/// maintained from it on every catalog update.
1149#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
1150pub struct ReplicaSystemConfiguration {
1151    pub replica_id: ReplicaId,
1152    pub name: String,
1153    pub value: String,
1154}
1155
1156impl DurableType for ReplicaSystemConfiguration {
1157    type Key = ReplicaSystemConfigurationKey;
1158    type Value = ReplicaSystemConfigurationValue;
1159
1160    fn into_key_value(self) -> (Self::Key, Self::Value) {
1161        (
1162            ReplicaSystemConfigurationKey {
1163                replica_id: self.replica_id,
1164                name: self.name,
1165            },
1166            ReplicaSystemConfigurationValue { value: self.value },
1167        )
1168    }
1169
1170    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
1171        Self {
1172            replica_id: key.replica_id,
1173            name: key.name,
1174            value: value.value,
1175        }
1176    }
1177
1178    fn key(&self) -> Self::Key {
1179        ReplicaSystemConfigurationKey {
1180            replica_id: self.replica_id,
1181            name: self.name.clone(),
1182        }
1183    }
1184}
1185
1186impl DurableType for MzAclItem {
1187    type Key = SystemPrivilegesKey;
1188    type Value = SystemPrivilegesValue;
1189
1190    fn into_key_value(self) -> (Self::Key, Self::Value) {
1191        (
1192            SystemPrivilegesKey {
1193                grantee: self.grantee,
1194                grantor: self.grantor,
1195            },
1196            SystemPrivilegesValue {
1197                acl_mode: self.acl_mode,
1198            },
1199        )
1200    }
1201
1202    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
1203        Self {
1204            grantee: key.grantee,
1205            grantor: key.grantor,
1206            acl_mode: value.acl_mode,
1207        }
1208    }
1209
1210    fn key(&self) -> Self::Key {
1211        SystemPrivilegesKey {
1212            grantee: self.grantee,
1213            grantor: self.grantor,
1214        }
1215    }
1216}
1217
1218#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
1219pub struct AuditLog {
1220    pub event: VersionedEvent,
1221}
1222
1223impl DurableType for AuditLog {
1224    type Key = AuditLogKey;
1225    type Value = ();
1226
1227    fn into_key_value(self) -> (Self::Key, Self::Value) {
1228        (AuditLogKey { event: self.event }, ())
1229    }
1230
1231    fn from_key_value(key: Self::Key, _value: Self::Value) -> Self {
1232        Self { event: key.event }
1233    }
1234
1235    fn key(&self) -> Self::Key {
1236        AuditLogKey {
1237            event: self.event.clone(),
1238        }
1239    }
1240}
1241
1242#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
1243pub struct StorageCollectionMetadata {
1244    pub id: GlobalId,
1245    pub shard: ShardId,
1246}
1247
1248impl DurableType for StorageCollectionMetadata {
1249    type Key = StorageCollectionMetadataKey;
1250    type Value = StorageCollectionMetadataValue;
1251
1252    fn into_key_value(self) -> (Self::Key, Self::Value) {
1253        (
1254            StorageCollectionMetadataKey { id: self.id },
1255            StorageCollectionMetadataValue { shard: self.shard },
1256        )
1257    }
1258
1259    fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
1260        Self {
1261            id: key.id,
1262            shard: value.shard,
1263        }
1264    }
1265
1266    fn key(&self) -> Self::Key {
1267        StorageCollectionMetadataKey { id: self.id }
1268    }
1269}
1270
1271#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
1272pub struct UnfinalizedShard {
1273    pub shard: ShardId,
1274}
1275
1276impl DurableType for UnfinalizedShard {
1277    type Key = UnfinalizedShardKey;
1278    type Value = ();
1279
1280    fn into_key_value(self) -> (Self::Key, Self::Value) {
1281        (UnfinalizedShardKey { shard: self.shard }, ())
1282    }
1283
1284    fn from_key_value(key: Self::Key, _value: Self::Value) -> Self {
1285        Self { shard: key.shard }
1286    }
1287
1288    fn key(&self) -> Self::Key {
1289        UnfinalizedShardKey {
1290            shard: self.shard.clone(),
1291        }
1292    }
1293}
1294
1295// Structs used internally to represent on-disk state.
1296
1297/// A snapshot of the current on-disk state.
1298#[derive(Debug, Clone, PartialEq, Eq, Default)]
1299pub struct Snapshot {
1300    pub databases: BTreeMap<proto::DatabaseKey, proto::DatabaseValue>,
1301    pub schemas: BTreeMap<proto::SchemaKey, proto::SchemaValue>,
1302    pub roles: BTreeMap<proto::RoleKey, proto::RoleValue>,
1303    pub role_auth: BTreeMap<proto::RoleAuthKey, proto::RoleAuthValue>,
1304    pub items: BTreeMap<proto::ItemKey, proto::ItemValue>,
1305    pub comments: BTreeMap<proto::CommentKey, proto::CommentValue>,
1306    pub clusters: BTreeMap<proto::ClusterKey, proto::ClusterValue>,
1307    pub network_policies: BTreeMap<proto::NetworkPolicyKey, proto::NetworkPolicyValue>,
1308    pub cluster_replicas: BTreeMap<proto::ClusterReplicaKey, proto::ClusterReplicaValue>,
1309    pub introspection_sources: BTreeMap<
1310        proto::ClusterIntrospectionSourceIndexKey,
1311        proto::ClusterIntrospectionSourceIndexValue,
1312    >,
1313    pub id_allocator: BTreeMap<proto::IdAllocKey, proto::IdAllocValue>,
1314    pub configs: BTreeMap<proto::ConfigKey, proto::ConfigValue>,
1315    pub settings: BTreeMap<proto::SettingKey, proto::SettingValue>,
1316    pub system_object_mappings: BTreeMap<proto::GidMappingKey, proto::GidMappingValue>,
1317    pub system_configurations:
1318        BTreeMap<proto::ServerConfigurationKey, proto::ServerConfigurationValue>,
1319    pub cluster_system_configurations:
1320        BTreeMap<proto::ClusterSystemConfigurationKey, proto::ClusterSystemConfigurationValue>,
1321    pub replica_system_configurations:
1322        BTreeMap<proto::ReplicaSystemConfigurationKey, proto::ReplicaSystemConfigurationValue>,
1323    pub default_privileges: BTreeMap<proto::DefaultPrivilegesKey, proto::DefaultPrivilegesValue>,
1324    pub source_references: BTreeMap<proto::SourceReferencesKey, proto::SourceReferencesValue>,
1325    pub system_privileges: BTreeMap<proto::SystemPrivilegesKey, proto::SystemPrivilegesValue>,
1326    pub storage_collection_metadata:
1327        BTreeMap<proto::StorageCollectionMetadataKey, proto::StorageCollectionMetadataValue>,
1328    pub unfinalized_shards: BTreeMap<proto::UnfinalizedShardKey, ()>,
1329    pub txn_wal_shard: BTreeMap<(), proto::TxnWalShardValue>,
1330}
1331
1332impl Snapshot {
1333    pub fn empty() -> Snapshot {
1334        Snapshot::default()
1335    }
1336}
1337
1338/// Token used to fence out other processes.
1339///
1340/// Every time a new process takes over, the `epoch` should be incremented.
1341/// Every time a new version is deployed, the `deploy` generation should be incremented.
1342#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1343#[cfg_attr(test, derive(Arbitrary))]
1344pub struct FenceToken {
1345    pub(crate) deploy_generation: u64,
1346    pub(crate) epoch: Epoch,
1347}
1348
1349impl PartialOrd for FenceToken {
1350    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1351        Some(self.cmp(other))
1352    }
1353}
1354
1355impl Ord for FenceToken {
1356    fn cmp(&self, other: &Self) -> Ordering {
1357        self.deploy_generation
1358            .cmp(&other.deploy_generation)
1359            .then(self.epoch.cmp(&other.epoch))
1360    }
1361}
1362
1363#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1364pub struct SettingKey {
1365    pub(crate) name: String,
1366}
1367
1368#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1369pub struct SettingValue {
1370    pub(crate) value: String,
1371}
1372
1373#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1374pub struct IdAllocKey {
1375    pub(crate) name: String,
1376}
1377
1378#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1379pub struct IdAllocValue {
1380    pub(crate) next_id: u64,
1381}
1382
1383#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1384pub struct GidMappingKey {
1385    pub(crate) schema_name: String,
1386    pub(crate) object_type: CatalogItemType,
1387    pub(crate) object_name: String,
1388}
1389
1390#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1391pub struct GidMappingValue {
1392    pub(crate) catalog_id: SystemCatalogItemId,
1393    pub(crate) global_id: SystemGlobalId,
1394    pub(crate) fingerprint: String,
1395}
1396
1397#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1398pub struct ClusterKey {
1399    pub(crate) id: ClusterId,
1400}
1401
1402#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1403pub struct ClusterValue {
1404    pub(crate) name: String,
1405    pub(crate) owner_id: RoleId,
1406    pub(crate) privileges: Vec<MzAclItem>,
1407    pub(crate) config: ClusterConfig,
1408}
1409
1410#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1411pub struct ClusterIntrospectionSourceIndexKey {
1412    pub(crate) cluster_id: ClusterId,
1413    pub(crate) name: String,
1414}
1415
1416#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1417pub struct ClusterIntrospectionSourceIndexValue {
1418    pub(crate) catalog_id: IntrospectionSourceIndexCatalogItemId,
1419    pub(crate) global_id: IntrospectionSourceIndexGlobalId,
1420    pub(crate) oid: u32,
1421}
1422
1423#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1424pub struct ClusterReplicaKey {
1425    pub(crate) id: ReplicaId,
1426}
1427
1428#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1429pub struct ClusterReplicaValue {
1430    pub(crate) cluster_id: ClusterId,
1431    pub(crate) name: String,
1432    pub(crate) config: ReplicaConfig,
1433    pub(crate) owner_id: RoleId,
1434}
1435
1436#[derive(Clone, Copy, Debug, PartialOrd, PartialEq, Eq, Ord, Hash)]
1437#[cfg_attr(test, derive(Arbitrary))]
1438pub struct DatabaseKey {
1439    pub(crate) id: DatabaseId,
1440}
1441
1442#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
1443#[cfg_attr(test, derive(Arbitrary))]
1444pub struct DatabaseValue {
1445    pub(crate) name: String,
1446    pub(crate) owner_id: RoleId,
1447    pub(crate) privileges: Vec<MzAclItem>,
1448    pub(crate) oid: u32,
1449}
1450
1451#[derive(Clone, Copy, Debug, PartialOrd, PartialEq, Eq, Ord, Hash)]
1452#[cfg_attr(test, derive(Arbitrary))]
1453pub struct SourceReferencesKey {
1454    pub(crate) source_id: CatalogItemId,
1455}
1456
1457#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
1458#[cfg_attr(test, derive(Arbitrary))]
1459pub struct SourceReferencesValue {
1460    pub(crate) references: Vec<SourceReference>,
1461    pub(crate) updated_at: u64,
1462}
1463
1464#[derive(Clone, Copy, Debug, PartialOrd, PartialEq, Eq, Ord, Hash)]
1465#[cfg_attr(test, derive(Arbitrary))]
1466pub struct SchemaKey {
1467    pub(crate) id: SchemaId,
1468}
1469
1470#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
1471#[cfg_attr(test, derive(Arbitrary))]
1472pub struct SchemaValue {
1473    pub(crate) database_id: Option<DatabaseId>,
1474    pub(crate) name: String,
1475    pub(crate) owner_id: RoleId,
1476    pub(crate) privileges: Vec<MzAclItem>,
1477    pub(crate) oid: u32,
1478}
1479
1480#[derive(Clone, PartialOrd, PartialEq, Eq, Ord, Hash, Debug)]
1481#[cfg_attr(test, derive(Arbitrary))]
1482pub struct ItemKey {
1483    pub(crate) id: CatalogItemId,
1484}
1485
1486#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
1487#[cfg_attr(test, derive(Arbitrary))]
1488pub struct ItemValue {
1489    pub(crate) schema_id: SchemaId,
1490    pub(crate) name: String,
1491    pub(crate) create_sql: String,
1492    pub(crate) owner_id: RoleId,
1493    pub(crate) privileges: Vec<MzAclItem>,
1494    pub(crate) oid: u32,
1495    pub(crate) global_id: GlobalId,
1496    pub(crate) extra_versions: BTreeMap<RelationVersion, GlobalId>,
1497}
1498
1499impl ItemValue {
1500    pub fn item_type(&self) -> CatalogItemType {
1501        item_type(&self.create_sql)
1502    }
1503}
1504
1505pub fn item_type(create_sql: &str) -> CatalogItemType {
1506    // NOTE(benesch): the implementation of this method is hideous, but is
1507    // there a better alternative? Storing the object type alongside the
1508    // `create_sql` would introduce the possibility of skew.
1509    let mut tokens = create_sql.split_whitespace();
1510    assert_eq!(tokens.next(), Some("CREATE"));
1511
1512    // Read away item type modifiers, if any.
1513    let next_token = match tokens.next() {
1514        Some("TEMPORARY") | Some("REPLACEMENT") => tokens.next(),
1515        token => token,
1516    };
1517
1518    match next_token {
1519        Some("TABLE") => CatalogItemType::Table,
1520        Some("SOURCE") | Some("SUBSOURCE") => CatalogItemType::Source,
1521        Some("SINK") => CatalogItemType::Sink,
1522        Some("VIEW") => CatalogItemType::View,
1523        Some("MATERIALIZED") => {
1524            assert_eq!(tokens.next(), Some("VIEW"));
1525            CatalogItemType::MaterializedView
1526        }
1527        Some("INDEX") => CatalogItemType::Index,
1528        Some("TYPE") => CatalogItemType::Type,
1529        Some("FUNCTION") => CatalogItemType::Func,
1530        Some("SECRET") => CatalogItemType::Secret,
1531        Some("CONNECTION") => CatalogItemType::Connection,
1532        _ => panic!("unexpected create sql: {}", create_sql),
1533    }
1534}
1535
1536#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
1537pub struct CommentKey {
1538    pub(crate) object_id: CommentObjectId,
1539    pub(crate) sub_component: Option<usize>,
1540}
1541
1542#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
1543#[cfg_attr(test, derive(Arbitrary))]
1544pub struct CommentValue {
1545    pub(crate) comment: String,
1546}
1547
1548#[derive(Clone, PartialOrd, PartialEq, Eq, Ord, Hash, Debug)]
1549pub struct RoleKey {
1550    pub(crate) id: RoleId,
1551}
1552
1553#[derive(Clone, PartialOrd, PartialEq, Eq, Ord, Debug)]
1554pub struct RoleValue {
1555    pub(crate) name: String,
1556    pub(crate) attributes: RoleAttributes,
1557    pub(crate) membership: RoleMembership,
1558    pub(crate) vars: RoleVars,
1559    pub(crate) oid: u32,
1560}
1561
1562#[derive(Clone, PartialOrd, PartialEq, Eq, Ord, Hash, Debug)]
1563pub struct NetworkPolicyKey {
1564    pub(crate) id: NetworkPolicyId,
1565}
1566
1567#[derive(Clone, PartialOrd, PartialEq, Eq, Ord, Debug)]
1568pub struct NetworkPolicyValue {
1569    pub(crate) name: String,
1570    pub(crate) rules: Vec<NetworkPolicyRule>,
1571    pub(crate) owner_id: RoleId,
1572    pub(crate) privileges: Vec<MzAclItem>,
1573    pub(crate) oid: u32,
1574}
1575
1576#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1577pub struct ConfigKey {
1578    pub(crate) key: String,
1579}
1580
1581#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1582pub struct ConfigValue {
1583    pub(crate) value: u64,
1584}
1585
1586#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1587pub struct AuditLogKey {
1588    pub(crate) event: VersionedEvent,
1589}
1590
1591#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1592pub struct StorageCollectionMetadataKey {
1593    pub(crate) id: GlobalId,
1594}
1595
1596/// This value is stored transparently, however, it should only ever be
1597/// manipulated by the storage controller.
1598#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1599pub struct StorageCollectionMetadataValue {
1600    pub(crate) shard: ShardId,
1601}
1602
1603/// This value is stored transparently, however, it should only ever be
1604/// manipulated by the storage controller.
1605#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1606pub struct UnfinalizedShardKey {
1607    pub(crate) shard: ShardId,
1608}
1609
1610/// This value is stored transparently, however, it should only ever be
1611/// manipulated by the storage controller.
1612#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1613pub struct TxnWalShardValue {
1614    pub(crate) shard: ShardId,
1615}
1616
1617#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1618pub struct ServerConfigurationKey {
1619    pub(crate) name: String,
1620}
1621
1622#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1623pub struct ServerConfigurationValue {
1624    pub(crate) value: String,
1625}
1626
1627#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1628pub struct ClusterSystemConfigurationKey {
1629    pub(crate) cluster_id: ClusterId,
1630    pub(crate) name: String,
1631}
1632
1633#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1634pub struct ClusterSystemConfigurationValue {
1635    pub(crate) value: String,
1636}
1637
1638#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1639pub struct ReplicaSystemConfigurationKey {
1640    pub(crate) replica_id: ReplicaId,
1641    pub(crate) name: String,
1642}
1643
1644#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1645pub struct ReplicaSystemConfigurationValue {
1646    pub(crate) value: String,
1647}
1648
1649#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1650pub struct DefaultPrivilegesKey {
1651    pub(crate) role_id: RoleId,
1652    pub(crate) database_id: Option<DatabaseId>,
1653    pub(crate) schema_id: Option<SchemaId>,
1654    pub(crate) object_type: ObjectType,
1655    pub(crate) grantee: RoleId,
1656}
1657
1658#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1659pub struct DefaultPrivilegesValue {
1660    pub(crate) privileges: AclMode,
1661}
1662
1663#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1664pub struct SystemPrivilegesKey {
1665    pub(crate) grantee: RoleId,
1666    pub(crate) grantor: RoleId,
1667}
1668
1669#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1670pub struct SystemPrivilegesValue {
1671    pub(crate) acl_mode: AclMode,
1672}
1673
1674#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1675pub struct RoleAuthKey {
1676    // TODO(auth): Depending on what the future holds, here is where
1677    // we might also want to key by a `version` field.
1678    // That way we can store password versions or what have you.
1679    pub(crate) role_id: RoleId,
1680}
1681
1682#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1683pub struct RoleAuthValue {
1684    pub(crate) password_hash: Option<String>,
1685    pub(crate) updated_at: u64,
1686}
1687
1688#[cfg(test)]
1689mod test {
1690    use mz_proto::{ProtoType, RustType};
1691    use proptest::prelude::*;
1692
1693    use super::{
1694        DatabaseKey, DatabaseValue, FenceToken, ItemKey, ItemValue, SchemaKey, SchemaValue,
1695    };
1696    use crate::durable::Epoch;
1697
1698    proptest! {
1699        #[mz_ore::test]
1700        #[cfg_attr(miri, ignore)] // slow
1701        fn proptest_database_key_roundtrip(key: DatabaseKey) {
1702            let proto = key.into_proto();
1703            let round = proto.into_rust().expect("to roundtrip");
1704
1705            prop_assert_eq!(key, round);
1706        }
1707
1708        #[mz_ore::test]
1709        #[cfg_attr(miri, ignore)] // slow
1710        fn proptest_database_value_roundtrip(value: DatabaseValue) {
1711            let proto = value.into_proto();
1712            let round = proto.into_rust().expect("to roundtrip");
1713
1714            prop_assert_eq!(value, round);
1715        }
1716
1717        #[mz_ore::test]
1718        #[cfg_attr(miri, ignore)] // slow
1719        fn proptest_schema_key_roundtrip(key: SchemaKey) {
1720            let proto = key.into_proto();
1721            let round = proto.into_rust().expect("to roundtrip");
1722
1723            prop_assert_eq!(key, round);
1724        }
1725
1726        #[mz_ore::test]
1727        #[cfg_attr(miri, ignore)] // slow
1728        fn proptest_schema_value_roundtrip(value: SchemaValue) {
1729            let proto = value.into_proto();
1730            let round = proto.into_rust().expect("to roundtrip");
1731
1732            prop_assert_eq!(value, round);
1733        }
1734
1735        #[mz_ore::test]
1736        #[cfg_attr(miri, ignore)] // slow
1737        fn proptest_item_key_roundtrip(key: ItemKey) {
1738            let proto = key.into_proto();
1739            let round = proto.into_rust().expect("to roundtrip");
1740
1741            prop_assert_eq!(key, round);
1742        }
1743
1744        #[mz_ore::test]
1745        #[cfg_attr(miri, ignore)] // slow
1746        fn proptest_item_value_roundtrip(value: ItemValue) {
1747            let proto = value.into_proto();
1748            let round = proto.into_rust().expect("to roundtrip");
1749
1750            prop_assert_eq!(value, round);
1751        }
1752    }
1753
1754    #[mz_ore::test]
1755    fn test_fence_token_order() {
1756        let ft1 = FenceToken {
1757            deploy_generation: 10,
1758            epoch: Epoch::new(20).expect("non-zero"),
1759        };
1760        let ft2 = FenceToken {
1761            deploy_generation: 10,
1762            epoch: Epoch::new(19).expect("non-zero"),
1763        };
1764
1765        assert!(ft1 > ft2);
1766
1767        let ft3 = FenceToken {
1768            deploy_generation: 11,
1769            epoch: Epoch::new(10).expect("non-zero"),
1770        };
1771
1772        assert!(ft3 > ft1);
1773
1774        let ft4 = FenceToken {
1775            deploy_generation: 11,
1776            epoch: Epoch::new(30).expect("non-zero"),
1777        };
1778
1779        assert!(ft4 > ft1);
1780    }
1781}