@@ -34,6 +34,19 @@ impl BinaryMultiple {
34
34
BinaryMultiple :: Exbi => "e" . to_string ( ) ,
35
35
}
36
36
}
37
+
38
+ /// The exponential scale factor used when converting a `BinaryMultiple`
39
+ /// to another one.
40
+ fn exponential_scale_factor ( & self ) -> i32 {
41
+ match self {
42
+ BinaryMultiple :: Kibi => 1 ,
43
+ BinaryMultiple :: Mebi => 2 ,
44
+ BinaryMultiple :: Gibi => 3 ,
45
+ BinaryMultiple :: Tebi => 4 ,
46
+ BinaryMultiple :: Pebi => 5 ,
47
+ BinaryMultiple :: Exbi => 6 ,
48
+ }
49
+ }
37
50
}
38
51
39
52
impl FromStr for BinaryMultiple {
@@ -56,13 +69,13 @@ impl FromStr for BinaryMultiple {
56
69
57
70
/// Easily transform K8S memory resources to Java heap options.
58
71
#[ derive( Clone , Copy , Debug , PartialEq ) ]
59
- pub struct Memory {
72
+ struct Memory {
60
73
value : f32 ,
61
74
unit : BinaryMultiple ,
62
75
}
63
76
64
77
/// Convert a (memory) [`Quantity`] to Java heap settings.
65
- /// Quantities are usually passed on to container resources whily Java heap
78
+ /// Quantities are usually passed on to container resources while Java heap
66
79
/// sizes need to be scaled accordingly.
67
80
/// This implements a very simple heuristic to ensure that:
68
81
/// - the quantity unit has been mapped to a java supported heap unit. Java only
@@ -84,11 +97,41 @@ pub fn to_java_heap(q: &Quantity, factor: f32) -> OperatorResult<String> {
84
97
}
85
98
}
86
99
100
+ /// Convert a (memory) [`Quantity`] to a raw Java heap value of the desired `target_unit`.
101
+ /// Quantities are usually passed on to container resources while Java heap
102
+ /// sizes need to be scaled accordingly.
103
+ /// The raw heap value is converted to the specified `target_unit` (this conversion
104
+ /// is done even if specified a unit greater that Gibibytes. It is not recommended to scale
105
+ /// to anything bigger than Gibibytes.
106
+ /// This implements a very simple heuristic to ensure that:
107
+ /// - the quantity unit has been mapped to a java supported heap unit. Java only
108
+ /// supports up to Gibibytes while K8S quantities can be expressed in Exbibytes.
109
+ /// - the heap size has a non-zero value.
110
+ /// Fails if it can't enforce the above restrictions.
111
+ pub fn to_java_heap_value (
112
+ q : & Quantity ,
113
+ factor : f32 ,
114
+ target_unit : BinaryMultiple ,
115
+ ) -> OperatorResult < u32 > {
116
+ let scaled = ( q. 0 . parse :: < Memory > ( ) ? * factor)
117
+ . scale_for_java ( )
118
+ . scale_to ( target_unit) ;
119
+
120
+ if scaled. value < 1.0 {
121
+ Err ( Error :: CannotConvertToJavaHeapValue {
122
+ value : q. 0 . to_owned ( ) ,
123
+ target_unit : format ! ( "{:?}" , target_unit) ,
124
+ } )
125
+ } else {
126
+ Ok ( scaled. value as u32 )
127
+ }
128
+ }
129
+
87
130
impl Memory {
88
131
/// Scales the unit to a value supported by Java and may even scale
89
132
/// further down, in an attempt to avoid having zero sizes or losing too
90
133
/// much precision.
91
- pub fn scale_for_java ( & self ) -> Self {
134
+ fn scale_for_java ( & self ) -> Self {
92
135
let ( norm_value, norm_unit) = match self . unit {
93
136
BinaryMultiple :: Kibi => ( self . value , self . unit ) ,
94
137
BinaryMultiple :: Mebi => ( self . value , self . unit ) ,
@@ -114,7 +157,22 @@ impl Memory {
114
157
unit : scaled_unit,
115
158
}
116
159
}
160
+
161
+ /// Scale up or down to the desired `BinaryMultiple`. Returns a new `Memory` and does
162
+ /// not change itself.
163
+ fn scale_to ( & self , binary_multiple : BinaryMultiple ) -> Self {
164
+ let from_exponent: i32 = self . unit . exponential_scale_factor ( ) ;
165
+ let to_exponent: i32 = binary_multiple. exponential_scale_factor ( ) ;
166
+
167
+ let exponent_diff = from_exponent - to_exponent;
168
+
169
+ Memory {
170
+ value : self . value * 1024f32 . powi ( exponent_diff) ,
171
+ unit : binary_multiple,
172
+ }
173
+ }
117
174
}
175
+
118
176
impl Mul < f32 > for Memory {
119
177
type Output = Memory ;
120
178
@@ -167,7 +225,7 @@ mod test {
167
225
#[ case( "0.8Ti" , Memory { value: 0.8f32 , unit: BinaryMultiple :: Tebi } ) ]
168
226
#[ case( "3.2Pi" , Memory { value: 3.2f32 , unit: BinaryMultiple :: Pebi } ) ]
169
227
#[ case( "0.2Ei" , Memory { value: 0.2f32 , unit: BinaryMultiple :: Exbi } ) ]
170
- pub fn test_memory_parse ( #[ case] input : & str , #[ case] output : Memory ) {
228
+ fn test_memory_parse ( #[ case] input : & str , #[ case] output : Memory ) {
171
229
let got = input. parse :: < Memory > ( ) . unwrap ( ) ;
172
230
assert_eq ! ( got, output) ;
173
231
}
@@ -178,7 +236,67 @@ mod test {
178
236
#[ case( "2Mi" , 0.8 , "-Xmx1638k" ) ]
179
237
#[ case( "1.5Gi" , 0.8 , "-Xmx1229m" ) ]
180
238
#[ case( "2Gi" , 0.8 , "-Xmx1638m" ) ]
181
- pub fn test_memory_scale ( #[ case] q : & str , #[ case] factor : f32 , #[ case] heap : & str ) {
239
+ pub fn test_to_java_heap ( #[ case] q : & str , #[ case] factor : f32 , #[ case] heap : & str ) {
182
240
assert_eq ! ( heap, to_java_heap( & Quantity ( q. to_owned( ) ) , factor) . unwrap( ) ) ;
183
241
}
242
+
243
+ #[ rstest]
244
+ #[ case( 2000f32 , BinaryMultiple :: Kibi , BinaryMultiple :: Kibi , 2000f32 ) ]
245
+ #[ case( 2000f32 , BinaryMultiple :: Kibi , BinaryMultiple :: Mebi , 2000f32 /1024f32 ) ]
246
+ #[ case( 2000f32 , BinaryMultiple :: Kibi , BinaryMultiple :: Gibi , 2000f32 /1024f32 /1024f32 ) ]
247
+ #[ case( 2000f32 , BinaryMultiple :: Kibi , BinaryMultiple :: Tebi , 2000f32 /1024f32 /1024f32 /1024f32 ) ]
248
+ #[ case( 2000f32 , BinaryMultiple :: Kibi , BinaryMultiple :: Pebi , 2000f32 /1024f32 /1024f32 /1024f32 /1024f32 ) ]
249
+ #[ case( 2000f32 , BinaryMultiple :: Pebi , BinaryMultiple :: Mebi , 2000f32 * 1024f32 * 1024f32 * 1024f32 ) ]
250
+ #[ case( 2000f32 , BinaryMultiple :: Pebi , BinaryMultiple :: Kibi , 2000f32 * 1024f32 * 1024f32 * 1024f32 * 1024f32 ) ]
251
+ #[ case( 2000f32 , BinaryMultiple :: Exbi , BinaryMultiple :: Pebi , 2000f32 * 1024f32 ) ]
252
+ pub fn test_scale_to (
253
+ #[ case] value : f32 ,
254
+ #[ case] unit : BinaryMultiple ,
255
+ #[ case] target_unit : BinaryMultiple ,
256
+ #[ case] expected : f32 ,
257
+ ) {
258
+ let memory = Memory { value, unit } ;
259
+ let scaled_memory = memory. scale_to ( target_unit) ;
260
+ assert_eq ! ( scaled_memory. value, expected) ;
261
+ }
262
+
263
+ #[ rstest]
264
+ #[ case( "256Ki" , 1.0 , BinaryMultiple :: Kibi , 256 ) ]
265
+ #[ case( "256Ki" , 0.8 , BinaryMultiple :: Kibi , 204 ) ]
266
+ #[ case( "2Mi" , 0.8 , BinaryMultiple :: Kibi , 1638 ) ]
267
+ #[ case( "1.5Gi" , 0.8 , BinaryMultiple :: Mebi , 1228 ) ]
268
+ #[ case( "2Gi" , 0.8 , BinaryMultiple :: Mebi , 1638 ) ]
269
+ #[ case( "2Ti" , 0.8 , BinaryMultiple :: Mebi , 1677721 ) ]
270
+ #[ case( "2Ti" , 0.8 , BinaryMultiple :: Gibi , 1638 ) ]
271
+ #[ case( "2Ti" , 1.0 , BinaryMultiple :: Gibi , 2048 ) ]
272
+ #[ case( "2048Ki" , 1.0 , BinaryMultiple :: Mebi , 2 ) ]
273
+ #[ case( "2000Ki" , 1.0 , BinaryMultiple :: Mebi , 1 ) ]
274
+ #[ case( "4000Mi" , 1.0 , BinaryMultiple :: Gibi , 3 ) ]
275
+ #[ case( "4000Mi" , 0.8 , BinaryMultiple :: Gibi , 3 ) ]
276
+ pub fn test_to_java_heap_value (
277
+ #[ case] q : & str ,
278
+ #[ case] factor : f32 ,
279
+ #[ case] target_unit : BinaryMultiple ,
280
+ #[ case] heap : u32 ,
281
+ ) {
282
+ assert_eq ! (
283
+ to_java_heap_value( & Quantity ( q. to_owned( ) ) , factor, target_unit) . unwrap( ) ,
284
+ heap
285
+ ) ;
286
+ }
287
+
288
+ #[ rstest]
289
+ #[ case( "1000Ki" , 0.8 , BinaryMultiple :: Gibi ) ]
290
+ #[ case( "1000Ki" , 0.8 , BinaryMultiple :: Mebi ) ]
291
+ #[ case( "1000Mi" , 0.8 , BinaryMultiple :: Gibi ) ]
292
+ #[ case( "1000Mi" , 1.0 , BinaryMultiple :: Gibi ) ]
293
+ #[ case( "1023Mi" , 1.0 , BinaryMultiple :: Gibi ) ]
294
+ #[ case( "1024Mi" , 0.8 , BinaryMultiple :: Gibi ) ]
295
+ pub fn test_to_java_heap_value_failure (
296
+ #[ case] q : & str ,
297
+ #[ case] factor : f32 ,
298
+ #[ case] target_unit : BinaryMultiple ,
299
+ ) {
300
+ assert ! ( to_java_heap_value( & Quantity ( q. to_owned( ) ) , factor, target_unit) . is_err( ) ) ;
301
+ }
184
302
}
0 commit comments