From 97817108ddf27fe590f804ce0390d1d2b4a84ce9 Mon Sep 17 00:00:00 2001 From: cxljs Date: Thu, 14 Aug 2025 20:48:45 +0800 Subject: [PATCH 1/6] Set the read/write buffer size of the sentinel client to 4KiB (#3476) Signed-off-by: Xiaolong Chen --- sentinel.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sentinel.go b/sentinel.go index 7963a069..008f23cf 100644 --- a/sentinel.go +++ b/sentinel.go @@ -201,8 +201,9 @@ func (opt *FailoverOptions) sentinelOptions(addr string) *Options { MinRetryBackoff: opt.MinRetryBackoff, MaxRetryBackoff: opt.MaxRetryBackoff, - ReadBufferSize: opt.ReadBufferSize, - WriteBufferSize: opt.WriteBufferSize, + // The sentinel client uses a 4KiB read/write buffer size. + ReadBufferSize: 4096, + WriteBufferSize: 4096, DialTimeout: opt.DialTimeout, ReadTimeout: opt.ReadTimeout, From d2ad801ba2a8902c230c9431bedee221946bbda9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Aug 2025 11:33:44 +0300 Subject: [PATCH 2/6] chore(deps): bump actions/checkout from 4 to 5 (#3484) Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build.yml | 4 ++-- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/doctests.yaml | 2 +- .github/workflows/golangci-lint.yml | 2 +- .github/workflows/spellcheck.yml | 2 +- .github/workflows/test-redis-enterprise.yml | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cb011248..ae2220dd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,7 +32,7 @@ jobs: go-version: ${{ matrix.go-version }} - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Test environment env: @@ -84,7 +84,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Run tests uses: ./.github/actions/run-tests diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 1a803d37..0a62809e 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -35,7 +35,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/doctests.yaml b/.github/workflows/doctests.yaml index 321654fa..ba072454 100644 --- a/.github/workflows/doctests.yaml +++ b/.github/workflows/doctests.yaml @@ -36,7 +36,7 @@ jobs: go-version: ${{ matrix.go-version }} - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Test doc examples working-directory: ./doctests diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index def3eb79..62552abf 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -20,7 +20,7 @@ jobs: name: lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: golangci-lint uses: golangci/golangci-lint-action@v8.0.0 with: diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml index 81e73cd4..9daecbc5 100644 --- a/.github/workflows/spellcheck.yml +++ b/.github/workflows/spellcheck.yml @@ -6,7 +6,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Check Spelling uses: rojopolis/spellcheck-github-actions@0.51.0 with: diff --git a/.github/workflows/test-redis-enterprise.yml b/.github/workflows/test-redis-enterprise.yml index 47de6478..a51c9e8c 100644 --- a/.github/workflows/test-redis-enterprise.yml +++ b/.github/workflows/test-redis-enterprise.yml @@ -20,10 +20,10 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Clone Redis EE docker repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: RedisLabs/redis-ee-docker path: redis-ee From 8336c444041b9c3852cf6c026feac6f4300fa1fa Mon Sep 17 00:00:00 2001 From: cxljs Date: Mon, 18 Aug 2025 20:46:31 +0800 Subject: [PATCH 3/6] chore(client): fix UniversalOptions miss ReadBufferSize and WriteBufferSize options (#3485) Signed-off-by: Xiaolong Chen --- universal.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/universal.go b/universal.go index 9b150d7d..763d50fa 100644 --- a/universal.go +++ b/universal.go @@ -61,6 +61,20 @@ type UniversalOptions struct { WriteTimeout time.Duration ContextTimeoutEnabled bool + // ReadBufferSize is the size of the bufio.Reader buffer for each connection. + // Larger buffers can improve performance for commands that return large responses. + // Smaller buffers can improve memory usage for larger pools. + // + // default: 256KiB (262144 bytes) + ReadBufferSize int + + // WriteBufferSize is the size of the bufio.Writer buffer for each connection. + // Larger buffers can improve performance for large pipelines and commands with many arguments. + // Smaller buffers can improve memory usage for larger pools. + // + // default: 256KiB (262144 bytes) + WriteBufferSize int + // PoolFIFO uses FIFO mode for each node connection pool GET/PUT (default LIFO). PoolFIFO bool @@ -143,6 +157,9 @@ func (o *UniversalOptions) Cluster() *ClusterOptions { WriteTimeout: o.WriteTimeout, ContextTimeoutEnabled: o.ContextTimeoutEnabled, + ReadBufferSize: o.ReadBufferSize, + WriteBufferSize: o.WriteBufferSize, + PoolFIFO: o.PoolFIFO, PoolSize: o.PoolSize, @@ -200,6 +217,9 @@ func (o *UniversalOptions) Failover() *FailoverOptions { WriteTimeout: o.WriteTimeout, ContextTimeoutEnabled: o.ContextTimeoutEnabled, + ReadBufferSize: o.ReadBufferSize, + WriteBufferSize: o.WriteBufferSize, + PoolFIFO: o.PoolFIFO, PoolSize: o.PoolSize, PoolTimeout: o.PoolTimeout, @@ -250,6 +270,9 @@ func (o *UniversalOptions) Simple() *Options { WriteTimeout: o.WriteTimeout, ContextTimeoutEnabled: o.ContextTimeoutEnabled, + ReadBufferSize: o.ReadBufferSize, + WriteBufferSize: o.WriteBufferSize, + PoolFIFO: o.PoolFIFO, PoolSize: o.PoolSize, PoolTimeout: o.PoolTimeout, From b8682d037bbba5cf8753d75d0b436d761e63a35e Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Mon, 18 Aug 2025 14:51:38 +0100 Subject: [PATCH 4/6] chore(ci): Bumps test image to 8.2.1-pre (#3478) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bumps test image to 8.2.1-pre Signed-off-by: Elena Kolevska * Missed the “benchmark” job Signed-off-by: Elena Kolevska --------- Signed-off-by: Elena Kolevska --- .github/actions/run-tests/action.yml | 2 +- .github/workflows/build.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/run-tests/action.yml b/.github/actions/run-tests/action.yml index a90d4605..b8e576e7 100644 --- a/.github/actions/run-tests/action.yml +++ b/.github/actions/run-tests/action.yml @@ -25,7 +25,7 @@ runs: # Mapping of redis version to redis testing containers declare -A redis_version_mapping=( - ["8.2.x"]="8.2" + ["8.2.x"]="8.2.1-pre" ["8.0.x"]="8.0.2" ["7.4.x"]="rs-7.4.0-v5" ["7.2.x"]="rs-7.2.0-v17" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ae2220dd..05f84ef6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,7 +44,7 @@ jobs: # Mapping of redis version to redis testing containers declare -A redis_version_mapping=( - ["8.2.x"]="8.2" + ["8.2.x"]="8.2.1-pre" ["8.0.x"]="8.0.2" ["7.4.x"]="rs-7.4.0-v5" ) From e07f55bed102aa1111739efc395592827e46b847 Mon Sep 17 00:00:00 2001 From: cxljs Date: Tue, 19 Aug 2025 01:04:55 +0800 Subject: [PATCH 5/6] chore(buffers): Set the default read/write buffer size of Redis connection to 32KiB (#3483) * update README.md Signed-off-by: Xiaolong Chen * typo: 0.5MiB -> 256KiB Signed-off-by: Xiaolong Chen * Set the default read/write buffer size of Redis connection to 32KiB Signed-off-by: Xiaolong Chen --------- Signed-off-by: Xiaolong Chen --- README.md | 4 ++-- internal/pool/buffer_size_test.go | 28 ++++++++++++++-------------- internal/pool/conn.go | 4 ++-- internal/proto/reader.go | 4 ++-- options.go | 4 ++-- osscluster.go | 4 ++-- ring.go | 4 ++-- sentinel.go | 4 ++-- universal.go | 4 ++-- 9 files changed, 30 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index f4e73da0..3c6bf743 100644 --- a/README.md +++ b/README.md @@ -301,7 +301,7 @@ func main() { ### Buffer Size Configuration -go-redis uses 0.5MiB read and write buffers by default for optimal performance. For high-throughput applications or large pipelines, you can customize buffer sizes: +go-redis uses 32KiB read and write buffers by default for optimal performance. For high-throughput applications or large pipelines, you can customize buffer sizes: ```go rdb := redis.NewClient(&redis.Options{ @@ -376,7 +376,7 @@ You can find further details in the [query dialect documentation](https://redis. #### Custom buffer sizes Prior to v9.12, the buffer size was the default go value of 4096 bytes. Starting from v9.12, -go-redis uses 256KiB read and write buffers by default for optimal performance. +go-redis uses 32KiB read and write buffers by default for optimal performance. For high-throughput applications or large pipelines, you can customize buffer sizes: ```go diff --git a/internal/pool/buffer_size_test.go b/internal/pool/buffer_size_test.go index f2e4b30c..7f4bd37e 100644 --- a/internal/pool/buffer_size_test.go +++ b/internal/pool/buffer_size_test.go @@ -34,12 +34,12 @@ var _ = Describe("Buffer Size Configuration", func() { Expect(err).NotTo(HaveOccurred()) defer connPool.CloseConn(cn) - // Check that default buffer sizes are used (256KiB) + // Check that default buffer sizes are used (32KiB) writerBufSize := getWriterBufSizeUnsafe(cn) readerBufSize := getReaderBufSizeUnsafe(cn) - Expect(writerBufSize).To(Equal(proto.DefaultBufferSize)) // Default 256KiB buffer size - Expect(readerBufSize).To(Equal(proto.DefaultBufferSize)) // Default 256KiB buffer size + Expect(writerBufSize).To(Equal(proto.DefaultBufferSize)) // Default 32KiB buffer size + Expect(readerBufSize).To(Equal(proto.DefaultBufferSize)) // Default 32KiB buffer size }) It("should use custom buffer sizes when specified", func() { @@ -79,16 +79,16 @@ var _ = Describe("Buffer Size Configuration", func() { Expect(err).NotTo(HaveOccurred()) defer connPool.CloseConn(cn) - // Check that default buffer sizes are used (256KiB) + // Check that default buffer sizes are used (32KiB) writerBufSize := getWriterBufSizeUnsafe(cn) readerBufSize := getReaderBufSizeUnsafe(cn) - Expect(writerBufSize).To(Equal(proto.DefaultBufferSize)) // Default 256KiB buffer size - Expect(readerBufSize).To(Equal(proto.DefaultBufferSize)) // Default 256KiB buffer size + Expect(writerBufSize).To(Equal(proto.DefaultBufferSize)) // Default 32KiB buffer size + Expect(readerBufSize).To(Equal(proto.DefaultBufferSize)) // Default 32KiB buffer size }) - It("should use 256KiB default buffer sizes for standalone NewConn", func() { - // Test that NewConn (without pool) also uses 256KiB buffers + It("should use 32KiB default buffer sizes for standalone NewConn", func() { + // Test that NewConn (without pool) also uses 32KiB buffers netConn := newDummyConn() cn := pool.NewConn(netConn) defer cn.Close() @@ -96,11 +96,11 @@ var _ = Describe("Buffer Size Configuration", func() { writerBufSize := getWriterBufSizeUnsafe(cn) readerBufSize := getReaderBufSizeUnsafe(cn) - Expect(writerBufSize).To(Equal(proto.DefaultBufferSize)) // Default 256KiB buffer size - Expect(readerBufSize).To(Equal(proto.DefaultBufferSize)) // Default 256KiB buffer size + Expect(writerBufSize).To(Equal(proto.DefaultBufferSize)) // Default 32KiB buffer size + Expect(readerBufSize).To(Equal(proto.DefaultBufferSize)) // Default 32KiB buffer size }) - It("should use 256KiB defaults even when pool is created directly without buffer sizes", func() { + It("should use 32KiB defaults even when pool is created directly without buffer sizes", func() { // Test the scenario where someone creates a pool directly (like in tests) // without setting ReadBufferSize and WriteBufferSize connPool = pool.NewConnPool(&pool.Options{ @@ -114,12 +114,12 @@ var _ = Describe("Buffer Size Configuration", func() { Expect(err).NotTo(HaveOccurred()) defer connPool.CloseConn(cn) - // Should still get 256KiB defaults because NewConnPool sets them + // Should still get 32KiB defaults because NewConnPool sets them writerBufSize := getWriterBufSizeUnsafe(cn) readerBufSize := getReaderBufSizeUnsafe(cn) - Expect(writerBufSize).To(Equal(proto.DefaultBufferSize)) // Default 256KiB buffer size - Expect(readerBufSize).To(Equal(proto.DefaultBufferSize)) // Default 256KiB buffer size + Expect(writerBufSize).To(Equal(proto.DefaultBufferSize)) // Default 32KiB buffer size + Expect(readerBufSize).To(Equal(proto.DefaultBufferSize)) // Default 32KiB buffer size }) }) diff --git a/internal/pool/conn.go b/internal/pool/conn.go index 989ab10d..6b02ddb0 100644 --- a/internal/pool/conn.go +++ b/internal/pool/conn.go @@ -37,11 +37,11 @@ func NewConnWithBufferSize(netConn net.Conn, readBufSize, writeBufSize int) *Con createdAt: time.Now(), } - // Use specified buffer sizes, or fall back to 0.5MiB defaults if 0 + // Use specified buffer sizes, or fall back to 32KiB defaults if 0 if readBufSize > 0 { cn.rd = proto.NewReaderSize(netConn, readBufSize) } else { - cn.rd = proto.NewReader(netConn) // Uses 0.5MiB default + cn.rd = proto.NewReader(netConn) // Uses 32KiB default } if writeBufSize > 0 { diff --git a/internal/proto/reader.go b/internal/proto/reader.go index 13ff2547..654f2cab 100644 --- a/internal/proto/reader.go +++ b/internal/proto/reader.go @@ -12,8 +12,8 @@ import ( "github.com/redis/go-redis/v9/internal/util" ) -// DefaultBufferSize is the default size for read/write buffers (256 KiB). -const DefaultBufferSize = 256 * 1024 +// DefaultBufferSize is the default size for read/write buffers (32 KiB). +const DefaultBufferSize = 32 * 1024 // redis resp protocol data type. const ( diff --git a/options.go b/options.go index 9b09b7d7..799cb53a 100644 --- a/options.go +++ b/options.go @@ -135,14 +135,14 @@ type Options struct { // Larger buffers can improve performance for commands that return large responses. // Smaller buffers can improve memory usage for larger pools. // - // default: 256KiB (262144 bytes) + // default: 32KiB (32768 bytes) ReadBufferSize int // WriteBufferSize is the size of the bufio.Writer buffer for each connection. // Larger buffers can improve performance for large pipelines and commands with many arguments. // Smaller buffers can improve memory usage for larger pools. // - // default: 256KiB (262144 bytes) + // default: 32KiB (32768 bytes) WriteBufferSize int // PoolFIFO type of connection pool. diff --git a/osscluster.go b/osscluster.go index 8d839a0a..7ea80cb2 100644 --- a/osscluster.go +++ b/osscluster.go @@ -96,14 +96,14 @@ type ClusterOptions struct { // Larger buffers can improve performance for commands that return large responses. // Smaller buffers can improve memory usage for larger pools. // - // default: 256KiB (262144 bytes) + // default: 32KiB (32768 bytes) ReadBufferSize int // WriteBufferSize is the size of the bufio.Writer buffer for each connection. // Larger buffers can improve performance for large pipelines and commands with many arguments. // Smaller buffers can improve memory usage for larger pools. // - // default: 256KiB (262144 bytes) + // default: 32KiB (32768 bytes) WriteBufferSize int TLSConfig *tls.Config diff --git a/ring.go b/ring.go index 6c740310..3381460a 100644 --- a/ring.go +++ b/ring.go @@ -128,14 +128,14 @@ type RingOptions struct { // Larger buffers can improve performance for commands that return large responses. // Smaller buffers can improve memory usage for larger pools. // - // default: 256KiB (262144 bytes) + // default: 32KiB (32768 bytes) ReadBufferSize int // WriteBufferSize is the size of the bufio.Writer buffer for each connection. // Larger buffers can improve performance for large pipelines and commands with many arguments. // Smaller buffers can improve memory usage for larger pools. // - // default: 256KiB (262144 bytes) + // default: 32KiB (32768 bytes) WriteBufferSize int TLSConfig *tls.Config diff --git a/sentinel.go b/sentinel.go index 008f23cf..819ec192 100644 --- a/sentinel.go +++ b/sentinel.go @@ -94,14 +94,14 @@ type FailoverOptions struct { // Larger buffers can improve performance for commands that return large responses. // Smaller buffers can improve memory usage for larger pools. // - // default: 256KiB (262144 bytes) + // default: 32KiB (32768 bytes) ReadBufferSize int // WriteBufferSize is the size of the bufio.Writer buffer for each connection. // Larger buffers can improve performance for large pipelines and commands with many arguments. // Smaller buffers can improve memory usage for larger pools. // - // default: 256KiB (262144 bytes) + // default: 32KiB (32768 bytes) WriteBufferSize int PoolFIFO bool diff --git a/universal.go b/universal.go index 763d50fa..02da3be8 100644 --- a/universal.go +++ b/universal.go @@ -65,14 +65,14 @@ type UniversalOptions struct { // Larger buffers can improve performance for commands that return large responses. // Smaller buffers can improve memory usage for larger pools. // - // default: 256KiB (262144 bytes) + // default: 32KiB (32768 bytes) ReadBufferSize int // WriteBufferSize is the size of the bufio.Writer buffer for each connection. // Larger buffers can improve performance for large pipelines and commands with many arguments. // Smaller buffers can improve memory usage for larger pools. // - // default: 256KiB (262144 bytes) + // default: 32KiB (32768 bytes) WriteBufferSize int // PoolFIFO uses FIFO mode for each node connection pool GET/PUT (default LIFO). From ff4d63e06b2063680aaae5c0850c7f2f688e649b Mon Sep 17 00:00:00 2001 From: cybersmeashish Date: Mon, 18 Aug 2025 22:35:47 +0530 Subject: [PATCH 6/6] chore(test): Add comprehensive edge case tests for IncrByFloat command (#3477) This commit adds extensive test coverage for the IncrByFloat Redis command, covering various edge cases and scenarios that were not previously tested. Test cases added: - Negative increment values - Zero increment (should return current value) - High precision floating point operations - Non-existent key behavior (should start from 0) - Integer values stored as strings - Scientific notation (both positive and negative) - Error handling for non-numeric values - Very large numbers (near float64 limits) - Very small numbers (near zero precision) These tests ensure robust behavior of the IncrByFloat command across different numeric formats and edge conditions, improving the overall reliability and test coverage of the go-redis library. The tests use Gomega's BeNumerically matcher for floating point comparisons to handle precision issues appropriately. --- commands_test.go | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/commands_test.go b/commands_test.go index 9e130089..c110d582 100644 --- a/commands_test.go +++ b/commands_test.go @@ -2412,6 +2412,77 @@ var _ = Describe("Commands", func() { Expect(args).To(Equal(expectedArgs)) }) + + It("should IncrByFloat with edge cases", func() { + // Test with negative increment + set := client.Set(ctx, "key", "10.5", 0) + Expect(set.Err()).NotTo(HaveOccurred()) + + incrByFloat := client.IncrByFloat(ctx, "key", -2.3) + Expect(incrByFloat.Err()).NotTo(HaveOccurred()) + Expect(incrByFloat.Val()).To(BeNumerically("~", 8.2, 0.0001)) + + // Test with zero increment (should return current value) + incrByFloat = client.IncrByFloat(ctx, "key", 0.0) + Expect(incrByFloat.Err()).NotTo(HaveOccurred()) + Expect(incrByFloat.Val()).To(BeNumerically("~", 8.2, 0.0001)) + + // Test with very small increment (precision test) + incrByFloat = client.IncrByFloat(ctx, "key", 0.0001) + Expect(incrByFloat.Err()).NotTo(HaveOccurred()) + Expect(incrByFloat.Val()).To(BeNumerically("~", 8.2001, 0.00001)) + + // Test with non-existent key (should start from 0) + incrByFloat = client.IncrByFloat(ctx, "nonexistent", 5.5) + Expect(incrByFloat.Err()).NotTo(HaveOccurred()) + Expect(incrByFloat.Val()).To(Equal(5.5)) + + // Test with integer value stored as string + set = client.Set(ctx, "intkey", "42", 0) + Expect(set.Err()).NotTo(HaveOccurred()) + + incrByFloat = client.IncrByFloat(ctx, "intkey", 0.5) + Expect(incrByFloat.Err()).NotTo(HaveOccurred()) + Expect(incrByFloat.Val()).To(Equal(42.5)) + + // Test with scientific notation + set = client.Set(ctx, "scikey", "1.5e2", 0) + Expect(set.Err()).NotTo(HaveOccurred()) + + incrByFloat = client.IncrByFloat(ctx, "scikey", 5.0) + Expect(incrByFloat.Err()).NotTo(HaveOccurred()) + Expect(incrByFloat.Val()).To(Equal(155.0)) + + // Test with negative scientific notation + incrByFloat = client.IncrByFloat(ctx, "scikey", -1.5e1) + Expect(incrByFloat.Err()).NotTo(HaveOccurred()) + Expect(incrByFloat.Val()).To(Equal(140.0)) + + // Test error case: non-numeric value + set = client.Set(ctx, "stringkey", "notanumber", 0) + Expect(set.Err()).NotTo(HaveOccurred()) + + incrByFloat = client.IncrByFloat(ctx, "stringkey", 1.0) + Expect(incrByFloat.Err()).To(HaveOccurred()) + Expect(incrByFloat.Err().Error()).To(ContainSubstring("value is not a valid float")) + + // Test with very large numbers + set = client.Set(ctx, "largekey", "1.7976931348623157e+308", 0) + Expect(set.Err()).NotTo(HaveOccurred()) + + // This should work as it's within float64 range + incrByFloat = client.IncrByFloat(ctx, "largekey", -1.0e+308) + Expect(incrByFloat.Err()).NotTo(HaveOccurred()) + Expect(incrByFloat.Val()).To(BeNumerically("~", 7.976931348623157e+307, 1e+300)) + + // Test with very small numbers (near zero) + set = client.Set(ctx, "smallkey", "1e-10", 0) + Expect(set.Err()).NotTo(HaveOccurred()) + + incrByFloat = client.IncrByFloat(ctx, "smallkey", 1e-10) + Expect(incrByFloat.Err()).NotTo(HaveOccurred()) + Expect(incrByFloat.Val()).To(BeNumerically("~", 2e-10, 1e-15)) + }) }) Describe("hashes", func() {