Skip to content

Shard verifySig cache to reduce mutex contention. - #5286

Merged
dmkozh merged 2 commits into
stellar:masterfrom
dmkozh:sig_cache_opt
Oct 27, 2026
Merged

dmkozh merged 2 commits into
stellar:masterfrom
dmkozh:sig_cache_opt

Conversation

@dmkozh

@dmkozh dmkozh commented May 21, 2026

Copy link
Copy Markdown
Contributor

Description

Replace the single global mutex + RandomEvictionCache with 16 sharded caches (each with its own mutex) so concurrent signature verification threads no longer block on a shared lock.

Also use the single-lookup maybeGet() in place of the exists()/get() double-lookup and use Rust verification unconditionally (an overdue cleanup).

Checklist

  • Reviewed the contributing document
  • Rebased on top of master (no merge commits)
  • Ran clang-format v8.0.0 (via make format or the Visual Studio extension)
  • Compiles
  • Ran all tests
  • If change impacts performance, include supporting evidence per the performance document

Copilot AI review requested due to automatic review settings May 21, 2026 23:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces lock contention in the global Ed25519 signature-verification result cache by sharding it into multiple independently-locked caches, improving throughput when signature verification occurs concurrently across threads. It also removes the protocol-gated switch to Rust ed25519-dalek verification and uses the Rust verifier unconditionally.

Changes:

  • Replace the single global RandomEvictionCache + mutex with 16 sharded caches (one mutex per shard).
  • Switch cache lookups from exists()/get() to maybeGet() to avoid a double hash-table lookup on hits.
  • Remove the protocol-version-triggered enableRustDalekVerify() mechanism and always verify via the Rust dalek bridge.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/main/ApplicationImpl.cpp Removes protocol-version-based enablement of Rust dalek verification during startup.
src/ledger/LedgerManagerImpl.cpp Removes protocol-version-based enablement of Rust dalek verification when setting LCL.
src/herder/Upgrades.cpp Removes Rust dalek enablement at the protocol version upgrade boundary.
src/crypto/test/CryptoTests.cpp Removes explicit test-time enabling of Rust dalek verification.
src/crypto/SecretKey.h Removes the enableRustDalekVerify() declaration and related comments.
src/crypto/SecretKey.cpp Implements sharded verifySig cache, atomic hit/miss counters, and unconditional Rust dalek verification.

@dmkozh
dmkozh requested a review from marta-lokhova May 29, 2026 17:12
Comment thread src/crypto/SecretKey.cpp Outdated
Comment thread src/crypto/SecretKey.cpp Outdated
@SirTyson

SirTyson commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

A few nits. One performance observation though. While this is an improvement, we still have a blocking dependency when we hash anything due to gKeyMutex. This actually make a pretty significant delta here, I had AI put together a benchmark test, and we got 10x better throughput when we removed this mutex (assuming all threads saturated with 100% cache hit rate). In practice it won't be that significant, but still seems non-trivial, and I assume there's other places where we hash state in a multi-threaded context.

It doesn't seem like we actually need this mutex either. It's just to protect our initial hash seed, which we just set once on startup. We do modify the seed in test contexts, but is there any reason we can't just move the mutex behind BUILD_TESTS?

Copilot AI balanced review requested due to automatic review settings October 15, 2026 23:23
@dmkozh

dmkozh commented Oct 15, 2026

Copy link
Copy Markdown
Contributor Author

One performance observation though. While this is an improvement, we still have a blocking dependency when we hash anything due to gKeyMutex.

ShortHash locking has been removed a while ago, this branch is just very old. So it shouldn't be an issue anymore.

FWIW I've also prototyped the lock-free version of cache, but it's sketchy and doesn't seem worth it based on benchmarks. Also, there was yet another global mutex, which was easily replaceable with atomics.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Concurrent metric drains can produce inconsistent counts, and shard selection causes hash-bucket clustering on Windows.

2 open findings

🧠 Review effort: Balanced

Comment thread src/crypto/SecretKey.cpp Outdated
Comment thread src/transactions/SignatureChecker.cpp
SirTyson
SirTyson previously approved these changes Oct 25, 2026

@SirTyson SirTyson left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, LGTM!

Replace the single signature cache global mutex + RandomEvictionCache with 64 sharded caches (each with its own mutex) so concurrent signature verification threads no longer block on a shared lock. In addition, replace another global mutex for metrics with atomic counters.

Also use the single-lookup maybeGet() in place of the exists()/get() double-lookup and use Rust verification unconditionally.
SirTyson
SirTyson previously approved these changes Oct 27, 2026
@dmkozh
dmkozh added this pull request to the merge queue Oct 27, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 27, 2026
@dmkozh
dmkozh enabled auto-merge October 27, 2026 21:06
@dmkozh
dmkozh added this pull request to the merge queue Oct 27, 2026
Merged via the queue into stellar:master with commit b8c4f12 Oct 27, 2026
60 of 62 checks passed
@dmkozh
dmkozh deleted the sig_cache_opt branch October 27, 2026 22:57
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.

3 participants