1111
1212use std:: collections:: { BTreeMap , BTreeSet } ;
1313use std:: fmt;
14+ use std:: num:: NonZero ;
1415use std:: str:: FromStr ;
1516use std:: sync:: Arc ;
1617use std:: sync:: LazyLock ;
@@ -34,9 +35,9 @@ use mz_orchestrator::{
3435 CpuLimit , DiskLimit , LabelSelectionLogic , LabelSelector , MemoryLimit , Service , ServiceConfig ,
3536 ServiceEvent , ServicePort ,
3637} ;
37- use mz_ore:: halt;
38- use mz_ore:: instrument;
38+ use mz_ore:: cast:: CastInto ;
3939use mz_ore:: task:: { self , AbortOnDropHandle } ;
40+ use mz_ore:: { halt, instrument} ;
4041use mz_repr:: GlobalId ;
4142use mz_repr:: adt:: numeric:: Numeric ;
4243use regex:: Regex ;
@@ -80,9 +81,9 @@ pub struct ReplicaAllocation {
8081 /// The disk limit for each process in the replica.
8182 pub disk_limit : Option < DiskLimit > ,
8283 /// The number of processes in the replica.
83- pub scale : u16 ,
84+ pub scale : NonZero < u16 > ,
8485 /// The number of worker threads in the replica.
85- pub workers : usize ,
86+ pub workers : NonZero < usize > ,
8687 /// The number of credits per hour that the replica consumes.
8788 #[ serde( deserialize_with = "mz_repr::adt::numeric::str_serde::deserialize" ) ]
8889 pub credits_per_hour : Numeric ,
@@ -113,6 +114,7 @@ fn default_true() -> bool {
113114#[ cfg_attr( miri, ignore) ] // unsupported operation: can't call foreign function `decContextDefault` on OS `linux`
114115fn test_replica_allocation_deserialization ( ) {
115116 use bytesize:: ByteSize ;
117+ use mz_ore:: { assert_err, assert_ok} ;
116118
117119 let data = r#"
118120 {
@@ -143,8 +145,8 @@ fn test_replica_allocation_deserialization() {
143145 cpu_exclusive: false ,
144146 is_cc: true ,
145147 swap_enabled: true ,
146- scale: 16 ,
147- workers: 1 ,
148+ scale: NonZero :: new ( 16 ) . unwrap ( ) ,
149+ workers: NonZero :: new ( 1 ) . unwrap ( ) ,
148150 selectors: BTreeMap :: from( [
149151 ( "key1" . to_string( ) , "value1" . to_string( ) ) ,
150152 ( "key2" . to_string( ) , "value2" . to_string( ) )
@@ -157,8 +159,8 @@ fn test_replica_allocation_deserialization() {
157159 "cpu_limit": 0,
158160 "memory_limit": "0GiB",
159161 "disk_limit": "0MiB",
160- "scale": 0 ,
161- "workers": 0 ,
162+ "scale": 1 ,
163+ "workers": 1 ,
162164 "credits_per_hour": "0",
163165 "cpu_exclusive": true,
164166 "disabled": true
@@ -178,11 +180,19 @@ fn test_replica_allocation_deserialization() {
178180 cpu_exclusive: true ,
179181 is_cc: true ,
180182 swap_enabled: false ,
181- scale: 0 ,
182- workers: 0 ,
183+ scale: NonZero :: new ( 1 ) . unwrap ( ) ,
184+ workers: NonZero :: new ( 1 ) . unwrap ( ) ,
183185 selectors: Default :: default ( ) ,
184186 }
185187 ) ;
188+
189+ // `scale` and `workers` must be non-zero.
190+ let data = r#"{"scale": 0, "workers": 1, "credits_per_hour": "0"}"# ;
191+ assert_err ! ( serde_json:: from_str:: <ReplicaAllocation >( data) ) ;
192+ let data = r#"{"scale": 1, "workers": 0, "credits_per_hour": "0"}"# ;
193+ assert_err ! ( serde_json:: from_str:: <ReplicaAllocation >( data) ) ;
194+ let data = r#"{"scale": 1, "workers": 1, "credits_per_hour": "0"}"# ;
195+ assert_ok ! ( serde_json:: from_str:: <ReplicaAllocation >( data) ) ;
186196}
187197
188198/// Configures the location of a cluster replica.
@@ -202,7 +212,7 @@ impl ReplicaLocation {
202212 computectl_addrs, ..
203213 } ) => computectl_addrs. len ( ) ,
204214 ReplicaLocation :: Managed ( ManagedReplicaLocation { allocation, .. } ) => {
205- allocation. scale . into ( )
215+ allocation. scale . cast_into ( )
206216 }
207217 }
208218 }
@@ -229,7 +239,7 @@ impl ReplicaLocation {
229239 pub fn workers ( & self ) -> Option < usize > {
230240 match self {
231241 ReplicaLocation :: Managed ( ManagedReplicaLocation { allocation, .. } ) => {
232- Some ( allocation. workers * self . num_processes ( ) )
242+ Some ( allocation. workers . get ( ) * self . num_processes ( ) )
233243 }
234244 ReplicaLocation :: Unmanaged ( _) => None ,
235245 }
@@ -661,12 +671,12 @@ where
661671 init_container_image : self . init_container_image . clone ( ) ,
662672 args : Box :: new ( move |assigned| {
663673 let storage_timely_config = TimelyConfig {
664- workers : location. allocation . workers ,
674+ workers : location. allocation . workers . get ( ) ,
665675 addresses : assigned. peer_addresses ( "storage" ) ,
666676 ..storage_proto_timely_config
667677 } ;
668678 let compute_timely_config = TimelyConfig {
669- workers : location. allocation . workers ,
679+ workers : location. allocation . workers . get ( ) ,
670680 addresses : assigned. peer_addresses ( "compute" ) ,
671681 ..compute_proto_timely_config
672682 } ;
0 commit comments