Skip to content

fix(p2p): serialize sync application - #73

Merged
trvon merged 1 commit into
fix/p2p-bootstrap-trustfrom
fix/p2p-apply-serialization
Aug 30, 2026
Merged

fix(p2p): serialize sync application#73
trvon merged 1 commit into
fix/p2p-bootstrap-trustfrom
fix/p2p-apply-serialization

Conversation

@trvon

@trvon trvon commented Aug 29, 2026

Copy link
Copy Markdown
Owner

Summary

Stacked draft child of #72. This change closes the disclosed direct-P2P replicated-apply serialization blocker without merging or deploying anything.

  • serializes post-sync callbacks from periodic reconciliation and concurrent direct-P2P sessions process-wide, preventing cross-service ABBA cycles
  • keeps memory-sync loop locks released before adapter callbacks, preserving safe callback re-entry
  • coalesces callback-side recursive publications and refreshes queued snapshots instead of deadlocking, regressing state, or dropping follow-up work
  • invalidates pre-stop queued callbacks and safely drains direct-session callbacks across stop/restart and cross-service destruction
  • serializes the daemon content/metadata/vector/topology apply pipeline and vector rebuild state
  • separately serializes bounded daemon backfill cursor/domain state

Before the fix:

  • two concurrent direct-delta applies entered the post-sync callback simultaneously (maximumActive == 2)
  • two concurrent daemon apply calls both reached apply.after_content while the first callback remained blocked

Known stack blockers

This draft child is not independently mergeable or deployable. The umbrella still has separately tracked operator-status semantics, fuzzing, and final live/release gates.

AI disclosure

Extensive AI assistance was used for implementation, test generation, and adversarial review. All changes were locally inspected and validated; remaining stack blockers are disclosed above.

Stack

Do not merge or deploy this child independently.

Signed-off-by: trvon <git@trevon.dev>
@trvon
trvon marked this pull request as ready for review August 30, 2026 15:48
Copilot AI lite review requested due to automatic review settings August 30, 2026 15:48

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

The updated MemorySyncService shutdown/drain locking introduces a credible cross-thread ABBA deadlock scenario between lifecycleMutex_ and the global callbackExecutionMutex_ that should be resolved before approval.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR adds process-wide serialization for MemorySyncService post-sync adapter callbacks and serializes the daemon’s memory-sync apply/backfill pipelines to prevent concurrent callback/apply interleavings that can trigger cross-service lock cycles during direct-P2P replication.

Changes:

  • Serialize MemorySyncService after-sync callback execution across service instances, with callback coalescing for recursive callback-triggered work and stop/restart generation invalidation.
  • Serialize daemon memory-sync apply and backfill execution with dedicated mutexes and test-only counters/lock-introspection.
  • Add unit and integration tests covering concurrent apply/callback serialization, stop/drain behavior, and callback-driven cross-service interactions.
File summaries
File Description
tests/unit/memory_sync/memory_sync_service_catch2_test.cpp Adds concurrency/stop/destruction/recursive-callback unit tests for serialized post-sync callbacks.
tests/integration/daemon/meson.build Registers a new non-parallel daemon integration test for apply serialization.
tests/integration/daemon/memory_sync_service_integration_test.cpp Adds integration coverage for serialized daemon apply/backfill callbacks and correct replication outcomes.
src/daemon/components/ServiceManager.cpp Serializes daemon apply/backfill entrypoints and adds attempt counters for test assertions.
include/yams/memory_sync/memory_sync_service.h Implements process-wide callback serialization, callback snapshot context stacking, and stop/restart callback drain logic.
include/yams/daemon/components/ServiceManager.h Adds mutexes/counters and testing helpers for daemon apply/backfill serialization observability.
Review details
  • Files reviewed: 6/6 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 132 to +146
@@ -117,6 +141,9 @@ class MemorySyncService {
shutdownFailures_.fetch_add(1, std::memory_order_relaxed);
}
}
// Direct-session callbacks do not belong to worker_. Drain the active callback before
// releasing lifecycleMutex_. Generation checks discard callbacks queued before stop().
std::lock_guard<std::recursive_mutex> callbackDrain(callbackExecutionMutex_);
Comment on lines +567 to 573
while (!callbackExecutionMutex_.try_lock()) {
if (stop_.load(std::memory_order_acquire) ||
callbackGeneration != callbackGeneration_.load(std::memory_order_acquire)) {
return;
}
std::this_thread::yield();
}
@trvon
trvon merged commit e954c6d into experimental Aug 30, 2026
4 checks passed
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.

2 participants