diff --git a/cmd/neofs-node/config/cast.go b/cmd/neofs-node/config/cast.go index c4b7e602b..5a92675f8 100644 --- a/cmd/neofs-node/config/cast.go +++ b/cmd/neofs-node/config/cast.go @@ -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 + } + + n = s + multiplier >>= 10 + } + + hi, lo := bits.Mul64(n, multiplier) + if hi != 0 { return 0 } - return c + 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) } diff --git a/cmd/neofs-node/config/cast_test.go b/cmd/neofs-node/config/cast_test.go index 8ff493a63..85b6e1e95 100644 --- a/cmd/neofs-node/config/cast_test.go +++ b/cmd/neofs-node/config/cast_test.go @@ -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")) }) diff --git a/cmd/neofs-node/config/test/config.json b/cmd/neofs-node/config/test/config.json index e1f1da781..45635c7ab 100644 --- a/cmd/neofs-node/config/test/config.json +++ b/cmd/neofs-node/config/test/config.json @@ -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 }, diff --git a/cmd/neofs-node/config/test/config.yaml b/cmd/neofs-node/config/test/config.yaml index e2e6d3aa9..102c045a1 100644 --- a/cmd/neofs-node/config/test/config.yaml +++ b/cmd/neofs-node/config/test/config.yaml @@ -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