From 8f7b9133f0ccf963c12aa86ff5225bc2ba6f2e0c Mon Sep 17 00:00:00 2001 From: Steve McDaniel Date: Mon, 8 May 2023 11:05:17 -0600 Subject: [PATCH 1/4] Add LRU cache for JSONPointerToSlice and DotPathToSlice. Signed-off-by: Steve McDaniel --- gabs.go | 28 ++++++++++++++++++++++++++++ go.mod | 4 +++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/gabs.go b/gabs.go index b846954..5e0ce14 100644 --- a/gabs.go +++ b/gabs.go @@ -31,6 +31,8 @@ import ( "os" "strconv" "strings" + + lru "github.com/hashicorp/golang-lru/v2" ) //------------------------------------------------------------------------------ @@ -79,11 +81,17 @@ var ( var ( r1 *strings.Replacer r2 *strings.Replacer + // Cache for DotPathToSlice + dotPathCache *lru.Cache[string, []string] + // Cache for JSONPointerToSlice + jsonPointerCache *lru.Cache[string, []string] ) func init() { r1 = strings.NewReplacer("~1", "/", "~0", "~") r2 = strings.NewReplacer("~1", ".", "~0", "~") + dotPathCache, _ = lru.New[string, []string](1024) + jsonPointerCache, _ = lru.New[string, []string](1024) } //------------------------------------------------------------------------------ @@ -105,10 +113,20 @@ func JSONPointerToSlice(path string) ([]string, error) { if path == "/" { return []string{""}, nil } + + item, ok := jsonPointerCache.Get(path) + + if ok { + return item, nil + } + hierarchy := strings.Split(path, "/")[1:] for i, v := range hierarchy { hierarchy[i] = r1.Replace(v) } + + jsonPointerCache.Add(path, hierarchy) + return hierarchy, nil } @@ -118,10 +136,20 @@ func JSONPointerToSlice(path string) ([]string, error) { // if it appears in the reference key. Likewise, '~' (%x7E) must be encoded // as '~0' since it is the escape character for encoding '.'. func DotPathToSlice(path string) []string { + item, ok := dotPathCache.Get(path) + + if ok { + return item + } + hierarchy := strings.Split(path, ".") + for i, v := range hierarchy { hierarchy[i] = r2.Replace(v) } + + dotPathCache.Add(path, hierarchy) + return hierarchy } diff --git a/go.mod b/go.mod index bd75790..a791483 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module github.com/Jeffail/gabs/v2 -go 1.16 +go 1.18 + +require github.com/hashicorp/golang-lru/v2 v2.0.2 From 43bcb71cf1b398789f9d2a09deedeec797c9fb99 Mon Sep 17 00:00:00 2001 From: Steve McDaniel Date: Mon, 8 May 2023 11:11:58 -0600 Subject: [PATCH 2/4] Add go.sum --- go.sum | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 go.sum diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..8f2fb76 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/hashicorp/golang-lru/v2 v2.0.2 h1:Dwmkdr5Nc/oBiXgJS3CDHNhJtIHkuZ3DZF5twqnfBdU= +github.com/hashicorp/golang-lru/v2 v2.0.2/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= From 11cd7d9142f2a796e979aff7b43f7ba4381f8d8a Mon Sep 17 00:00:00 2001 From: Steve McDaniel Date: Mon, 8 May 2023 11:13:59 -0600 Subject: [PATCH 3/4] bump to go 1.18.x --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f1f4207..3ba89bd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,7 +11,7 @@ jobs: - name: Install Go uses: actions/setup-go@v3 with: - go-version: 1.16.x + go-version: 1.18.x - name: Checkout code uses: actions/checkout@v3 From 856d3c632fe5a35989d6ed699306152e6c961f07 Mon Sep 17 00:00:00 2001 From: Steve McDaniel Date: Sun, 18 Feb 2024 20:17:19 -0700 Subject: [PATCH 4/4] add benchmark for JSONPointerToSlice cache --- gabs_test.go | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/gabs_test.go b/gabs_test.go index f8429e5..29506d2 100644 --- a/gabs_test.go +++ b/gabs_test.go @@ -1950,3 +1950,37 @@ func BenchmarkWildcardSearch(b *testing.B) { val.Search([]string{"test", "*", "value"}...) } } + +func BenchmarkJsonPointerToSlice(b *testing.B) { + samples := []string{ + "/test/field", + "/field/test", + "/user/name", + "/user/email/address", + "/host/ip/addres", + "/host/os/family", + "/host/os/version", + "/test/field", + "/field/test", + "/user/name", + "/user/email/address", + "/host/ip/addres", + "/host/os/family", + "/host/os/version", + "/test/field", + "/field/test", + "/user/name", + "/user/email/address", + "/host/ip/addres", + "/host/os/family", + "/host/os/version", + } + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + for _, s := range samples { + JSONPointerToSlice(s) + } + } +}