mz_storage_types/
instances.rs
1use std::fmt;
13use std::str::FromStr;
14
15use anyhow::bail;
16use mz_proto::{RustType, TryFromProtoError};
17use proptest::prelude::{Arbitrary, Strategy};
18use proptest::strategy::BoxedStrategy;
19use serde::{Deserialize, Serialize};
20use tracing::error;
21
22include!(concat!(env!("OUT_DIR"), "/mz_storage_types.instances.rs"));
23
24#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
26pub enum StorageInstanceId {
27 System(u64),
29 User(u64),
31}
32
33impl StorageInstanceId {
34 pub fn system(id: u64) -> Option<Self> {
38 Self::new(id, Self::System)
39 }
40
41 pub fn user(id: u64) -> Option<Self> {
45 Self::new(id, Self::User)
46 }
47
48 fn new(id: u64, variant: fn(u64) -> Self) -> Option<Self> {
49 const MASK: u64 = 0xFFFF << 48;
50 const WARN_MASK: u64 = 1 << 47;
51 if MASK & id == 0 {
52 if WARN_MASK & id != 0 {
53 error!("{WARN_MASK} or more `StorageInstanceId`s allocated, we will run out soon");
54 }
55 Some(variant(id))
56 } else {
57 None
58 }
59 }
60
61 pub fn inner_id(&self) -> u64 {
62 match self {
63 StorageInstanceId::System(id) | StorageInstanceId::User(id) => *id,
64 }
65 }
66
67 pub fn is_user(&self) -> bool {
68 matches!(self, Self::User(_))
69 }
70
71 pub fn is_system(&self) -> bool {
72 matches!(self, Self::System(_))
73 }
74}
75
76impl FromStr for StorageInstanceId {
77 type Err = anyhow::Error;
78
79 fn from_str(s: &str) -> Result<Self, Self::Err> {
80 if s.len() < 2 {
81 bail!("couldn't parse compute instance id {}", s);
82 }
83 let val: u64 = s[1..].parse()?;
84 match s.chars().next().unwrap() {
85 's' => Ok(Self::System(val)),
86 'u' => Ok(Self::User(val)),
87 _ => bail!("couldn't parse compute instance id {}", s),
88 }
89 }
90}
91
92impl fmt::Display for StorageInstanceId {
93 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
94 match self {
95 Self::System(id) => write!(f, "s{}", id),
96 Self::User(id) => write!(f, "u{}", id),
97 }
98 }
99}
100
101impl RustType<ProtoStorageInstanceId> for StorageInstanceId {
102 fn into_proto(&self) -> ProtoStorageInstanceId {
103 use proto_storage_instance_id::Kind::*;
104 ProtoStorageInstanceId {
105 kind: Some(match self {
106 StorageInstanceId::System(x) => System(*x),
107 StorageInstanceId::User(x) => User(*x),
108 }),
109 }
110 }
111
112 fn from_proto(proto: ProtoStorageInstanceId) -> Result<Self, TryFromProtoError> {
113 use proto_storage_instance_id::Kind::*;
114 match proto.kind {
115 Some(System(x)) => StorageInstanceId::system(x).ok_or_else(|| {
116 TryFromProtoError::InvalidPersistState(format!(
117 "{x} is not a valid StorageInstanceId"
118 ))
119 }),
120 Some(User(x)) => StorageInstanceId::user(x).ok_or_else(|| {
121 TryFromProtoError::InvalidPersistState(format!(
122 "{x} is not a valid StorageInstanceId"
123 ))
124 }),
125 None => Err(TryFromProtoError::missing_field(
126 "ProtoStorageInstanceId::kind",
127 )),
128 }
129 }
130}
131
132impl Arbitrary for StorageInstanceId {
133 type Parameters = ();
134
135 fn arbitrary_with((): Self::Parameters) -> Self::Strategy {
136 const UPPER_BOUND: u64 = 1 << 47;
137 (0..2, 0..UPPER_BOUND)
138 .prop_map(|(variant, id)| match variant {
139 0 => StorageInstanceId::System(id),
140 1 => StorageInstanceId::User(id),
141 _ => unreachable!(),
142 })
143 .boxed()
144 }
145
146 type Strategy = BoxedStrategy<StorageInstanceId>;
147}