Visitar URL original
Reset a CycleBuffer segment's start trim when it is recycled (#3302) by mgravell · Pull Request #3303 · seredis/StackExchange.Redis · GitHub
Skip to content

Reset a CycleBuffer segment's start trim when it is recycled (#3302) - #3303

Merged
mgravell merged 2 commits into
mainfrom
marc/3302-cyclebuffer-trim
Oct 27, 2026
Merged

mgravell merged 2 commits into
mainfrom
marc/3302-cyclebuffer-trim

Conversation

@mgravell

Copy link
Copy Markdown
Member

Fixes #3302.

CycleBuffer.Segment.Recycle() returns segments to a process-wide _spare slot without resetting StartTrimCount, and Create/Init don't reset it either, so the next buffer to take that segment (any connection, any multiplexer) inherits a trim that never happened. Segments reach the slot still trimmed via Release() and via AppendOrRecycle's search-exhausted path (after ResetAndGetNext, which restores Memory but not the trim) - the latter in steady state for multi-segment buffers, not just on teardown.

The stale value bites in Commit -> CopyDueToDiscardDuringWrite: when the buffer is fully drained while a write lease is open (the outbound copy-out loop discarding while the writer holds GetMemory), Untrim zeroes the trim and the copy reads from leasedStart, which still includes the stale offset - so the wrong bytes go out.

  • Cherry-picks de30137 from the v4 line: reset StartTrimCount in Recycle, plus its test.
  • Adds DiscardDuringWriteKeepsLeasedBytesAfterARecycledTrimmedSegment, which checks the bytes rather than the field: without the fix the second buffer commits 789 (the previous buffer's payload) instead of XYZ.

RESPite.Tests pass on net10.0 (1719/1719).

Absorbed from PR #3251's branch (0ce150b), where its read/parse stress test
found it. Segment.Recycle returns the segment to a process-wide spare slot,
from which Segment.Create hands it to any buffer as pristine - but it kept
StartTrimCount, and some paths recycle without Untrim first (Release, and
AppendOrRecycle's search-exhausted path). The next buffer's 'new' segment
then carried a trim that never happened: Debug.Assert(leasedStart == 0) in
Debug, and in Release a later Untrim expanding backwards by it, corrupting
the chain's running indexes.

ARecycledTrimmedSegmentStartsCleanInTheNextBuffer: trim, Release, then a new
buffer's first segment - StartTrimCount 4 on the old code, 0 now.
)

A discard that drains the buffer while a write lease is open - the outbound
copy-out loop racing the writer - copied from leasedStart, which included the
stale trim; the 'new' buffer emitted bytes from the previous owner's payload
('789' instead of 'XYZ').
@mgravell
mgravell merged commit ee47e53 into main Oct 27, 2026
5 checks passed
@mgravell
mgravell deleted the marc/3302-cyclebuffer-trim branch October 27, 2026 11:52
mgravell added a commit that referenced this pull request Oct 29, 2026
…nore)

- #3303: the CycleBuffer fix itself was already in v4 (recycle resets StartTrimCount); only main's second
  test, DiscardDuringWriteKeepsLeasedBytesAfterARecycledTrimmedSegment, is new here.
- #3306: .claude/* ignored except .claude/skills/, superseding v4's .claude/worktrees/ line.
FloatingMilkshake added a commit to FloatingMilkshake/Azusa that referenced this pull request Oct 30, 2026
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [StackExchange.Redis](https://seredis.dev/) ([source](https://github.com/StackExchange/StackExchange.Redis)) | nuget | patch | `3.4.20` → `3.4.29` |

---

### Release Notes

<details>
<summary>StackExchange/StackExchange.Redis (StackExchange.Redis)</summary>

### [`v3.4.29`](https://github.com/StackExchange/StackExchange.Redis/releases/tag/3.4.29)

[Compare Source](seredis/StackExchange.Redis@3.4.20...3.4.29)

#### What's Changed

- (stabilty) Reset a CycleBuffer segment's start trim when it is recycled ([#&#8203;3302](seredis/StackExchange.Redis#3302)) by [@&#8203;mgravell](https://github.com/mgravell) in [#&#8203;3303](seredis/StackExchange.Redis#3303)
- Restore: make the dedicated subscription connection lazy by [@&#8203;mgravell](https://github.com/mgravell) in [#&#8203;3310](seredis/StackExchange.Redis#3310)
- Update RedisType.Bitmap and the keyspace-event tokens to reflect current server values by [@&#8203;mgravell](https://github.com/mgravell) in [#&#8203;3312](seredis/StackExchange.Redis#3312)
- Fix ConnectionGroupMember string-ctor dropping the name by [@&#8203;mgravell](https://github.com/mgravell) in [#&#8203;3314](seredis/StackExchange.Redis#3314)
- Parse unbracketed IPv6 ip:port from the server ([#&#8203;1422](seredis/StackExchange.Redis#1422)) by [@&#8203;mgravell](https://github.com/mgravell) in [#&#8203;3307](seredis/StackExchange.Redis#3307)
- Profile commands sent in a batch ([#&#8203;2175](seredis/StackExchange.Redis#2175)) by [@&#8203;mohsinaliwork686-rgb](https://github.com/mohsinaliwork686-rgb) in [#&#8203;3313](seredis/StackExchange.Redis#3313)

#### Tooling

- gitignore: .claude is per-user state except .claude/skills by [@&#8203;mgravell](https://github.com/mgravell) in [#&#8203;3306](seredis/StackExchange.Redis#3306)
- Command coverage ledger and audit skill by [@&#8203;mgravell](https://github.com/mgravell) in [#&#8203;3311](seredis/StackExchange.Redis#3311)
- Update public API docs by [@&#8203;mgravell](https://github.com/mgravell) in [#&#8203;3429](https://github.com/StackExchange/StackExchange.Redis/pull/3429)

#### New Contributors

- [@&#8203;mohsinaliwork686-rgb](https://github.com/mohsinaliwork686-rgb) made their first contribution in [#&#8203;3313](seredis/StackExchange.Redis#3313)

**Full Changelog**: <seredis/StackExchange.Redis@3.4.20...3.4.29>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xOTguMiIsInVwZGF0ZWRJblZlciI6IjQ0LjE5OC4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://git.milkshake.services/FloatingMilkshake/Azusa/pulls/13
Reviewed-by: Milkshake <me@floatingmilkshake.com>
FloatingMilkshake added a commit to FloatingMilkshake/MechanicalMilkshake that referenced this pull request Oct 30, 2026
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [StackExchange.Redis](https://seredis.dev/) ([source](https://github.com/StackExchange/StackExchange.Redis)) | nuget | patch | `3.4.20` → `3.4.29` |

---

### Release Notes

<details>
<summary>StackExchange/StackExchange.Redis (StackExchange.Redis)</summary>

### [`v3.4.29`](https://github.com/StackExchange/StackExchange.Redis/releases/tag/3.4.29)

[Compare Source](seredis/StackExchange.Redis@3.4.20...3.4.29)

#### What's Changed

- (stabilty) Reset a CycleBuffer segment's start trim when it is recycled ([#&#8203;3302](seredis/StackExchange.Redis#3302)) by [@&#8203;mgravell](https://github.com/mgravell) in [#&#8203;3303](seredis/StackExchange.Redis#3303)
- Restore: make the dedicated subscription connection lazy by [@&#8203;mgravell](https://github.com/mgravell) in [#&#8203;3310](seredis/StackExchange.Redis#3310)
- Update RedisType.Bitmap and the keyspace-event tokens to reflect current server values by [@&#8203;mgravell](https://github.com/mgravell) in [#&#8203;3312](seredis/StackExchange.Redis#3312)
- Fix ConnectionGroupMember string-ctor dropping the name by [@&#8203;mgravell](https://github.com/mgravell) in [#&#8203;3314](seredis/StackExchange.Redis#3314)
- Parse unbracketed IPv6 ip:port from the server ([#&#8203;1422](seredis/StackExchange.Redis#1422)) by [@&#8203;mgravell](https://github.com/mgravell) in [#&#8203;3307](seredis/StackExchange.Redis#3307)
- Profile commands sent in a batch ([#&#8203;2175](seredis/StackExchange.Redis#2175)) by [@&#8203;mohsinaliwork686-rgb](https://github.com/mohsinaliwork686-rgb) in [#&#8203;3313](seredis/StackExchange.Redis#3313)

#### Tooling

- gitignore: .claude is per-user state except .claude/skills by [@&#8203;mgravell](https://github.com/mgravell) in [#&#8203;3306](seredis/StackExchange.Redis#3306)
- Command coverage ledger and audit skill by [@&#8203;mgravell](https://github.com/mgravell) in [#&#8203;3311](seredis/StackExchange.Redis#3311)
- Update public API docs by [@&#8203;mgravell](https://github.com/mgravell) in [#&#8203;3429](https://github.com/StackExchange/StackExchange.Redis/pull/3429)

#### New Contributors

- [@&#8203;mohsinaliwork686-rgb](https://github.com/mohsinaliwork686-rgb) made their first contribution in [#&#8203;3313](seredis/StackExchange.Redis#3313)

**Full Changelog**: <seredis/StackExchange.Redis@3.4.20...3.4.29>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xOTguMiIsInVwZGF0ZWRJblZlciI6IjQ0LjE5OC4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://git.milkshake.services/FloatingMilkshake/MechanicalMilkshake/pulls/13
Reviewed-by: Milkshake <me@floatingmilkshake.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

v3: CycleBuffer recycles a segment without resetting StartTrimCount, corrupting another connection's reply stream (request to backport de301373 to 3.4.x)

1 participant