From 5364b3d8f56969288122422156451409e8cb4ce2 Mon Sep 17 00:00:00 2001 From: Jianfei Wang Date: Sat, 9 Apr 2016 11:33:06 +0800 Subject: [PATCH 1/2] storage: add test for ParseKeyHash --- go/storage/needle.go | 2 +- go/storage/needle_test.go | 45 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 go/storage/needle_test.go diff --git a/go/storage/needle.go b/go/storage/needle.go index e49368820..d6345adb1 100644 --- a/go/storage/needle.go +++ b/go/storage/needle.go @@ -218,7 +218,7 @@ func ParseKeyHash(key_hash_string string) (uint64, uint32, error) { } key_hash_bytes, khe := hex.DecodeString(key_hash_string) key_hash_len := len(key_hash_bytes) - if khe != nil || key_hash_len <= 4 { + if khe != nil || key_hash_len <= 4 || key_hash_len > 12 { glog.V(0).Infoln("Invalid key_hash", key_hash_string, "length:", key_hash_len, "error", khe) return 0, 0, errors.New("Invalid key and hash:" + key_hash_string) } diff --git a/go/storage/needle_test.go b/go/storage/needle_test.go new file mode 100644 index 000000000..c05afda2f --- /dev/null +++ b/go/storage/needle_test.go @@ -0,0 +1,45 @@ +package storage + +import "testing" + +func TestParseKeyHash(t *testing.T) { + testcases := []struct { + KeyHash string + ID uint64 + Cookie uint32 + Err bool + }{ + // normal + {"4ed4c8116e41", 0x4ed4, 0xc8116e41, false}, + // cookie with leading zeros + {"4ed401116e41", 0x4ed4, 0x01116e41, false}, + // odd length + {"ed400116e41", 0xed4, 0x00116e41, false}, + // uint + {"fed4c8114ed4c811f0116e41", 0xfed4c8114ed4c811, 0xf0116e41, false}, + // err: too short + {"4ed4c811", 0, 0, true}, + // err: too long + {"4ed4c8114ed4c8114ed4c8111", 0, 0, true}, + // err: invalid character + {"helloworld", 0, 0, true}, + } + + for _, tc := range testcases { + if id, cookie, err := ParseKeyHash(tc.KeyHash); err != nil && !tc.Err { + t.Fatalf("Parse %s error: %v", tc.KeyHash, err) + } else if err == nil && tc.Err { + t.Fatalf("Parse %s expected error got nil", tc.KeyHash) + } else if id != tc.ID || cookie != tc.Cookie { + t.Fatalf("Parse %s wrong result. Expected: (%d, %d) got: (%d, %d)", tc.KeyHash, tc.ID, tc.Cookie, id, cookie) + } + } +} + +func BenchmarkParseKeyHash(b *testing.B) { + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + ParseKeyHash("4ed44ed44ed44ed4c8116e41") + } +} From eec72b51362773cc5ef7f585bd1d8ccf4061ac7a Mon Sep 17 00:00:00 2001 From: Jianfei Wang Date: Sun, 10 Apr 2016 15:54:40 +0800 Subject: [PATCH 2/2] storage: faster ParseKeyHash --- go/storage/needle.go | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/go/storage/needle.go b/go/storage/needle.go index d6345adb1..66cf5b22a 100644 --- a/go/storage/needle.go +++ b/go/storage/needle.go @@ -1,7 +1,6 @@ package storage import ( - "encoding/hex" "errors" "fmt" "io/ioutil" @@ -15,7 +14,6 @@ import ( "github.com/chrislusf/seaweedfs/go/glog" "github.com/chrislusf/seaweedfs/go/images" "github.com/chrislusf/seaweedfs/go/operation" - "github.com/chrislusf/seaweedfs/go/util" ) const ( @@ -213,16 +211,25 @@ func (n *Needle) ParsePath(fid string) (err error) { } func ParseKeyHash(key_hash_string string) (uint64, uint32, error) { - if len(key_hash_string)%2 == 1 { - key_hash_string = "0" + key_hash_string - } - key_hash_bytes, khe := hex.DecodeString(key_hash_string) - key_hash_len := len(key_hash_bytes) - if khe != nil || key_hash_len <= 4 || key_hash_len > 12 { - glog.V(0).Infoln("Invalid key_hash", key_hash_string, "length:", key_hash_len, "error", khe) + key, hash, ok := parseKeyHash(key_hash_string) + if !ok { return 0, 0, errors.New("Invalid key and hash:" + key_hash_string) } - key := util.BytesToUint64(key_hash_bytes[0 : key_hash_len-4]) - hash := util.BytesToUint32(key_hash_bytes[key_hash_len-4 : key_hash_len]) return key, hash, nil } + +func parseKeyHash(keyhash string) (uint64, uint32, bool) { + if len(keyhash) <= 8 || len(keyhash) > 24 { + return 0, 0, false + } + split := len(keyhash) - 8 + key, err := strconv.ParseUint(keyhash[:split], 16, 64) + if err != nil { + return 0, 0, false + } + hash, err := strconv.ParseUint(keyhash[split:], 16, 32) + if err != nil { + return 0, 0, false + } + return key, uint32(hash), true +}