Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ jobs:
with:
name: packages
path: .nupkgs/*.nupkg
include-hidden-files: true # .nupkgs is a dot-folder, which upload-artifact skips by default
if-no-files-found: error
- name: NuGet login (OIDC to temp API key)
if: github.event_name == 'release'
uses: NuGet/login@v1
Expand Down
7 changes: 4 additions & 3 deletions docs/SyncOverAsync.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,10 @@ service while the real fix is made. It is not a licence to keep the blocking cal

Two caveats worth knowing before you enable it:

- it costs a reader and a writer thread **for each node you connect to** (not RESP2 pub/sub connections, which
stay on the thread-pool; RESP3 does not use separate pub/sub connections), so think about it before enabling
it against a very wide cluster, where that scales with the number of shards;
- it costs three threads **for each node you connect to** — two readers (one pulling bytes off the socket, one
parsing and dispatching them) and a writer (not RESP2 pub/sub connections, which stay on the thread-pool; RESP3
does not use separate pub/sub connections), so think about it before enabling it against a very wide cluster,
where that scales with the number of shards;
- it is deliberately opt-in, and set process-wide at startup rather than per-connection.

Neither is meant to be permanent, and the first one especially. Work is in progress on dedicated readers built
Expand Down
9 changes: 9 additions & 0 deletions src/RESPite/Buffers/CycleBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,15 @@ public void Recycle()
Memory = default;
RunningIndex = 0;
_flags = Flags.None;

// This object becomes available - via the *shared, static* _spare slot below - to any
// CycleBuffer instance in the process, handed out by Segment.Create() as a pristine segment.
// StartTrimCount must not survive that: some callers reach Recycle() without having gone
// through Untrim() first (e.g. AppendOrRecycle's search-exhausted path), and Init() (called
// from Create()) never touches it either. A stale nonzero value here previously surfaced as
// Debug.Assert(leasedStart == 0, "should be zero for a new segment") failing in
// GetUncommittedMemory for what looked like a brand new segment.
StartTrimCount = 0;
Interlocked.Exchange(ref _spare, this);
DebugAssertValidChain();
}
Expand Down
6 changes: 4 additions & 2 deletions src/RESPite/Messages/RespReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1390,7 +1390,8 @@ public unsafe bool TryReadNext()
{
case LengthPrefixResult.Length:
// still need to valid terminating CRLF
if (remaining.Length < consumed + _length + 2) break; // need more data
// long: _length can be up to int.MaxValue, so this sum can overflow int
if (remaining.Length < (long)consumed + _length + 2) break; // need more data
UnsafeAssertClLf(1 + consumed + _length);

_flags = RespFlags.IsScalar | RespFlags.IsInlineScalar;
Expand Down Expand Up @@ -1418,7 +1419,8 @@ public unsafe bool TryReadNext()
break;
case LengthPrefixResult.Length:
// still need to valid terminating CRLF
if (remaining.Length < consumed + _length + 2) break; // need more data
// long: _length can be up to int.MaxValue, so this sum can overflow int
if (remaining.Length < (long)consumed + _length + 2) break; // need more data
UnsafeAssertClLf(1 + consumed + _length);

_flags = RespFlags.IsScalar | RespFlags.IsInlineScalar | RespFlags.IsStreaming;
Expand Down
5 changes: 3 additions & 2 deletions src/StackExchange.Redis/ConnectionMultiplexer.FeatureFlags.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ private enum FeatureFlags
/// out of that queue. It does not *fix* the thread-pool, and nothing here can: it means only that redis
/// traffic keeps flowing while the real problem is found. See docs/SyncOverAsync.md.
/// <para>
/// Costs a reader and a writer thread per connection, so it is worth thinking about before enabling it
/// against a very wide cluster, where connection counts scale with the number of shards.
/// Costs three threads per connection - two readers (one pulling bytes off the socket, one parsing and
/// dispatching them) and a writer - so it is worth thinking about before enabling it against a very wide
/// cluster, where connection counts scale with the number of shards.
/// </para>
/// </remarks>
DedicatedThreads = 2,
Expand Down
Loading
Loading