Browse Source
Merge pull request #2025 from bingoohuang/master
Merge pull request #2025 from bingoohuang/master
improvement for minFreeSpace argumentpull/2030/head
Chris Lu
4 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 305 additions and 35 deletions
-
2unmaintained/repeated_vacuum/repeated_vacuum.go
-
9weed/command/server.go
-
28weed/command/volume.go
-
4weed/server/volume_server.go
-
18weed/storage/disk_location.go
-
6weed/storage/store.go
-
95weed/util/bytes.go
-
59weed/util/bytes_test.go
-
90weed/util/minfreespace.go
-
29weed/util/minfreespace_test.go
@ -0,0 +1,59 @@ |
|||
package util |
|||
|
|||
import "testing" |
|||
|
|||
func TestByteParsing(t *testing.T) { |
|||
tests := []struct { |
|||
in string |
|||
exp uint64 |
|||
}{ |
|||
{"42", 42}, |
|||
{"42MB", 42000000}, |
|||
{"42MiB", 44040192}, |
|||
{"42mb", 42000000}, |
|||
{"42mib", 44040192}, |
|||
{"42MIB", 44040192}, |
|||
{"42 MB", 42000000}, |
|||
{"42 MiB", 44040192}, |
|||
{"42 mb", 42000000}, |
|||
{"42 mib", 44040192}, |
|||
{"42 MIB", 44040192}, |
|||
{"42.5MB", 42500000}, |
|||
{"42.5MiB", 44564480}, |
|||
{"42.5 MB", 42500000}, |
|||
{"42.5 MiB", 44564480}, |
|||
// No need to say B
|
|||
{"42M", 42000000}, |
|||
{"42Mi", 44040192}, |
|||
{"42m", 42000000}, |
|||
{"42mi", 44040192}, |
|||
{"42MI", 44040192}, |
|||
{"42 M", 42000000}, |
|||
{"42 Mi", 44040192}, |
|||
{"42 m", 42000000}, |
|||
{"42 mi", 44040192}, |
|||
{"42 MI", 44040192}, |
|||
{"42.5M", 42500000}, |
|||
{"42.5Mi", 44564480}, |
|||
{"42.5 M", 42500000}, |
|||
{"42.5 Mi", 44564480}, |
|||
// Bug #42
|
|||
{"1,005.03 MB", 1005030000}, |
|||
// Large testing, breaks when too much larger than
|
|||
// this.
|
|||
{"12.5 EB", uint64(12.5 * float64(EByte))}, |
|||
{"12.5 E", uint64(12.5 * float64(EByte))}, |
|||
{"12.5 EiB", uint64(12.5 * float64(EiByte))}, |
|||
} |
|||
|
|||
for _, p := range tests { |
|||
got, err := ParseBytes(p.in) |
|||
if err != nil { |
|||
t.Errorf("Couldn't parse %v: %v", p.in, err) |
|||
} |
|||
if got != p.exp { |
|||
t.Errorf("Expected %v for %v, got %v", |
|||
p.exp, p.in, got) |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,90 @@ |
|||
package util |
|||
|
|||
import ( |
|||
"errors" |
|||
"fmt" |
|||
"github.com/chrislusf/seaweedfs/weed/glog" |
|||
"strconv" |
|||
"strings" |
|||
) |
|||
|
|||
// MinFreeSpaceType is the type of MinFreeSpace.
|
|||
type MinFreeSpaceType int |
|||
|
|||
const ( |
|||
// AsPercent set the MinFreeSpaceType to a percentage value from 0 to 100.
|
|||
AsPercent MinFreeSpaceType = iota |
|||
// AsBytes set the MinFreeSpaceType to a absolute value bytes.
|
|||
AsBytes |
|||
) |
|||
|
|||
// MinFreeSpace is type that defines the limit for the minimum free space.
|
|||
type MinFreeSpace struct { |
|||
Type MinFreeSpaceType |
|||
Bytes uint64 |
|||
Percent float32 |
|||
Raw string |
|||
} |
|||
|
|||
// IsLow tells whether the free space is low or not.
|
|||
func (s MinFreeSpace) IsLow(freeBytes uint64, freePercent float32) (yes bool, desc string) { |
|||
switch s.Type { |
|||
case AsPercent: |
|||
yes = freePercent < s.Percent |
|||
op := IfElse(yes, "<", ">=") |
|||
return yes, fmt.Sprintf("disk free %.2f%% %s required %.2f%%", freePercent, op, s.Percent) |
|||
case AsBytes: |
|||
yes = freeBytes < s.Bytes |
|||
op := IfElse(yes, "<", ">=") |
|||
return yes, fmt.Sprintf("disk free %s %s required %s", |
|||
BytesToHumanReadable(freeBytes), op, BytesToHumanReadable(s.Bytes)) |
|||
} |
|||
|
|||
return false, "" |
|||
} |
|||
|
|||
// String returns a string representation of MinFreeSpace.
|
|||
func (s MinFreeSpace) String() string { |
|||
switch s.Type { |
|||
case AsPercent: |
|||
return fmt.Sprintf("%.2f%%", s.Percent) |
|||
default: |
|||
return s.Raw |
|||
} |
|||
} |
|||
|
|||
// MustParseMinFreeSpace parses comma-separated argument for min free space setting.
|
|||
// minFreeSpace has the high priority than minFreeSpacePercent if it is set.
|
|||
func MustParseMinFreeSpace(minFreeSpace string, minFreeSpacePercent string) (spaces []MinFreeSpace) { |
|||
ss := strings.Split(EmptyTo(minFreeSpace, minFreeSpacePercent), ",") |
|||
for _, freeString := range ss { |
|||
if vv, e := ParseMinFreeSpace(freeString); e == nil { |
|||
spaces = append(spaces, *vv) |
|||
} else { |
|||
glog.Fatalf("The value specified in -minFreeSpace not a valid value %s", freeString) |
|||
} |
|||
} |
|||
|
|||
return spaces |
|||
} |
|||
|
|||
var ErrMinFreeSpaceBadValue = errors.New("minFreeSpace is invalid") |
|||
|
|||
// ParseMinFreeSpace parses min free space expression s as percentage like 1,10 or human readable size like 10G
|
|||
func ParseMinFreeSpace(s string) (*MinFreeSpace, error) { |
|||
if percent, e := strconv.ParseFloat(s, 32); e == nil { |
|||
if percent < 0 || percent > 100 { |
|||
return nil, ErrMinFreeSpaceBadValue |
|||
} |
|||
return &MinFreeSpace{Type: AsPercent, Percent: float32(percent), Raw: s}, nil |
|||
} |
|||
|
|||
if directSize, e := ParseBytes(s); e == nil { |
|||
if directSize <= 100 { |
|||
return nil, ErrMinFreeSpaceBadValue |
|||
} |
|||
return &MinFreeSpace{Type: AsBytes, Bytes: directSize, Raw: s}, nil |
|||
} |
|||
|
|||
return nil, ErrMinFreeSpaceBadValue |
|||
} |
@ -0,0 +1,29 @@ |
|||
package util |
|||
|
|||
import "testing" |
|||
|
|||
func TestParseMinFreeSpace(t *testing.T) { |
|||
tests := []struct { |
|||
in string |
|||
ok bool |
|||
value *MinFreeSpace |
|||
}{ |
|||
{in: "42", ok: true, value: &MinFreeSpace{Type: AsPercent, Percent: 42, Raw: "42"}}, |
|||
{in: "-1", ok: false, value: nil}, |
|||
{in: "101", ok: false, value: nil}, |
|||
{in: "100B", ok: false, value: nil}, |
|||
{in: "100Ki", ok: true, value: &MinFreeSpace{Type: AsBytes, Bytes: 100 * 1024, Raw: "100Ki"}}, |
|||
{in: "100GiB", ok: true, value: &MinFreeSpace{Type: AsBytes, Bytes: 100 * 1024 * 1024 * 1024, Raw: "100GiB"}}, |
|||
{in: "42M", ok: true, value: &MinFreeSpace{Type: AsBytes, Bytes: 42 * 1000 * 1000, Raw: "42M"}}, |
|||
} |
|||
|
|||
for _, p := range tests { |
|||
got, err := ParseMinFreeSpace(p.in) |
|||
if p.ok != (err == nil) { |
|||
t.Errorf("failed to test %v", p.in) |
|||
} |
|||
if p.ok && err == nil && *got != *p.value { |
|||
t.Errorf("failed to test %v", p.in) |
|||
} |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue