1pub mod serialization;
29pub(crate) mod state_update;
30
31use std::cmp::Ordering;
32use std::collections::BTreeMap;
33
34use mz_audit_log::VersionedEvent;
35use mz_controller::clusters::ReplicaLogging;
36use mz_controller_types::{ClusterId, ReplicaId};
37use mz_persist_types::ShardId;
38use mz_repr::adt::mz_acl_item::{AclMode, MzAclItem};
39use mz_repr::network_policy_id::NetworkPolicyId;
40use mz_repr::role_id::RoleId;
41use mz_repr::{CatalogItemId, GlobalId, RelationVersion};
42use mz_sql::catalog::{
43 CatalogItemType, DefaultPrivilegeAclItem, DefaultPrivilegeObject, ObjectType, RoleAttributes,
44 RoleMembership, RoleVars,
45};
46use mz_sql::names::{CommentObjectId, DatabaseId, SchemaId};
47use mz_sql::plan::{ClusterSchedule, NetworkPolicyRule};
48use proptest_derive::Arbitrary;
49
50use crate::builtin::RUNTIME_ALTERABLE_FINGERPRINT_SENTINEL;
51use crate::durable::Epoch;
52use crate::durable::objects::serialization::proto;
53
54pub trait DurableType: Sized {
69 type Key;
70 type Value;
71
72 fn into_key_value(self) -> (Self::Key, Self::Value);
74
75 fn from_key_value(key: Self::Key, value: Self::Value) -> Self;
78
79 fn key(&self) -> Self::Key;
84}
85
86#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
87pub struct Database {
88 pub id: DatabaseId,
89 pub oid: u32,
90 pub name: String,
91 pub owner_id: RoleId,
92 pub privileges: Vec<MzAclItem>,
93}
94
95impl DurableType for Database {
96 type Key = DatabaseKey;
97 type Value = DatabaseValue;
98
99 fn into_key_value(self) -> (Self::Key, Self::Value) {
100 (
101 DatabaseKey { id: self.id },
102 DatabaseValue {
103 oid: self.oid,
104 name: self.name,
105 owner_id: self.owner_id,
106 privileges: self.privileges,
107 },
108 )
109 }
110
111 fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
112 Self {
113 id: key.id,
114 oid: value.oid,
115 name: value.name,
116 owner_id: value.owner_id,
117 privileges: value.privileges,
118 }
119 }
120
121 fn key(&self) -> Self::Key {
122 DatabaseKey { id: self.id }
123 }
124}
125
126#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
127pub struct Schema {
128 pub id: SchemaId,
129 pub oid: u32,
130 pub name: String,
131 pub database_id: Option<DatabaseId>,
132 pub owner_id: RoleId,
133 pub privileges: Vec<MzAclItem>,
134}
135
136impl DurableType for Schema {
137 type Key = SchemaKey;
138 type Value = SchemaValue;
139
140 fn into_key_value(self) -> (Self::Key, Self::Value) {
141 (
142 SchemaKey { id: self.id },
143 SchemaValue {
144 oid: self.oid,
145 database_id: self.database_id,
146 name: self.name,
147 owner_id: self.owner_id,
148 privileges: self.privileges,
149 },
150 )
151 }
152
153 fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
154 Self {
155 id: key.id,
156 oid: value.oid,
157 name: value.name,
158 database_id: value.database_id,
159 owner_id: value.owner_id,
160 privileges: value.privileges,
161 }
162 }
163
164 fn key(&self) -> Self::Key {
165 SchemaKey { id: self.id }
166 }
167}
168
169#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
170pub struct Role {
171 pub id: RoleId,
172 pub oid: u32,
173 pub name: String,
174 pub attributes: RoleAttributes,
175 pub membership: RoleMembership,
176 pub vars: RoleVars,
177}
178
179impl DurableType for Role {
180 type Key = RoleKey;
181 type Value = RoleValue;
182
183 fn into_key_value(self) -> (Self::Key, Self::Value) {
184 (
185 RoleKey { id: self.id },
186 RoleValue {
187 oid: self.oid,
188 name: self.name,
189 attributes: self.attributes,
190 membership: self.membership,
191 vars: self.vars,
192 },
193 )
194 }
195
196 fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
197 Self {
198 id: key.id,
199 oid: value.oid,
200 name: value.name,
201 attributes: value.attributes,
202 membership: value.membership,
203 vars: value.vars,
204 }
205 }
206
207 fn key(&self) -> Self::Key {
208 RoleKey { id: self.id }
209 }
210}
211
212#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
213pub struct RoleAuth {
214 pub role_id: RoleId,
215 pub password_hash: Option<String>,
216 pub updated_at: u64,
217}
218
219impl DurableType for RoleAuth {
220 type Key = RoleAuthKey;
221 type Value = RoleAuthValue;
222
223 fn into_key_value(self) -> (Self::Key, Self::Value) {
224 (
225 RoleAuthKey {
226 role_id: self.role_id,
227 },
228 RoleAuthValue {
229 password_hash: self.password_hash,
230 updated_at: self.updated_at,
231 },
232 )
233 }
234
235 fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
236 Self {
237 role_id: key.role_id,
238 password_hash: value.password_hash,
239 updated_at: value.updated_at,
240 }
241 }
242
243 fn key(&self) -> Self::Key {
244 RoleAuthKey {
245 role_id: self.role_id,
246 }
247 }
248}
249
250#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
251pub struct NetworkPolicy {
252 pub name: String,
253 pub id: NetworkPolicyId,
254 pub oid: u32,
255 pub rules: Vec<NetworkPolicyRule>,
256 pub owner_id: RoleId,
257 pub(crate) privileges: Vec<MzAclItem>,
258}
259
260impl DurableType for NetworkPolicy {
261 type Key = NetworkPolicyKey;
262 type Value = NetworkPolicyValue;
263
264 fn into_key_value(self) -> (Self::Key, Self::Value) {
265 (
266 NetworkPolicyKey { id: self.id },
267 NetworkPolicyValue {
268 oid: self.oid,
269 name: self.name,
270 rules: self.rules,
271 owner_id: self.owner_id,
272 privileges: self.privileges,
273 },
274 )
275 }
276
277 fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
278 Self {
279 id: key.id,
280 oid: value.oid,
281 name: value.name,
282 rules: value.rules,
283 owner_id: value.owner_id,
284 privileges: value.privileges,
285 }
286 }
287
288 fn key(&self) -> Self::Key {
289 NetworkPolicyKey { id: self.id }
290 }
291}
292
293#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
294pub struct Cluster {
295 pub id: ClusterId,
296 pub name: String,
297 pub owner_id: RoleId,
298 pub privileges: Vec<MzAclItem>,
299 pub config: ClusterConfig,
300}
301
302impl DurableType for Cluster {
303 type Key = ClusterKey;
304 type Value = ClusterValue;
305
306 fn into_key_value(self) -> (Self::Key, Self::Value) {
307 (
308 ClusterKey { id: self.id },
309 ClusterValue {
310 name: self.name,
311 owner_id: self.owner_id,
312 privileges: self.privileges,
313 config: self.config,
314 },
315 )
316 }
317
318 fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
319 Self {
320 id: key.id,
321 name: value.name,
322 owner_id: value.owner_id,
323 privileges: value.privileges,
324 config: value.config,
325 }
326 }
327
328 fn key(&self) -> Self::Key {
329 ClusterKey { id: self.id }
330 }
331}
332
333#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
334pub struct ClusterConfig {
335 pub variant: ClusterVariant,
336 pub workload_class: Option<String>,
337}
338
339#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
340pub enum ClusterVariant {
341 Managed(ClusterVariantManaged),
342 Unmanaged,
343}
344
345#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
346pub struct ClusterVariantManaged {
347 pub size: String,
348 pub availability_zones: Vec<String>,
349 pub logging: ReplicaLogging,
350 pub replication_factor: u32,
351 pub disk: bool,
352 pub optimizer_feature_overrides: BTreeMap<String, String>,
353 pub schedule: ClusterSchedule,
354}
355
356#[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq)]
357pub struct IntrospectionSourceIndex {
358 pub cluster_id: ClusterId,
359 pub name: String,
360 pub item_id: CatalogItemId,
361 pub index_id: GlobalId,
362 pub oid: u32,
363}
364
365impl DurableType for IntrospectionSourceIndex {
366 type Key = ClusterIntrospectionSourceIndexKey;
367 type Value = ClusterIntrospectionSourceIndexValue;
368
369 fn into_key_value(self) -> (Self::Key, Self::Value) {
370 (
371 ClusterIntrospectionSourceIndexKey {
372 cluster_id: self.cluster_id,
373 name: self.name,
374 },
375 ClusterIntrospectionSourceIndexValue {
376 catalog_id: self
377 .item_id
378 .try_into()
379 .expect("cluster introspection source index mapping must be an Introspection Source Index ID"),
380 global_id: self
381 .index_id
382 .try_into()
383 .expect("cluster introspection source index mapping must be a Introspection Source Index ID"),
384 oid: self.oid,
385 },
386 )
387 }
388
389 fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
390 Self {
391 cluster_id: key.cluster_id,
392 name: key.name,
393 item_id: value.catalog_id.into(),
394 index_id: value.global_id.into(),
395 oid: value.oid,
396 }
397 }
398
399 fn key(&self) -> Self::Key {
400 ClusterIntrospectionSourceIndexKey {
401 cluster_id: self.cluster_id,
402 name: self.name.clone(),
403 }
404 }
405}
406
407#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
408pub struct ClusterReplica {
409 pub cluster_id: ClusterId,
410 pub replica_id: ReplicaId,
411 pub name: String,
412 pub config: ReplicaConfig,
413 pub owner_id: RoleId,
414}
415
416impl DurableType for ClusterReplica {
417 type Key = ClusterReplicaKey;
418 type Value = ClusterReplicaValue;
419
420 fn into_key_value(self) -> (Self::Key, Self::Value) {
421 (
422 ClusterReplicaKey {
423 id: self.replica_id,
424 },
425 ClusterReplicaValue {
426 cluster_id: self.cluster_id,
427 name: self.name,
428 config: self.config,
429 owner_id: self.owner_id,
430 },
431 )
432 }
433
434 fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
435 Self {
436 cluster_id: value.cluster_id,
437 replica_id: key.id,
438 name: value.name,
439 config: value.config,
440 owner_id: value.owner_id,
441 }
442 }
443
444 fn key(&self) -> Self::Key {
445 ClusterReplicaKey {
446 id: self.replica_id,
447 }
448 }
449}
450
451#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
455pub struct ReplicaConfig {
456 pub location: ReplicaLocation,
457 pub logging: ReplicaLogging,
458}
459
460impl From<mz_controller::clusters::ReplicaConfig> for ReplicaConfig {
461 fn from(config: mz_controller::clusters::ReplicaConfig) -> Self {
462 Self {
463 location: config.location.into(),
464 logging: config.compute.logging,
465 }
466 }
467}
468
469#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
470pub enum ReplicaLocation {
471 Unmanaged {
472 storagectl_addrs: Vec<String>,
473 storage_addrs: Vec<String>,
474 computectl_addrs: Vec<String>,
475 compute_addrs: Vec<String>,
476 workers: usize,
477 },
478 Managed {
479 size: String,
480 availability_zone: Option<String>,
482 disk: bool,
483 internal: bool,
484 billed_as: Option<String>,
485 pending: bool,
486 },
487}
488
489impl From<mz_controller::clusters::ReplicaLocation> for ReplicaLocation {
490 fn from(loc: mz_controller::clusters::ReplicaLocation) -> Self {
491 match loc {
492 mz_controller::clusters::ReplicaLocation::Unmanaged(
493 mz_controller::clusters::UnmanagedReplicaLocation {
494 storagectl_addrs,
495 storage_addrs,
496 computectl_addrs,
497 compute_addrs,
498 workers,
499 },
500 ) => Self::Unmanaged {
501 storagectl_addrs,
502 storage_addrs,
503 computectl_addrs,
504 compute_addrs,
505 workers,
506 },
507 mz_controller::clusters::ReplicaLocation::Managed(
508 mz_controller::clusters::ManagedReplicaLocation {
509 allocation: _,
510 size,
511 availability_zones,
512 disk,
513 billed_as,
514 internal,
515 pending,
516 },
517 ) => ReplicaLocation::Managed {
518 size,
519 availability_zone:
520 if let mz_controller::clusters::ManagedReplicaAvailabilityZones::FromReplica(
521 Some(az),
522 ) = availability_zones
523 {
524 Some(az)
525 } else {
526 None
527 },
528 disk,
529 internal,
530 billed_as,
531 pending,
532 },
533 }
534 }
535}
536
537#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
538pub struct Item {
539 pub id: CatalogItemId,
540 pub oid: u32,
541 pub global_id: GlobalId,
542 pub schema_id: SchemaId,
543 pub name: String,
544 pub create_sql: String,
545 pub owner_id: RoleId,
546 pub privileges: Vec<MzAclItem>,
547 pub extra_versions: BTreeMap<RelationVersion, GlobalId>,
548}
549
550impl Item {
551 pub fn item_type(&self) -> CatalogItemType {
552 item_type(&self.create_sql)
553 }
554}
555
556impl DurableType for Item {
557 type Key = ItemKey;
558 type Value = ItemValue;
559
560 fn into_key_value(self) -> (Self::Key, Self::Value) {
561 (
562 ItemKey { id: self.id },
563 ItemValue {
564 oid: self.oid,
565 global_id: self.global_id,
566 schema_id: self.schema_id,
567 name: self.name,
568 create_sql: self.create_sql,
569 owner_id: self.owner_id,
570 privileges: self.privileges,
571 extra_versions: self.extra_versions,
572 },
573 )
574 }
575
576 fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
577 Self {
578 id: key.id,
579 oid: value.oid,
580 global_id: value.global_id,
581 schema_id: value.schema_id,
582 name: value.name,
583 create_sql: value.create_sql,
584 owner_id: value.owner_id,
585 privileges: value.privileges,
586 extra_versions: value.extra_versions,
587 }
588 }
589
590 fn key(&self) -> Self::Key {
591 ItemKey { id: self.id }
592 }
593}
594
595#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
596pub struct SourceReferences {
597 pub source_id: CatalogItemId,
598 pub updated_at: u64,
599 pub references: Vec<SourceReference>,
600}
601
602#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq, Arbitrary)]
603pub struct SourceReference {
604 pub name: String,
605 pub namespace: Option<String>,
606 pub columns: Vec<String>,
607}
608
609impl DurableType for SourceReferences {
610 type Key = SourceReferencesKey;
611 type Value = SourceReferencesValue;
612
613 fn into_key_value(self) -> (Self::Key, Self::Value) {
614 (
615 SourceReferencesKey {
616 source_id: self.source_id,
617 },
618 SourceReferencesValue {
619 updated_at: self.updated_at,
620 references: self.references,
621 },
622 )
623 }
624
625 fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
626 Self {
627 source_id: key.source_id,
628 updated_at: value.updated_at,
629 references: value.references,
630 }
631 }
632
633 fn key(&self) -> Self::Key {
634 SourceReferencesKey {
635 source_id: self.source_id,
636 }
637 }
638}
639
640#[derive(Debug, Copy, Clone, Ord, PartialOrd, PartialEq, Eq)]
642pub struct SystemCatalogItemId(u64);
643
644impl TryFrom<CatalogItemId> for SystemCatalogItemId {
645 type Error = &'static str;
646
647 fn try_from(val: CatalogItemId) -> Result<Self, Self::Error> {
648 match val {
649 CatalogItemId::System(x) => Ok(SystemCatalogItemId(x)),
650 CatalogItemId::IntrospectionSourceIndex(_) => Err("introspection_source_index"),
651 CatalogItemId::User(_) => Err("user"),
652 CatalogItemId::Transient(_) => Err("transient"),
653 }
654 }
655}
656
657impl From<SystemCatalogItemId> for CatalogItemId {
658 fn from(val: SystemCatalogItemId) -> Self {
659 CatalogItemId::System(val.0)
660 }
661}
662
663#[derive(Debug, Copy, Clone, Ord, PartialOrd, PartialEq, Eq)]
665pub struct IntrospectionSourceIndexCatalogItemId(u64);
666
667impl TryFrom<CatalogItemId> for IntrospectionSourceIndexCatalogItemId {
668 type Error = &'static str;
669
670 fn try_from(val: CatalogItemId) -> Result<Self, Self::Error> {
671 match val {
672 CatalogItemId::System(_) => Err("system"),
673 CatalogItemId::IntrospectionSourceIndex(x) => {
674 Ok(IntrospectionSourceIndexCatalogItemId(x))
675 }
676 CatalogItemId::User(_) => Err("user"),
677 CatalogItemId::Transient(_) => Err("transient"),
678 }
679 }
680}
681
682impl From<IntrospectionSourceIndexCatalogItemId> for CatalogItemId {
683 fn from(val: IntrospectionSourceIndexCatalogItemId) -> Self {
684 CatalogItemId::IntrospectionSourceIndex(val.0)
685 }
686}
687
688#[derive(Debug, Copy, Clone, Ord, PartialOrd, PartialEq, Eq)]
690pub struct SystemGlobalId(u64);
691
692impl TryFrom<GlobalId> for SystemGlobalId {
693 type Error = &'static str;
694
695 fn try_from(val: GlobalId) -> Result<Self, Self::Error> {
696 match val {
697 GlobalId::System(x) => Ok(SystemGlobalId(x)),
698 GlobalId::IntrospectionSourceIndex(_) => Err("introspection_source_index"),
699 GlobalId::User(_) => Err("user"),
700 GlobalId::Transient(_) => Err("transient"),
701 GlobalId::Explain => Err("explain"),
702 }
703 }
704}
705
706impl From<SystemGlobalId> for GlobalId {
707 fn from(val: SystemGlobalId) -> Self {
708 GlobalId::System(val.0)
709 }
710}
711
712#[derive(Debug, Copy, Clone, Ord, PartialOrd, PartialEq, Eq)]
714pub struct IntrospectionSourceIndexGlobalId(u64);
715
716impl TryFrom<GlobalId> for IntrospectionSourceIndexGlobalId {
717 type Error = &'static str;
718
719 fn try_from(val: GlobalId) -> Result<Self, Self::Error> {
720 match val {
721 GlobalId::System(_) => Err("system"),
722 GlobalId::IntrospectionSourceIndex(x) => Ok(IntrospectionSourceIndexGlobalId(x)),
723 GlobalId::User(_) => Err("user"),
724 GlobalId::Transient(_) => Err("transient"),
725 GlobalId::Explain => Err("explain"),
726 }
727 }
728}
729
730impl From<IntrospectionSourceIndexGlobalId> for GlobalId {
731 fn from(val: IntrospectionSourceIndexGlobalId) -> Self {
732 GlobalId::IntrospectionSourceIndex(val.0)
733 }
734}
735
736#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
737pub struct SystemObjectDescription {
738 pub schema_name: String,
739 pub object_type: CatalogItemType,
740 pub object_name: String,
741}
742
743#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
744pub struct SystemObjectUniqueIdentifier {
745 pub catalog_id: CatalogItemId,
746 pub global_id: GlobalId,
747 pub fingerprint: String,
748}
749
750impl SystemObjectUniqueIdentifier {
751 pub fn runtime_alterable(&self) -> bool {
752 self.fingerprint == RUNTIME_ALTERABLE_FINGERPRINT_SENTINEL
753 }
754}
755
756#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
764pub struct SystemObjectMapping {
765 pub description: SystemObjectDescription,
766 pub unique_identifier: SystemObjectUniqueIdentifier,
767}
768
769impl DurableType for SystemObjectMapping {
770 type Key = GidMappingKey;
771 type Value = GidMappingValue;
772
773 fn into_key_value(self) -> (Self::Key, Self::Value) {
774 (
775 GidMappingKey {
776 schema_name: self.description.schema_name,
777 object_type: self.description.object_type,
778 object_name: self.description.object_name,
779 },
780 GidMappingValue {
781 catalog_id: self
782 .unique_identifier
783 .catalog_id
784 .try_into()
785 .expect("catalog_id to be in the system namespace"),
786 global_id: self
787 .unique_identifier
788 .global_id
789 .try_into()
790 .expect("collection_id to be in the system namespace"),
791 fingerprint: self.unique_identifier.fingerprint,
792 },
793 )
794 }
795
796 fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
797 Self {
798 description: SystemObjectDescription {
799 schema_name: key.schema_name,
800 object_type: key.object_type,
801 object_name: key.object_name,
802 },
803 unique_identifier: SystemObjectUniqueIdentifier {
804 catalog_id: value.catalog_id.into(),
805 global_id: value.global_id.into(),
806 fingerprint: value.fingerprint,
807 },
808 }
809 }
810
811 fn key(&self) -> Self::Key {
812 GidMappingKey {
813 schema_name: self.description.schema_name.clone(),
814 object_type: self.description.object_type.clone(),
815 object_name: self.description.object_name.clone(),
816 }
817 }
818}
819
820#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
821pub struct DefaultPrivilege {
822 pub object: DefaultPrivilegeObject,
823 pub acl_item: DefaultPrivilegeAclItem,
824}
825
826impl DurableType for DefaultPrivilege {
827 type Key = DefaultPrivilegesKey;
828 type Value = DefaultPrivilegesValue;
829
830 fn into_key_value(self) -> (Self::Key, Self::Value) {
831 (
832 DefaultPrivilegesKey {
833 role_id: self.object.role_id,
834 database_id: self.object.database_id,
835 schema_id: self.object.schema_id,
836 object_type: self.object.object_type,
837 grantee: self.acl_item.grantee,
838 },
839 DefaultPrivilegesValue {
840 privileges: self.acl_item.acl_mode,
841 },
842 )
843 }
844
845 fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
846 Self {
847 object: DefaultPrivilegeObject {
848 role_id: key.role_id,
849 database_id: key.database_id,
850 schema_id: key.schema_id,
851 object_type: key.object_type,
852 },
853 acl_item: DefaultPrivilegeAclItem {
854 grantee: key.grantee,
855 acl_mode: value.privileges,
856 },
857 }
858 }
859
860 fn key(&self) -> Self::Key {
861 DefaultPrivilegesKey {
862 role_id: self.object.role_id,
863 database_id: self.object.database_id,
864 schema_id: self.object.schema_id,
865 object_type: self.object.object_type,
866 grantee: self.acl_item.grantee,
867 }
868 }
869}
870
871#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
872pub struct Comment {
873 pub object_id: CommentObjectId,
874 pub sub_component: Option<usize>,
875 pub comment: String,
876}
877
878impl DurableType for Comment {
879 type Key = CommentKey;
880 type Value = CommentValue;
881
882 fn into_key_value(self) -> (Self::Key, Self::Value) {
883 (
884 CommentKey {
885 object_id: self.object_id,
886 sub_component: self.sub_component,
887 },
888 CommentValue {
889 comment: self.comment,
890 },
891 )
892 }
893
894 fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
895 Self {
896 object_id: key.object_id,
897 sub_component: key.sub_component,
898 comment: value.comment,
899 }
900 }
901
902 fn key(&self) -> Self::Key {
903 CommentKey {
904 object_id: self.object_id,
905 sub_component: self.sub_component,
906 }
907 }
908}
909
910#[derive(Debug, Clone, PartialEq, Eq)]
911pub struct IdAlloc {
912 pub name: String,
913 pub next_id: u64,
914}
915
916impl DurableType for IdAlloc {
917 type Key = IdAllocKey;
918 type Value = IdAllocValue;
919
920 fn into_key_value(self) -> (Self::Key, Self::Value) {
921 (
922 IdAllocKey { name: self.name },
923 IdAllocValue {
924 next_id: self.next_id,
925 },
926 )
927 }
928
929 fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
930 Self {
931 name: key.name,
932 next_id: value.next_id,
933 }
934 }
935
936 fn key(&self) -> Self::Key {
937 IdAllocKey {
938 name: self.name.clone(),
939 }
940 }
941}
942
943#[derive(Debug, Clone, PartialEq, Eq)]
944pub struct Config {
945 pub key: String,
946 pub value: u64,
947}
948
949impl DurableType for Config {
950 type Key = ConfigKey;
951 type Value = ConfigValue;
952
953 fn into_key_value(self) -> (Self::Key, Self::Value) {
954 (
955 ConfigKey { key: self.key },
956 ConfigValue { value: self.value },
957 )
958 }
959
960 fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
961 Self {
962 key: key.key,
963 value: value.value,
964 }
965 }
966
967 fn key(&self) -> Self::Key {
968 ConfigKey {
969 key: self.key.clone(),
970 }
971 }
972}
973
974#[derive(Debug, Clone)]
975pub struct Setting {
976 pub name: String,
977 pub value: String,
978}
979
980impl DurableType for Setting {
981 type Key = SettingKey;
982 type Value = SettingValue;
983
984 fn into_key_value(self) -> (Self::Key, Self::Value) {
985 (
986 SettingKey { name: self.name },
987 SettingValue { value: self.value },
988 )
989 }
990
991 fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
992 Self {
993 name: key.name,
994 value: value.value,
995 }
996 }
997
998 fn key(&self) -> Self::Key {
999 SettingKey {
1000 name: self.name.clone(),
1001 }
1002 }
1003}
1004
1005#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
1006pub struct SystemConfiguration {
1007 pub name: String,
1008 pub value: String,
1009}
1010
1011impl DurableType for SystemConfiguration {
1012 type Key = ServerConfigurationKey;
1013 type Value = ServerConfigurationValue;
1014
1015 fn into_key_value(self) -> (Self::Key, Self::Value) {
1016 (
1017 ServerConfigurationKey { name: self.name },
1018 ServerConfigurationValue { value: self.value },
1019 )
1020 }
1021
1022 fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
1023 Self {
1024 name: key.name,
1025 value: value.value,
1026 }
1027 }
1028
1029 fn key(&self) -> Self::Key {
1030 ServerConfigurationKey {
1031 name: self.name.clone(),
1032 }
1033 }
1034}
1035
1036impl DurableType for MzAclItem {
1037 type Key = SystemPrivilegesKey;
1038 type Value = SystemPrivilegesValue;
1039
1040 fn into_key_value(self) -> (Self::Key, Self::Value) {
1041 (
1042 SystemPrivilegesKey {
1043 grantee: self.grantee,
1044 grantor: self.grantor,
1045 },
1046 SystemPrivilegesValue {
1047 acl_mode: self.acl_mode,
1048 },
1049 )
1050 }
1051
1052 fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
1053 Self {
1054 grantee: key.grantee,
1055 grantor: key.grantor,
1056 acl_mode: value.acl_mode,
1057 }
1058 }
1059
1060 fn key(&self) -> Self::Key {
1061 SystemPrivilegesKey {
1062 grantee: self.grantee,
1063 grantor: self.grantor,
1064 }
1065 }
1066}
1067
1068#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
1069pub struct AuditLog {
1070 pub event: VersionedEvent,
1071}
1072
1073impl DurableType for AuditLog {
1074 type Key = AuditLogKey;
1075 type Value = ();
1076
1077 fn into_key_value(self) -> (Self::Key, Self::Value) {
1078 (AuditLogKey { event: self.event }, ())
1079 }
1080
1081 fn from_key_value(key: Self::Key, _value: Self::Value) -> Self {
1082 Self { event: key.event }
1083 }
1084
1085 fn key(&self) -> Self::Key {
1086 AuditLogKey {
1087 event: self.event.clone(),
1088 }
1089 }
1090}
1091
1092#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
1093pub struct StorageCollectionMetadata {
1094 pub id: GlobalId,
1095 pub shard: ShardId,
1096}
1097
1098impl DurableType for StorageCollectionMetadata {
1099 type Key = StorageCollectionMetadataKey;
1100 type Value = StorageCollectionMetadataValue;
1101
1102 fn into_key_value(self) -> (Self::Key, Self::Value) {
1103 (
1104 StorageCollectionMetadataKey { id: self.id },
1105 StorageCollectionMetadataValue { shard: self.shard },
1106 )
1107 }
1108
1109 fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
1110 Self {
1111 id: key.id,
1112 shard: value.shard,
1113 }
1114 }
1115
1116 fn key(&self) -> Self::Key {
1117 StorageCollectionMetadataKey { id: self.id }
1118 }
1119}
1120
1121#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
1122pub struct UnfinalizedShard {
1123 pub shard: ShardId,
1124}
1125
1126impl DurableType for UnfinalizedShard {
1127 type Key = UnfinalizedShardKey;
1128 type Value = ();
1129
1130 fn into_key_value(self) -> (Self::Key, Self::Value) {
1131 (UnfinalizedShardKey { shard: self.shard }, ())
1132 }
1133
1134 fn from_key_value(key: Self::Key, _value: Self::Value) -> Self {
1135 Self { shard: key.shard }
1136 }
1137
1138 fn key(&self) -> Self::Key {
1139 UnfinalizedShardKey {
1140 shard: self.shard.clone(),
1141 }
1142 }
1143}
1144
1145#[derive(Debug, Clone, PartialEq, Eq, Default)]
1149pub struct Snapshot {
1150 pub databases: BTreeMap<proto::DatabaseKey, proto::DatabaseValue>,
1151 pub schemas: BTreeMap<proto::SchemaKey, proto::SchemaValue>,
1152 pub roles: BTreeMap<proto::RoleKey, proto::RoleValue>,
1153 pub role_auth: BTreeMap<proto::RoleAuthKey, proto::RoleAuthValue>,
1154 pub items: BTreeMap<proto::ItemKey, proto::ItemValue>,
1155 pub comments: BTreeMap<proto::CommentKey, proto::CommentValue>,
1156 pub clusters: BTreeMap<proto::ClusterKey, proto::ClusterValue>,
1157 pub network_policies: BTreeMap<proto::NetworkPolicyKey, proto::NetworkPolicyValue>,
1158 pub cluster_replicas: BTreeMap<proto::ClusterReplicaKey, proto::ClusterReplicaValue>,
1159 pub introspection_sources: BTreeMap<
1160 proto::ClusterIntrospectionSourceIndexKey,
1161 proto::ClusterIntrospectionSourceIndexValue,
1162 >,
1163 pub id_allocator: BTreeMap<proto::IdAllocKey, proto::IdAllocValue>,
1164 pub configs: BTreeMap<proto::ConfigKey, proto::ConfigValue>,
1165 pub settings: BTreeMap<proto::SettingKey, proto::SettingValue>,
1166 pub system_object_mappings: BTreeMap<proto::GidMappingKey, proto::GidMappingValue>,
1167 pub system_configurations:
1168 BTreeMap<proto::ServerConfigurationKey, proto::ServerConfigurationValue>,
1169 pub default_privileges: BTreeMap<proto::DefaultPrivilegesKey, proto::DefaultPrivilegesValue>,
1170 pub source_references: BTreeMap<proto::SourceReferencesKey, proto::SourceReferencesValue>,
1171 pub system_privileges: BTreeMap<proto::SystemPrivilegesKey, proto::SystemPrivilegesValue>,
1172 pub storage_collection_metadata:
1173 BTreeMap<proto::StorageCollectionMetadataKey, proto::StorageCollectionMetadataValue>,
1174 pub unfinalized_shards: BTreeMap<proto::UnfinalizedShardKey, ()>,
1175 pub txn_wal_shard: BTreeMap<(), proto::TxnWalShardValue>,
1176}
1177
1178impl Snapshot {
1179 pub fn empty() -> Snapshot {
1180 Snapshot::default()
1181 }
1182}
1183
1184#[derive(Debug, Clone, PartialEq, Eq, Hash, Arbitrary)]
1189pub struct FenceToken {
1190 pub(crate) deploy_generation: u64,
1191 pub(crate) epoch: Epoch,
1192}
1193
1194impl PartialOrd for FenceToken {
1195 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1196 Some(self.cmp(other))
1197 }
1198}
1199
1200impl Ord for FenceToken {
1201 fn cmp(&self, other: &Self) -> Ordering {
1202 self.deploy_generation
1203 .cmp(&other.deploy_generation)
1204 .then(self.epoch.cmp(&other.epoch))
1205 }
1206}
1207
1208#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1209pub struct SettingKey {
1210 pub(crate) name: String,
1211}
1212
1213#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1214pub struct SettingValue {
1215 pub(crate) value: String,
1216}
1217
1218#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1219pub struct IdAllocKey {
1220 pub(crate) name: String,
1221}
1222
1223#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1224pub struct IdAllocValue {
1225 pub(crate) next_id: u64,
1226}
1227
1228#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1229pub struct GidMappingKey {
1230 pub(crate) schema_name: String,
1231 pub(crate) object_type: CatalogItemType,
1232 pub(crate) object_name: String,
1233}
1234
1235#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1236pub struct GidMappingValue {
1237 pub(crate) catalog_id: SystemCatalogItemId,
1238 pub(crate) global_id: SystemGlobalId,
1239 pub(crate) fingerprint: String,
1240}
1241
1242#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1243pub struct ClusterKey {
1244 pub(crate) id: ClusterId,
1245}
1246
1247#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1248pub struct ClusterValue {
1249 pub(crate) name: String,
1250 pub(crate) owner_id: RoleId,
1251 pub(crate) privileges: Vec<MzAclItem>,
1252 pub(crate) config: ClusterConfig,
1253}
1254
1255#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1256pub struct ClusterIntrospectionSourceIndexKey {
1257 pub(crate) cluster_id: ClusterId,
1258 pub(crate) name: String,
1259}
1260
1261#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1262pub struct ClusterIntrospectionSourceIndexValue {
1263 pub(crate) catalog_id: IntrospectionSourceIndexCatalogItemId,
1264 pub(crate) global_id: IntrospectionSourceIndexGlobalId,
1265 pub(crate) oid: u32,
1266}
1267
1268#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1269pub struct ClusterReplicaKey {
1270 pub(crate) id: ReplicaId,
1271}
1272
1273#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1274pub struct ClusterReplicaValue {
1275 pub(crate) cluster_id: ClusterId,
1276 pub(crate) name: String,
1277 pub(crate) config: ReplicaConfig,
1278 pub(crate) owner_id: RoleId,
1279}
1280
1281#[derive(Clone, Copy, Debug, PartialOrd, PartialEq, Eq, Ord, Hash, Arbitrary)]
1282pub struct DatabaseKey {
1283 pub(crate) id: DatabaseId,
1284}
1285
1286#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord, Arbitrary)]
1287pub struct DatabaseValue {
1288 pub(crate) name: String,
1289 pub(crate) owner_id: RoleId,
1290 pub(crate) privileges: Vec<MzAclItem>,
1291 pub(crate) oid: u32,
1292}
1293
1294#[derive(Clone, Copy, Debug, PartialOrd, PartialEq, Eq, Ord, Hash, Arbitrary)]
1295pub struct SourceReferencesKey {
1296 pub(crate) source_id: CatalogItemId,
1297}
1298
1299#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord, Arbitrary)]
1300pub struct SourceReferencesValue {
1301 pub(crate) references: Vec<SourceReference>,
1302 pub(crate) updated_at: u64,
1303}
1304
1305#[derive(Clone, Copy, Debug, PartialOrd, PartialEq, Eq, Ord, Hash, Arbitrary)]
1306pub struct SchemaKey {
1307 pub(crate) id: SchemaId,
1308}
1309
1310#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord, Arbitrary)]
1311pub struct SchemaValue {
1312 pub(crate) database_id: Option<DatabaseId>,
1313 pub(crate) name: String,
1314 pub(crate) owner_id: RoleId,
1315 pub(crate) privileges: Vec<MzAclItem>,
1316 pub(crate) oid: u32,
1317}
1318
1319#[derive(Clone, PartialOrd, PartialEq, Eq, Ord, Hash, Debug, Arbitrary)]
1320pub struct ItemKey {
1321 pub(crate) id: CatalogItemId,
1322}
1323
1324#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord, Arbitrary)]
1325pub struct ItemValue {
1326 pub(crate) schema_id: SchemaId,
1327 pub(crate) name: String,
1328 pub(crate) create_sql: String,
1329 pub(crate) owner_id: RoleId,
1330 pub(crate) privileges: Vec<MzAclItem>,
1331 pub(crate) oid: u32,
1332 pub(crate) global_id: GlobalId,
1333 pub(crate) extra_versions: BTreeMap<RelationVersion, GlobalId>,
1334}
1335
1336impl ItemValue {
1337 pub fn item_type(&self) -> CatalogItemType {
1338 item_type(&self.create_sql)
1339 }
1340}
1341
1342fn item_type(create_sql: &str) -> CatalogItemType {
1343 let mut tokens = create_sql.split_whitespace();
1347 assert_eq!(tokens.next(), Some("CREATE"));
1348 match tokens.next() {
1349 Some("TABLE") => CatalogItemType::Table,
1350 Some("SOURCE") | Some("SUBSOURCE") => CatalogItemType::Source,
1351 Some("SINK") => CatalogItemType::Sink,
1352 Some("VIEW") => CatalogItemType::View,
1353 Some("MATERIALIZED") => {
1354 assert_eq!(tokens.next(), Some("VIEW"));
1355 CatalogItemType::MaterializedView
1356 }
1357 Some("CONTINUAL") => {
1358 assert_eq!(tokens.next(), Some("TASK"));
1359 CatalogItemType::ContinualTask
1360 }
1361 Some("INDEX") => CatalogItemType::Index,
1362 Some("TYPE") => CatalogItemType::Type,
1363 Some("FUNCTION") => CatalogItemType::Func,
1364 Some("SECRET") => CatalogItemType::Secret,
1365 Some("CONNECTION") => CatalogItemType::Connection,
1366 _ => panic!("unexpected create sql: {}", create_sql),
1367 }
1368}
1369
1370#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
1371pub struct CommentKey {
1372 pub(crate) object_id: CommentObjectId,
1373 pub(crate) sub_component: Option<usize>,
1374}
1375
1376#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord, Arbitrary)]
1377pub struct CommentValue {
1378 pub(crate) comment: String,
1379}
1380
1381#[derive(Clone, PartialOrd, PartialEq, Eq, Ord, Hash, Debug)]
1382pub struct RoleKey {
1383 pub(crate) id: RoleId,
1384}
1385
1386#[derive(Clone, PartialOrd, PartialEq, Eq, Ord, Debug)]
1387pub struct RoleValue {
1388 pub(crate) name: String,
1389 pub(crate) attributes: RoleAttributes,
1390 pub(crate) membership: RoleMembership,
1391 pub(crate) vars: RoleVars,
1392 pub(crate) oid: u32,
1393}
1394
1395#[derive(Clone, PartialOrd, PartialEq, Eq, Ord, Hash, Debug)]
1396pub struct NetworkPolicyKey {
1397 pub(crate) id: NetworkPolicyId,
1398}
1399
1400#[derive(Clone, PartialOrd, PartialEq, Eq, Ord, Debug)]
1401pub struct NetworkPolicyValue {
1402 pub(crate) name: String,
1403 pub(crate) rules: Vec<NetworkPolicyRule>,
1404 pub(crate) owner_id: RoleId,
1405 pub(crate) privileges: Vec<MzAclItem>,
1406 pub(crate) oid: u32,
1407}
1408
1409#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1410pub struct ConfigKey {
1411 pub(crate) key: String,
1412}
1413
1414#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1415pub struct ConfigValue {
1416 pub(crate) value: u64,
1417}
1418
1419#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1420pub struct AuditLogKey {
1421 pub(crate) event: VersionedEvent,
1422}
1423
1424#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1425pub struct StorageCollectionMetadataKey {
1426 pub(crate) id: GlobalId,
1427}
1428
1429#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1432pub struct StorageCollectionMetadataValue {
1433 pub(crate) shard: ShardId,
1434}
1435
1436#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1439pub struct UnfinalizedShardKey {
1440 pub(crate) shard: ShardId,
1441}
1442
1443#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1446pub struct TxnWalShardValue {
1447 pub(crate) shard: ShardId,
1448}
1449
1450#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1451pub struct ServerConfigurationKey {
1452 pub(crate) name: String,
1453}
1454
1455#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1456pub struct ServerConfigurationValue {
1457 pub(crate) value: String,
1458}
1459
1460#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1461pub struct DefaultPrivilegesKey {
1462 pub(crate) role_id: RoleId,
1463 pub(crate) database_id: Option<DatabaseId>,
1464 pub(crate) schema_id: Option<SchemaId>,
1465 pub(crate) object_type: ObjectType,
1466 pub(crate) grantee: RoleId,
1467}
1468
1469#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1470pub struct DefaultPrivilegesValue {
1471 pub(crate) privileges: AclMode,
1472}
1473
1474#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1475pub struct SystemPrivilegesKey {
1476 pub(crate) grantee: RoleId,
1477 pub(crate) grantor: RoleId,
1478}
1479
1480#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1481pub struct SystemPrivilegesValue {
1482 pub(crate) acl_mode: AclMode,
1483}
1484
1485#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1486pub struct RoleAuthKey {
1487 pub(crate) role_id: RoleId,
1491}
1492
1493#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
1494pub struct RoleAuthValue {
1495 pub(crate) password_hash: Option<String>,
1496 pub(crate) updated_at: u64,
1497}
1498
1499#[cfg(test)]
1500mod test {
1501 use mz_proto::{ProtoType, RustType};
1502 use proptest::prelude::*;
1503
1504 use super::{
1505 DatabaseKey, DatabaseValue, FenceToken, ItemKey, ItemValue, SchemaKey, SchemaValue,
1506 };
1507 use crate::durable::Epoch;
1508
1509 proptest! {
1510 #[mz_ore::test]
1511 #[cfg_attr(miri, ignore)] fn proptest_database_key_roundtrip(key: DatabaseKey) {
1513 let proto = key.into_proto();
1514 let round = proto.into_rust().expect("to roundtrip");
1515
1516 prop_assert_eq!(key, round);
1517 }
1518
1519 #[mz_ore::test]
1520 #[cfg_attr(miri, ignore)] fn proptest_database_value_roundtrip(value: DatabaseValue) {
1522 let proto = value.into_proto();
1523 let round = proto.into_rust().expect("to roundtrip");
1524
1525 prop_assert_eq!(value, round);
1526 }
1527
1528 #[mz_ore::test]
1529 #[cfg_attr(miri, ignore)] fn proptest_schema_key_roundtrip(key: SchemaKey) {
1531 let proto = key.into_proto();
1532 let round = proto.into_rust().expect("to roundtrip");
1533
1534 prop_assert_eq!(key, round);
1535 }
1536
1537 #[mz_ore::test]
1538 #[cfg_attr(miri, ignore)] fn proptest_schema_value_roundtrip(value: SchemaValue) {
1540 let proto = value.into_proto();
1541 let round = proto.into_rust().expect("to roundtrip");
1542
1543 prop_assert_eq!(value, round);
1544 }
1545
1546 #[mz_ore::test]
1547 #[cfg_attr(miri, ignore)] fn proptest_item_key_roundtrip(key: ItemKey) {
1549 let proto = key.into_proto();
1550 let round = proto.into_rust().expect("to roundtrip");
1551
1552 prop_assert_eq!(key, round);
1553 }
1554
1555 #[mz_ore::test]
1556 #[cfg_attr(miri, ignore)] fn proptest_item_value_roundtrip(value: ItemValue) {
1558 let proto = value.into_proto();
1559 let round = proto.into_rust().expect("to roundtrip");
1560
1561 prop_assert_eq!(value, round);
1562 }
1563 }
1564
1565 #[mz_ore::test]
1566 fn test_fence_token_order() {
1567 let ft1 = FenceToken {
1568 deploy_generation: 10,
1569 epoch: Epoch::new(20).expect("non-zero"),
1570 };
1571 let ft2 = FenceToken {
1572 deploy_generation: 10,
1573 epoch: Epoch::new(19).expect("non-zero"),
1574 };
1575
1576 assert!(ft1 > ft2);
1577
1578 let ft3 = FenceToken {
1579 deploy_generation: 11,
1580 epoch: Epoch::new(10).expect("non-zero"),
1581 };
1582
1583 assert!(ft3 > ft1);
1584
1585 let ft4 = FenceToken {
1586 deploy_generation: 11,
1587 epoch: Epoch::new(30).expect("non-zero"),
1588 };
1589
1590 assert!(ft4 > ft1);
1591 }
1592}