diff --git a/go.mod b/go.mod index 42434e8..49ee417 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/QuangTung97/memproxy go 1.19 require ( - github.com/QuangTung97/go-memcache v1.1.1-0.20231006091455-8893a554bbc3 + github.com/QuangTung97/go-memcache v1.1.1-0.20231009064511-4f8302dc7878 github.com/google/btree v1.1.2 github.com/matryer/moq v0.3.0 github.com/mgechev/revive v1.3.1 diff --git a/go.sum b/go.sum index 8483ad8..8010f59 100644 --- a/go.sum +++ b/go.sum @@ -5,8 +5,8 @@ github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20190129172621-c8b1d7a94ddf/go.mod h1:aJ4qN3TfrelA6NZ6AXsXRfmEVaYin3EDbSPJrKS8OXo= -github.com/QuangTung97/go-memcache v1.1.1-0.20231006091455-8893a554bbc3 h1:M0rmGGjKFqZhagsIAbxr750H3M4QeLgLnt9K3U0+Rhg= -github.com/QuangTung97/go-memcache v1.1.1-0.20231006091455-8893a554bbc3/go.mod h1:bInH+oopFx83sRE0DaLVuXc6t3c6DsapM3Y7B7IUpOg= +github.com/QuangTung97/go-memcache v1.1.1-0.20231009064511-4f8302dc7878 h1:lsuqm/3HYytjRogPD7+rHPnWM5DfFlHM7XRxW23aRNg= +github.com/QuangTung97/go-memcache v1.1.1-0.20231009064511-4f8302dc7878/go.mod h1:bInH+oopFx83sRE0DaLVuXc6t3c6DsapM3Y7B7IUpOg= github.com/aclements/go-gg v0.0.0-20170118225347-6dbb4e4fefb0/go.mod h1:55qNq4vcpkIuHowELi5C8e+1yUHtoLoOUR9QU5j7Tes= github.com/aclements/go-moremath v0.0.0-20210112150236-f10218a38794 h1:xlwdaKcTNVW4PtpQb8aKA4Pjy0CdJHEqvFbAnvR5m2g= github.com/aclements/go-moremath v0.0.0-20210112150236-f10218a38794/go.mod h1:7e+I0LQFUI9AXWxOfsQROs9xPhoJtbsyWcjJqDd4KPY= diff --git a/item/item.go b/item/item.go index 27188f6..6b2a869 100644 --- a/item/item.go +++ b/item/item.go @@ -6,6 +6,8 @@ import ( "log" "time" + "github.com/QuangTung97/go-memcache/memcache" + "github.com/QuangTung97/memproxy" ) @@ -307,6 +309,9 @@ func (s *getState[T, K]) nextFunc() { s.it.stats.TotalBytesRecv += uint64(len(leaseGetResp.Data)) resp, err := s.it.unmarshaler(leaseGetResp.Data) + + memcache.ReleaseGetResponseData(leaseGetResp.Data) + if err != nil { s.setResponseError(err) return diff --git a/mmap/bucket.go b/mmap/bucket.go index 922a917..9963f67 100644 --- a/mmap/bucket.go +++ b/mmap/bucket.go @@ -7,7 +7,6 @@ import ( "errors" "math" "strconv" - "strings" "github.com/QuangTung97/memproxy/item" ) @@ -24,16 +23,20 @@ type BucketKey[R RootKey] struct { func (k BucketKey[R]) String() string { rootKey := k.RootKey.String() - var buf strings.Builder + // 2 bytes for size log + // 8 bytes for hash value => can contain 4 byte uint32 + // 2 bytes for separator + // 116 bytes for key length + var tmpBuf [128]byte + result := tmpBuf[:0] - // 2 byte for size log - // 8 byte for hash value => can contain 4 byte uint32 - buf.Grow(len(rootKey) + 2*len(k.Sep) + 10) + result = append(result, rootKey...) + result = append(result, k.Sep...) - _, _ = buf.WriteString(rootKey) - _, _ = buf.WriteString(k.Sep) - _, _ = buf.WriteString(strconv.FormatInt(int64(k.SizeLog), 10)) - _, _ = buf.WriteString(k.Sep) + sizeLogNum := strconv.FormatInt(int64(k.SizeLog), 10) + result = append(result, sizeLogNum...) + + result = append(result, k.Sep...) hash := k.Hash & (math.MaxUint64 << (64 - k.SizeLog)) @@ -48,9 +51,8 @@ func (k BucketKey[R]) String() string { hexStr = hexStr[:len(hexStr)-1] } - _, _ = buf.WriteString(hexStr) - - return buf.String() + result = append(result, hexStr...) + return string(result) } // GetHashRange ... diff --git a/mmap/mmap_bench_test.go b/mmap/mmap_bench_test.go index dd87de4..c5b832a 100644 --- a/mmap/mmap_bench_test.go +++ b/mmap/mmap_bench_test.go @@ -3,6 +3,8 @@ package mmap import ( "context" "encoding/binary" + "os" + "runtime/pprof" "strconv" "testing" @@ -108,6 +110,23 @@ func Benchmark_Proxy__Map_Get_Batch_1000(b *testing.B) { } } +func Benchmark_ComputeBucketKeyString(b *testing.B) { + var sum int + for n := 0; n < b.N; n++ { + k := BucketKey[benchRootKey]{ + RootKey: benchRootKey{ + value: 23, + }, + SizeLog: 7, + Hash: newHash(0x1234, 2), + Sep: ":", + }.String() + sum += len(k) + } + b.StopTimer() + writeMemProfile() +} + func (v benchValue) getKey() benchKey { return v.key } @@ -167,3 +186,25 @@ func TestMarshalBenchValue(t *testing.T) { assert.Equal(t, nil, err) assert.Equal(t, b, newVal) } + +func writeMemProfile() { + if os.Getenv("ENABLE_BENCH_PROFILE") == "" { + return + } + + file, err := os.Create("./bench_profile.out") + if err != nil { + panic(err) + } + defer func() { + err := file.Close() + if err != nil { + panic(err) + } + }() + + err = pprof.WriteHeapProfile(file) + if err != nil { + panic(err) + } +} diff --git a/plain_memcache.go b/plain_memcache.go index ba9bd5b..1efb174 100644 --- a/plain_memcache.go +++ b/plain_memcache.go @@ -2,6 +2,7 @@ package memproxy import ( "context" + "github.com/QuangTung97/go-memcache/memcache" ) @@ -90,12 +91,20 @@ func (p *plainPipelineImpl) LowerSession() Session { // LeaseGet ... func (p *plainPipelineImpl) LeaseGet(key string, _ LeaseGetOptions) func() (LeaseGetResponse, error) { - fn := p.pipeline.MGet(key, memcache.MGetOptions{ + result, getErr := p.pipeline.MGetFast(key, memcache.MGetOptions{ N: p.leaseDuration, CAS: true, }) + if getErr != nil { + return func() (LeaseGetResponse, error) { + return LeaseGetResponse{}, getErr + } + } + return func() (LeaseGetResponse, error) { - mgetResp, err := fn() + mgetResp, err := result.Result() + memcache.ReleaseMGetResult(result) + if err != nil { return LeaseGetResponse{}, err }