layer: rm regexp use

Replace the regexp checking ID validity with a function. The benefits
are:

 - function is faster (up to 10x faster with less allocations);
 - no init overhead to compile the regexp;

Add a test case.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This commit is contained in:
Kir Kolyshkin
2024-07-16 12:30:17 -07:00
parent aae044039c
commit 1c0dc8a94f
2 changed files with 48 additions and 11 deletions

View File

@@ -7,7 +7,6 @@ import (
"io"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
@@ -18,14 +17,11 @@ import (
"github.com/pkg/errors"
)
var (
stringIDRegexp = regexp.MustCompile(`^[a-f0-9]{64}(-init)?$`)
supportedAlgorithms = []digest.Algorithm{
digest.SHA256,
// digest.SHA384, // Currently not used
// digest.SHA512, // Currently not used
}
)
var supportedAlgorithms = []digest.Algorithm{
digest.SHA256,
// digest.SHA384, // Currently not used
// digest.SHA512, // Currently not used
}
type fileMetadataStore struct {
root string
@@ -262,7 +258,7 @@ func (fms *fileMetadataStore) GetMountID(mount string) (string, error) {
}
content := strings.TrimSpace(string(contentBytes))
if !stringIDRegexp.MatchString(content) {
if !isValidID(content) {
return "", errors.New("invalid mount id value")
}
@@ -279,7 +275,7 @@ func (fms *fileMetadataStore) GetInitID(mount string) (string, error) {
}
content := strings.TrimSpace(string(contentBytes))
if !stringIDRegexp.MatchString(content) {
if !isValidID(content) {
return "", errors.New("invalid init id value")
}
@@ -431,3 +427,18 @@ func (fms *fileMetadataStore) Remove(layer ChainID, cache string) error {
func (fms *fileMetadataStore) RemoveMount(mount string) error {
return os.RemoveAll(fms.getMountDirectory(mount))
}
// isValidID checks if mount/init id is valid. It is similar to
// regexp.MustCompile(`^[a-f0-9]{64}(-init)?$`).MatchString(id).
func isValidID(id string) bool {
id = strings.TrimSuffix(id, "-init")
if len(id) != 64 {
return false
}
for _, c := range id {
if (c < '0' || c > '9') && (c < 'a' || c > 'f') {
return false
}
}
return true
}

View File

@@ -149,3 +149,29 @@ func TestGetOrphan(t *testing.T) {
t.Fatalf("Expected to have one orphan layer")
}
}
func TestIsValidID(t *testing.T) {
testCases := []struct {
name string
id string
expected bool
}{
{"Valid 64-char hexadecimal", "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", true},
{"Valid 64-char hexadecimal with -init suffix", "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef-init", true},
{"Invalid: too short", "1234567890abcdef", false},
{"Invalid: too long", "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef00", false},
{"Invalid: contains uppercase letter", "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdeF", false},
{"Invalid: contains non-hexadecimal character", "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdeg", false},
{"Invalid: empty string", "", false},
{"Invalid: only -init suffix", "-init", false},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := isValidID(tc.id)
if result != tc.expected {
t.Errorf("isValidID(%q): got %v, want %v", tc.id, result, tc.expected)
}
})
}
}