forked from TrueCloudLab/frostfs-node
[#903] config: support floating-point sizes
Rounding is done using the suffix boundary (i.e. floating point value with `gb` suffix will return size which is an integer number of megabytes). Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
parent
e7fd980951
commit
aba09bb853
4 changed files with 31 additions and 5 deletions
|
@ -1,6 +1,7 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"math/bits"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
|
@ -164,12 +165,28 @@ func SizeInBytesSafe(c *Config, name string) uint64 {
|
|||
// with minor corrections (allow to use both `k` and `kb` forms.
|
||||
// Seems like viper allows to convert sizes but corresponding parser in `cast` package
|
||||
// is missing.
|
||||
func safeMul(a, b uint64) uint64 {
|
||||
c := a * b
|
||||
if a > 1 && b > 1 && c/b != a {
|
||||
|
||||
// safeMul returns size*multiplier, rounding down to the
|
||||
// multiplier/1024 number of bytes.
|
||||
// Returns 0 if overflow is detected.
|
||||
func safeMul(size float64, multiplier uint64) uint64 {
|
||||
n := uint64(size)
|
||||
f := uint64((size - float64(n)) * 1024)
|
||||
if f != 0 && multiplier != 1 {
|
||||
s := n<<10 + f
|
||||
if s < n {
|
||||
return 0
|
||||
}
|
||||
return c
|
||||
|
||||
n = s
|
||||
multiplier >>= 10
|
||||
}
|
||||
|
||||
hi, lo := bits.Mul64(n, multiplier)
|
||||
if hi != 0 {
|
||||
return 0
|
||||
}
|
||||
return lo
|
||||
}
|
||||
|
||||
// parseSizeInBytes converts strings like 1GB or 12 mb into an unsigned integer number of bytes
|
||||
|
@ -203,6 +220,6 @@ func parseSizeInBytes(sizeStr string) uint64 {
|
|||
}
|
||||
}
|
||||
|
||||
size := cast.ToUint64(sizeStr)
|
||||
size := cast.ToFloat64(sizeStr)
|
||||
return safeMul(size, multiplier)
|
||||
}
|
||||
|
|
|
@ -130,6 +130,9 @@ func TestSizeInBytes(t *testing.T) {
|
|||
require.EqualValues(t, 12*mb, config.SizeInBytesSafe(c, "size_mb"))
|
||||
require.EqualValues(t, 4*gb, config.SizeInBytesSafe(c, "size_gb"))
|
||||
require.EqualValues(t, 5*tb, config.SizeInBytesSafe(c, "size_tb"))
|
||||
require.EqualValues(t, 12, config.SizeInBytesSafe(c, "size_i_am_not_very_clever"))
|
||||
require.EqualValues(t, tb/2, config.SizeInBytesSafe(c, "size_float"))
|
||||
require.EqualValues(t, uint64(14*gb+(gb*123/1000/mb*mb)), config.SizeInBytesSafe(c, "size_float_big"))
|
||||
require.EqualValues(t, 2048, config.SizeInBytesSafe(c, "size_bytes"))
|
||||
require.EqualValues(t, 123456, config.SizeInBytesSafe(c, "size_bytes_no_suffix"))
|
||||
})
|
||||
|
|
|
@ -54,6 +54,9 @@
|
|||
"size_mb": "12m",
|
||||
"size_gb": "4g",
|
||||
"size_tb": "5 TB",
|
||||
"size_float": ".5t",
|
||||
"size_float_big": "14.123 gb",
|
||||
"size_i_am_not_very_clever": "12.12345678",
|
||||
"size_bytes": "2048b",
|
||||
"size_bytes_no_suffix": 123456
|
||||
},
|
||||
|
|
|
@ -47,6 +47,9 @@ sizes:
|
|||
size_mb: 12m
|
||||
size_gb: 4g
|
||||
size_tb: 5 TB
|
||||
size_float: .5t
|
||||
size_float_big: 14.123 gb
|
||||
size_i_am_not_very_clever: 12.12345678
|
||||
size_bytes: 2048b
|
||||
size_bytes_no_suffix: 123456
|
||||
|
||||
|
|
Loading…
Reference in a new issue