-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Comparing changes
Open a pull request
base repository: redis/go-redis
base: v9.20.0
head repository: redis/go-redis
compare: v9.21.0
- 13 commits
- 56 files changed
- 10 contributors
Commits on May 29, 2026
-
fix(pubsub): prevent double reconnect in releaseConn (#3833)
When a connection is both not usable and has a bad conn error, releaseConn would call reconnect twice — first establishing a new connection, then immediately closing it to create another. Add early return after the first reconnect to avoid the wasted connection.
Configuration menu - View commit details
-
Copy full SHA for 65d6abd - Browse repository at this point
Copy the full SHA 65d6abdView commit details
Commits on Jun 4, 2026
-
fix(command): ignore unknown fields in CLUSTER SHARDS response (#3843)
The CLUSTER SHARDS 'nodes' field contains a list of all nodes within the shard. Each individual node is a map of attributes that describe the node. Some attributes are optional and more attributes may be added in the future. Previously, the parser returned an error on any unrecognized field, causing breakage whenever the server introduces new attributes. Now unknown fields at both the shard level and node level are silently discarded, matching the forward-compatible behavior already used elsewhere in this codebase. Signed-off-by: Madelyn Olson <[email protected]>
Configuration menu - View commit details
-
Copy full SHA for 974e717 - Browse repository at this point
Copy the full SHA 974e717View commit details
Commits on Jun 8, 2026
-
chore(deps): bump codecov/codecov-action from 6 to 7 (#3845)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 6 to 7. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](codecov/codecov-action@v6...v7) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Configuration menu - View commit details
-
Copy full SHA for a4b234f - Browse repository at this point
Copy the full SHA a4b234fView commit details
Commits on Jun 11, 2026
-
fix(ft.hybrid): Always generate vector param names if they are not pr…
…ovided by the user (#3844) * feat(search): always pass FT.HYBRID vector data via PARAMS Redis no longer supports inline vector blobs in FT.HYBRID. Always pass vector data through the PARAMS mechanism, generating a unique parameter name when VectorParamName is not provided. Update the related comments and drop the now-obsolete 8.6+ skip guards in the integration tests. * chore(search): add tests for generating vector param names * doc the limitations * use local params * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <[email protected]> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <[email protected]> * fix build --------- Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Configuration menu - View commit details
-
Copy full SHA for e1a2d68 - Browse repository at this point
Copy the full SHA e1a2d68View commit details -
fix(push): fix peeking when push name is truncated (#3842)
* fix(push): Fix peeking when push name is truncated * fix(push): fix peeking malformated push * protect agains potential panic
Configuration menu - View commit details
-
Copy full SHA for 10dc44f - Browse repository at this point
Copy the full SHA 10dc44fView commit details -
chore(release): 9.20.1 (#3847)
* bump version to 9.20.1 * Add release notes
Configuration menu - View commit details
-
Copy full SHA for a13416b - Browse repository at this point
Copy the full SHA a13416bView commit details -
feat(command): add zero-copy GetToBuffer and SetFromBuffer (#3834)
* feat(command): add zero-copy GetToBuffer and SetFromBuffer Adds two new methods on the StringCmdable interface that let callers read and write Redis string values directly into/from pre-allocated byte buffers, eliminating the per-call payload allocation that the regular Get/Set methods incur. Public API: GetToBuffer(ctx, key, buf) *ZeroCopyStringCmd SetFromBuffer(ctx, key, buf) *StatusCmd ZeroCopyStringCmd { Val() int; Bytes() []byte; Result() (int, error) } Available on *Client, *ClusterClient, *Ring, *Conn and Pipeliner via * fix(proto): avoid stale line[0] after bufio refill in ReadStringInto ReadLine() returns a slice into bufio.Reader's internal buffer (the ReadSlice fast path). The follow-up io.ReadFull / Discard calls on r.rd can trigger bufio.fill(), which copies new source bytes over the slot line[0] used to point at. The post-read if line[0] == RespVerbatim { ... } check on line 520 of reader.go could therefore observe a refilled byte rather than the original response type. When that refilled byte happened to be '=' (0x3D, RespVerbatim) — for example the head of a bulk-string payload whose tail forced the refill — a regular `$<n>...` Fix: capture line[0] into a local `isVerbatim` boolean before any further read on r.rd, and use that local for both the pre-read length check and the post-read prefix-stripping branch. Regression test (internal/proto/reader_test.go): a payload sized to exactly DefaultBufferSize, all '=' bytes. After ReadLine consumes the header, bufio holds (bufsize - headerLen) payload bytes; the final headerLen bytes io.ReadFull asks for force bufio.fill(), which places payload-tail + trailing \r\n at position 0 of bufio.buf — i.e. '=' at the slot line[0] points at. Against the buggy code the test fails with n=32764 wanted 32768; with the fix all 10 ReadStringInto tests pass. * chore(ci): bump bench test timeout to 11m * chore(bench): cap CI bench wrappers at 64 KiB; cover 10 MiB via test * fix(bench): keep proto Reader benches O(1) in b.N via loopFrameReader * fix(proto): drain payload on buffer-too-small; drop verbatim handling Three related cleanups to ReadStringInto and the cmd it backs: 1. Buffer-too-small now drains the unread payload + trailing CRLF before returning the error, so the underlying connection stays aligned for the next reply. Without this drain, a too-small caller buffer left the bulk payload sitting in the bufio stream — the connection would then be returned to the pool in a corrupted state, and the next user of that connection would parse the leftover bytes as a malformed response. The existing test only checked the first call's error and missed this; it now feeds two consecutive bulk-string replies and asserts the second parses cleanly. Verified failure-mode by reverting just the drain: the follow-up read fails with `can't parse reply="hello" reading string into buffer`. 2. Drop RespVerbatim handling from ReadStringInto. The only public caller is GetToBuffer, which issues GET, and GET never returns a verbatim string — RESP3 verbatim replies come from server-info commands like CLIENT INFO / DEBUG OBJECT / LOLWUT. Keeping the branch re-introduces a hazard class where the response-type byte read from a stale line[0] after a bufio refill can be misinterpreted as the verbatim format tag (the bug fixed in "fix(proto): avoid stale line[0] after bufio refill in ReadStringInto"). Removing the branch eliminates the class structurally and drops an O(n) memmove on the verbatim path (`copy(buf, buf[4:n])`). The unit test that previously asserted verbatim parsing is reshaped to assert verbatim now surfaces as an error, and the BulkStringStartingWithEqRefill regression test is kept (and its comment updated) as a guard against re-introducing verbatim support without re-introducing the bug. 3. Add a godoc paragraph to ZeroCopyStringCmd.Clone explaining the deep-copy semantics (clone gets a freshly allocated buffer, not a slice of the caller's memory) and noting that Clone is unreachable through normal client flows: it is only called from cluster fan-out routing in osscluster_router.go for multi-shard commands like DBSIZE / KEYS / FLUSHDB, and ZeroCopyStringCmd is only produced by GetToBuffer which issues GET — a single-key command never fanned out. Combined with NoRetry()=true blocking the retry path, Clone exists only to satisfy the Cmder interface and to keep the cmd usable if a future caller does fan out. * fix(zerocopy): clone fails explicitly; reset cmd.n; update doc Three small follow-ups to ZeroCopyStringCmd identified during a full review of the zero-copy buffer code path: 1. Clone() now returns a marked clone whose readReply drains the network reply and surfaces an explicit error rather than producing silently-wrong results. Cloning a ZeroCopyStringCmd has no well-defined semantics: the cmd writes into caller-owned memory (the buf passed to GetToBuffer), and a clone can neither share that buf (sibling clones would race, last-writer wins) nor allocate its own buf (the result would be invisible to whoever asked for the original cmd's reply). The previous implementation chose the second path and lost the result; this commit chooses to fail loudly. The Cmder interface requires Clone, so we still return a clone. The clone is flagged via a new private field, and readReply checks that flag, calls rd.DiscardNext() to keep the connection aligned, and returns a clear error ("redis: ZeroCopyStringCmd cannot be cloned (cmd writes into caller-owned memory)"). Pre-setting cmd.err in Clone would NOT work because pipelineReadCmds overwrites it with whatever readReply returns — the drain-and-error path is what actually survives the framework. In practice this path is unreachable through normal client flows: Clone is only called from cluster fan-out routing in osscluster_router.go for multi-shard commands (DBSIZE / KEYS / FLUSHDB), and ZeroCopyStringCmd is only produced by GetToBuffer which issues GET — a single-key command routed to one shard, never fanned out. Combined with NoRetry()=true blocking the retry path, the clone path is exercised only by explicit caller code. A new Ginkgo spec asserts both that processing a clone returns the expected error and that a follow-up GetToBuffer on the same client succeeds (the drain keeps the connection usable). 2. readReply now resets cmd.n = 0 on entry so that an error after a previous successful run can't leak the old data through Bytes(). Cheap defensive belt-and-braces — the caller is supposed to check Err() first, but this removes a stale-state failure mode entirely. 3. The ZeroCopyStringCmd type godoc previously claimed "no data is consumed beyond the header line" on the buffer-too-small path. That stopped being true after the previous commit added the drain to ReadStringInto. Updated to match reality. Verified end-to-end against Redis 8.8 in Docker: orig GetToBuffer: OK cloned cmd processing: errored as expected follow-up GetToBuffer: OK — connection stays aligned * docs(string): clarify that SetFromBuffer is API symmetry, not a perf path SetFromBuffer and Set(ctx, key, buf, 0) dispatch to the same `case []byte` branch in proto.Writer and produce byte-identical output on the wire. The "zero-copy on send" property comes from bufio.Writer.Write bypassing its internal buffer for payloads larger than that buffer — a property of bufio, not of SetFromBuffer. Set([]byte) gets the same behaviour for free. Without this clarification, callers reading the godoc could reasonably infer that SetFromBuffer is a performance optimisation over Set, choose it for that reason, and be disappointed when the bench numbers come back indistinguishable from Set([]byte). The added paragraph spells out the actual rationale (API symmetry with GetToBuffer for code that uses the buffer-based pattern on both sides) and tells callers who don't care about that symmetry that Set(ctx, key, buf, 0) is equally efficient. No behaviour change.Configuration menu - View commit details
-
Copy full SHA for 74d9bb0 - Browse repository at this point
Copy the full SHA 74d9bb0View commit details -
feat(streams): support explicit LIMIT 0 in XTRIM/XADD trimming via XT…
…rimLimitDisabled sentinel (#3848) Redis treats XTRIM/XADD trimming LIMIT 0 (valid only with the ~ approximate flag) as "disable the trimming effort cap entirely", which is different from omitting LIMIT (implicit default of 100 * stream-node-max-entries examined entries). The command builders only emitted LIMIT when limit > 0, so callers could never send an explicit LIMIT 0. Following the KeepTTL = -1 precedent, add the XTrimLimitDisabled = -1 sentinel and a shared appendXTrimLimit helper used by XAdd, xTrim and xTrimMode: - limit == 0 keeps the historical behavior: no LIMIT clause is sent; - limit > 0 emits LIMIT <limit> as before; - limit < 0 (XTrimLimitDisabled) emits an explicit LIMIT 0. No public signatures or struct fields change, and existing callers passing 0 produce byte-identical commands. Exact ("=") trim commands (XTrimMaxLen, XTrimMinID and their Mode variants) still never emit LIMIT; XAddArgs keeps the existing upstream behavior of passing a user-supplied Limit through even without Approx (Redis rejects it server-side), now explicitly documented on the field. Add server-less unit tests asserting the constructed command args for the omitted/positive/disabled-limit and exact-trim cases across all XTRIM variants and XAdd.
Configuration menu - View commit details
-
Copy full SHA for 641294c - Browse repository at this point
Copy the full SHA 641294cView commit details
Commits on Jun 15, 2026
-
chore(deps): bump rojopolis/spellcheck-github-actions (#3852)
Bumps [rojopolis/spellcheck-github-actions](https://github.com/rojopolis/spellcheck-github-actions) from 0.60.0 to 0.61.0. - [Release notes](https://github.com/rojopolis/spellcheck-github-actions/releases) - [Changelog](https://github.com/rojopolis/spellcheck-github-actions/blob/master/CHANGELOG.md) - [Commits](rojopolis/spellcheck-github-actions@0.60.0...0.61.0) --- updated-dependencies: - dependency-name: rojopolis/spellcheck-github-actions dependency-version: 0.61.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Configuration menu - View commit details
-
Copy full SHA for bf57a51 - Browse repository at this point
Copy the full SHA bf57a51View commit details
Commits on Jun 17, 2026
-
feat(tx): skip redundant UNWATCH in Tx.Close when no WATCH is active (#…
…3854) Tx.Close issued UNWATCH unconditionally before returning the connection to the pool, adding a round trip to every Watch transaction even when nothing was watched or when EXEC had already discarded the watched keys. Track whether a WATCH is still active on the transaction (watchArmed) and only issue UNWATCH from Close when it is. The flag is set on a successful WATCH and cleared only when EXEC actually ran: a nil error (committed), TxFailedErr (a watched key changed, EXEC returned nil), or an EXECABORT error (a queued command was rejected, EXEC discarded the transaction) — all of which release the watched keys server-side. Any other error may be reported before EXEC executes (for example -LOADING on the MULTI reply) or on a broken connection, so the flag is left set and Close still sends UNWATCH rather than risk leaving a watch on a pooled connection. This removes the extra UNWATCH on the common WATCH/.../EXEC path and on the no-key Watch path, and never returns a connection to the pool with an active WATCH. No exported API changes; the only wire difference is the elided no-op UNWATCH. Tests assert, on the wire (recording hook) and server-side (INFO commandstats), that UNWATCH is elided after a committed EXEC, an aborted EXEC, an EXECABORT, and a no-key Watch, and is still sent on every path where no EXEC cleared the watch: an error before EXEC, a read-only decision, a non-transactional pipeline, an empty TxPipelined, multi-key bail, a WATCH re-armed after EXEC, a panic in fn, a failed WATCH, and a server error reported before EXEC runs. A manual Unwatch case asserts no second UNWATCH from Close, and a PoolSize=1 reuse case asserts no watch leaks onto a pooled connection. Co-authored-by: Claude Opus 4.8 <[email protected]>
Configuration menu - View commit details
-
Copy full SHA for 5484b0b - Browse repository at this point
Copy the full SHA 5484b0bView commit details -
feat(pubsub): introduce timeouts for Ping on channel.initHealthCheck (#…
…3819) * replace context.TODO with context.WithTimeout in channel.initHealthCheck before calling c.pubSub.Ping * fix(pubsub): create fresh timeout context for each health check * create context with timeout after lock acquisition * export pingTimeout and reconnectTimeout --------- Co-authored-by: Nedyalko Dyakov <[email protected]>
Configuration menu - View commit details
-
Copy full SHA for 1f0ea0e - Browse repository at this point
Copy the full SHA 1f0ea0eView commit details
Commits on Jun 18, 2026
-
fix(maintnotifications): keep ModeAuto fail-open (#3853)
* fix maintnotifications ModeAuto fallback * retire maintnotifications connections on downgrade * guard maintnotifications tracking during downgrade
Configuration menu - View commit details
-
Copy full SHA for 1cfa927 - Browse repository at this point
Copy the full SHA 1cfa927View commit details
Commits on Jun 22, 2026
-
chore(release): 9.21.0 (#3857)
* bump version to 9.21.0 * add release notes
Configuration menu - View commit details
-
Copy full SHA for 1551837 - Browse repository at this point
Copy the full SHA 1551837View commit details
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff v9.20.0...v9.21.0