From 2c9636d9130c5843a5225c5abddcfbaa4fc6b26b Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Sun, 21 Jul 2024 13:31:40 +0200 Subject: [PATCH 1/5] *: update minimum go version to go1.18 This allows us to start using some new features, like strings.Cut Signed-off-by: Sebastiaan van Stijn --- .github/workflows/test.yml | 2 +- mount/go.mod | 2 +- mountinfo/go.mod | 2 +- sequential/go.mod | 2 +- signal/go.mod | 2 +- symlink/go.mod | 2 +- user/go.mod | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c92b3a58..5a73adff 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,7 +4,7 @@ jobs: test: strategy: matrix: - go-version: [1.17.x, 1.21.x, 1.22.x] + go-version: [1.18.x, 1.21.x, 1.22.x] platform: [ubuntu-20.04, ubuntu-22.04, ubuntu-24.04, windows-latest, macos-12, macos-14] runs-on: ${{ matrix.platform }} steps: diff --git a/mount/go.mod b/mount/go.mod index 000363d7..046fd514 100644 --- a/mount/go.mod +++ b/mount/go.mod @@ -1,6 +1,6 @@ module github.com/moby/sys/mount -go 1.17 +go 1.18 require ( github.com/moby/sys/mountinfo v0.7.2 diff --git a/mountinfo/go.mod b/mountinfo/go.mod index 42a37060..029f7374 100644 --- a/mountinfo/go.mod +++ b/mountinfo/go.mod @@ -1,5 +1,5 @@ module github.com/moby/sys/mountinfo -go 1.17 +go 1.18 require golang.org/x/sys v0.1.0 diff --git a/sequential/go.mod b/sequential/go.mod index 4e620fe1..2403a3d0 100644 --- a/sequential/go.mod +++ b/sequential/go.mod @@ -1,5 +1,5 @@ module github.com/moby/sys/sequential -go 1.17 +go 1.18 require golang.org/x/sys v0.1.0 diff --git a/signal/go.mod b/signal/go.mod index f76c5ad3..29a7be48 100644 --- a/signal/go.mod +++ b/signal/go.mod @@ -1,5 +1,5 @@ module github.com/moby/sys/signal -go 1.17 +go 1.18 require golang.org/x/sys v0.1.0 diff --git a/symlink/go.mod b/symlink/go.mod index 9b73f0c5..01b5b515 100644 --- a/symlink/go.mod +++ b/symlink/go.mod @@ -1,5 +1,5 @@ module github.com/moby/sys/symlink -go 1.17 +go 1.18 require golang.org/x/sys v0.1.0 diff --git a/user/go.mod b/user/go.mod index 1c62fac9..94e2d1f3 100644 --- a/user/go.mod +++ b/user/go.mod @@ -1,5 +1,5 @@ module github.com/moby/sys/user -go 1.17 +go 1.18 require golang.org/x/sys v0.1.0 From 59f6cd328d68fdf68968df03fd920b4851280fb3 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Sun, 21 Jul 2024 13:51:47 +0200 Subject: [PATCH 2/5] mount: MergeTmpfsOptions: use strings.Cut it's faster, and uses less allocations. Signed-off-by: Sebastiaan van Stijn --- mount/flags_unix.go | 8 ++++---- mount/mounter_linux_test.go | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/mount/flags_unix.go b/mount/flags_unix.go index 19fa61fc..ad3ba0a7 100644 --- a/mount/flags_unix.go +++ b/mount/flags_unix.go @@ -100,14 +100,14 @@ func MergeTmpfsOptions(options []string) ([]string, error) { } continue } - opt := strings.SplitN(option, "=", 2) - if len(opt) != 2 || !validFlags[opt[0]] { + opt, _, ok := strings.Cut(option, "=") + if !ok || !validFlags[opt] { return nil, fmt.Errorf("invalid tmpfs option %q", opt) } - if !dataCollisions[opt[0]] { + if !dataCollisions[opt] { // We prepend the option and add to collision map newOptions = append([]string{option}, newOptions...) - dataCollisions[opt[0]] = true + dataCollisions[opt] = true } } diff --git a/mount/mounter_linux_test.go b/mount/mounter_linux_test.go index 8d5c87ab..461deb49 100644 --- a/mount/mounter_linux_test.go +++ b/mount/mounter_linux_test.go @@ -212,7 +212,8 @@ func validateMount(t *testing.T, mnt string, opts, optional, vfs string) { // clean strips off any value param after the colon func clean(v string) string { - return strings.SplitN(v, ":", 2)[0] + out, _, _ := strings.Cut(v, ":") + return out } // has returns true if key is a member of m From 7a59c4272dcb5a6636f648e0680c98fe49cbced4 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Sat, 7 Aug 2021 12:41:04 +0200 Subject: [PATCH 3/5] mountinfo: add "toInt()" utility Signed-off-by: Sebastiaan van Stijn --- mountinfo/mountinfo_linux.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/mountinfo/mountinfo_linux.go b/mountinfo/mountinfo_linux.go index b32b5c9b..6951cc25 100644 --- a/mountinfo/mountinfo_linux.go +++ b/mountinfo/mountinfo_linux.go @@ -75,7 +75,10 @@ func GetMountsFromReader(r io.Reader, filter FilterFunc) ([]*Info, error) { } } - p := &Info{} + p := &Info{ + ID: toInt(fields[0]), + Parent: toInt(fields[1]), + } p.Mountpoint, err = unescape(fields[4]) if err != nil { @@ -91,15 +94,12 @@ func GetMountsFromReader(r io.Reader, filter FilterFunc) ([]*Info, error) { } p.VFSOptions = fields[sepIdx+3] - // ignore any numbers parsing errors, as there should not be any - p.ID, _ = strconv.Atoi(fields[0]) - p.Parent, _ = strconv.Atoi(fields[1]) mm := strings.SplitN(fields[2], ":", 3) if len(mm) != 2 { return nil, fmt.Errorf("parsing '%s' failed: unexpected major:minor pair %s", text, mm) } - p.Major, _ = strconv.Atoi(mm[0]) - p.Minor, _ = strconv.Atoi(mm[1]) + p.Major = toInt(mm[0]) + p.Minor = toInt(mm[1]) p.Root, err = unescape(fields[3]) if err != nil { @@ -248,3 +248,10 @@ func unescape(path string) (string, error) { return string(buf[:bufLen]), nil } + +// toInt converts a string to an int, and ignores any numbers parsing errors, +// as there should not be any. +func toInt(s string) int { + i, _ := strconv.Atoi(s) + return i +} From cb890fce77e717affe6e99d55c8df602fa7abada Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Sun, 21 Jul 2024 13:21:13 +0200 Subject: [PATCH 4/5] mountinfo: GetMountsFromReader: use strings.Cut It's faster, and reduces 410 allocations (1976 -> 1566). Before: go test -v -test.benchmem -count=10 -run ^$ -bench BenchmarkParseMountinfo . go: downloading golang.org/x/sys v0.1.0 goos: linux goarch: arm64 pkg: github.com/moby/sys/mountinfo BenchmarkParseMountinfo BenchmarkParseMountinfo-10 4405 283442 ns/op 245426 B/op 1976 allocs/op BenchmarkParseMountinfo-10 4180 258441 ns/op 245425 B/op 1976 allocs/op BenchmarkParseMountinfo-10 4146 258770 ns/op 245425 B/op 1976 allocs/op BenchmarkParseMountinfo-10 4180 259924 ns/op 245425 B/op 1976 allocs/op BenchmarkParseMountinfo-10 4162 263537 ns/op 245425 B/op 1976 allocs/op BenchmarkParseMountinfo-10 4218 261200 ns/op 245425 B/op 1976 allocs/op BenchmarkParseMountinfo-10 4746 259271 ns/op 245425 B/op 1976 allocs/op BenchmarkParseMountinfo-10 4362 265330 ns/op 245425 B/op 1976 allocs/op BenchmarkParseMountinfo-10 4454 263110 ns/op 245425 B/op 1976 allocs/op BenchmarkParseMountinfo-10 4134 266847 ns/op 245425 B/op 1976 allocs/op PASS ok github.com/moby/sys/mountinfo 11.653s After go test -v -test.benchmem -count=10 -run ^$ -bench BenchmarkParseMountinfo . go: downloading golang.org/x/sys v0.1.0 goos: linux goarch: arm64 pkg: github.com/moby/sys/mountinfo BenchmarkParseMountinfo BenchmarkParseMountinfo-10 4544 262155 ns/op 225746 B/op 1566 allocs/op BenchmarkParseMountinfo-10 4447 266108 ns/op 225745 B/op 1566 allocs/op BenchmarkParseMountinfo-10 4522 246329 ns/op 225745 B/op 1566 allocs/op BenchmarkParseMountinfo-10 4311 249786 ns/op 225745 B/op 1566 allocs/op BenchmarkParseMountinfo-10 4612 250989 ns/op 225745 B/op 1566 allocs/op BenchmarkParseMountinfo-10 4588 249702 ns/op 225745 B/op 1566 allocs/op BenchmarkParseMountinfo-10 4342 247774 ns/op 225745 B/op 1566 allocs/op BenchmarkParseMountinfo-10 4530 246963 ns/op 225745 B/op 1566 allocs/op BenchmarkParseMountinfo-10 4690 248594 ns/op 225745 B/op 1566 allocs/op BenchmarkParseMountinfo-10 4455 254278 ns/op 225745 B/op 1566 allocs/op PASS ok github.com/moby/sys/mountinfo 11.660s Signed-off-by: Sebastiaan van Stijn --- mountinfo/mountinfo_linux.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mountinfo/mountinfo_linux.go b/mountinfo/mountinfo_linux.go index 6951cc25..36677819 100644 --- a/mountinfo/mountinfo_linux.go +++ b/mountinfo/mountinfo_linux.go @@ -75,9 +75,16 @@ func GetMountsFromReader(r io.Reader, filter FilterFunc) ([]*Info, error) { } } + major, minor, ok := strings.Cut(fields[2], ":") + if !ok { + return nil, fmt.Errorf("parsing '%s' failed: unexpected major:minor pair %s", text, fields[2]) + } + p := &Info{ ID: toInt(fields[0]), Parent: toInt(fields[1]), + Major: toInt(major), + Minor: toInt(minor), } p.Mountpoint, err = unescape(fields[4]) @@ -94,13 +101,6 @@ func GetMountsFromReader(r io.Reader, filter FilterFunc) ([]*Info, error) { } p.VFSOptions = fields[sepIdx+3] - mm := strings.SplitN(fields[2], ":", 3) - if len(mm) != 2 { - return nil, fmt.Errorf("parsing '%s' failed: unexpected major:minor pair %s", text, mm) - } - p.Major = toInt(mm[0]) - p.Minor = toInt(mm[1]) - p.Root, err = unescape(fields[3]) if err != nil { return nil, fmt.Errorf("parsing '%s' failed: root: %w", fields[3], err) From b145b7ca59612035286081de6cb1e6dc06595e7b Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Sun, 21 Jul 2024 13:55:52 +0200 Subject: [PATCH 5/5] mountinfo: GetMountsFromReader: inline some assignments Signed-off-by: Sebastiaan van Stijn --- mountinfo/mountinfo_linux.go | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/mountinfo/mountinfo_linux.go b/mountinfo/mountinfo_linux.go index 36677819..43ced2c1 100644 --- a/mountinfo/mountinfo_linux.go +++ b/mountinfo/mountinfo_linux.go @@ -81,10 +81,13 @@ func GetMountsFromReader(r io.Reader, filter FilterFunc) ([]*Info, error) { } p := &Info{ - ID: toInt(fields[0]), - Parent: toInt(fields[1]), - Major: toInt(major), - Minor: toInt(minor), + ID: toInt(fields[0]), + Parent: toInt(fields[1]), + Major: toInt(major), + Minor: toInt(minor), + Options: fields[5], + Optional: strings.Join(fields[6:sepIdx], " "), // zero or more optional fields + VFSOptions: fields[sepIdx+3], } p.Mountpoint, err = unescape(fields[4]) @@ -99,18 +102,12 @@ func GetMountsFromReader(r io.Reader, filter FilterFunc) ([]*Info, error) { if err != nil { return nil, fmt.Errorf("parsing '%s' failed: source: %w", fields[sepIdx+2], err) } - p.VFSOptions = fields[sepIdx+3] p.Root, err = unescape(fields[3]) if err != nil { return nil, fmt.Errorf("parsing '%s' failed: root: %w", fields[3], err) } - p.Options = fields[5] - - // zero or more optional fields - p.Optional = strings.Join(fields[6:sepIdx], " ") - // Run the filter after parsing all fields. var skip, stop bool if filter != nil {