chore: CRDT bridge concurrency improvements#8968
Open
pravusjif wants to merge 1 commit into
Open
Conversation
- outgoing message serialization moved outside the producers' lock via list double-buffering - WorldSyncCommandBuffer instance reused across batches (Renew) instead of per-tick allocation - idle fast path: empty sync buffers skip the world mutex acquisition and command buffer playback Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
This was referenced Jun 12, 2026
Contributor
|
PR #8968, run #27390699039 Builds: Windows change, Windows baseline, macOS change, macOS baseline How to read this table
Framework 13 i7
Exception breakdown
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Three concurrency/allocation fixes on the scene ↔ renderer CRDT bridge, one PR of a series based on a CRDT pipeline audit (independent of #8967 — either can merge first; whichever lands second needs a small mechanical rebase in
OutgoingCRDTMessagesProvider/EngineAPIImplementation):OutgoingCRDTMessagesProvider.GetSerializationSyncBlockused to holdlock (messages)across protobufCalculateSize+SerializeIntofor every pending message, while every main-thread ECS system writing a Put/Delete/Append contends on that same lock once per scene tick. Now the pending list is swapped with a spare under the lock (a reference swap) and serialized lock-free; this is safe because the method is only invoked from the scene runtime thread (single consumer).WorldSyncCommandBufferreuse —GetSyncCommandBuffer()allocated a new buffer object everyCrdtSendToRenderercall (every tick of every scene, idle or not). The synchronizer's semaphore already guarantees one outstanding buffer, so a single instance is now kept andRenew()ed.MultiThreadSyncworld mutex — blocking the scene thread on main-thread availability — and ran an emptycommandBuffer.Playback.IWorldSyncCommandBuffer.IsEmpty(valid afterFinalizeAndDeserialize) now routes empty buffers through a newReleaseSyncCommandBufferthat disposes and releases the rent without touching the world. The systems update gate still opens on every tick so scene-world systems keep producing outgoing data.Why
These are per-tick fixed costs multiplied by scene count: with dozens of loaded scenes, mostly idle, every tick paid a main-thread lock stall, a wasted mutex round-trip, and a garbage buffer object.
QA / verification
DCL.EditMode.Testscompile clean locally (dotnet build, 0 errors).IsEmptysemantics inWorldSyncCommandBufferShould(4 cases incl. add+delete merging to no-op), buffer instance reuse and release-without-apply inCrdtWorldSynchronizerShould. Please rely on the CI EditMode run for execution; a local Test Runner run was not possible (editor lock).🤖 Generated with Claude Code