Skip to content

Add thread-safe double-checked locking to MotelyPaths.Initialize#19

Merged
joirunner merged 4 commits intofeat/stabilize-local-dev-pathsfrom
copilot/sub-pr-1-one-more-time
Jan 20, 2026
Merged

Add thread-safe double-checked locking to MotelyPaths.Initialize#19
joirunner merged 4 commits intofeat/stabilize-local-dev-pathsfrom
copilot/sub-pr-1-one-more-time

Conversation

Copy link

Copilot AI commented Jan 19, 2026

The volatile keyword alone is insufficient for thread-safe initialization. Multiple threads calling Initialize concurrently could race, creating directories multiple times or setting _isInitialized before initialization completes.

Changes

  • Added lock-based synchronization: Introduced _initLock with double-checked locking pattern
  • Fast path optimization: Check _isInitialized before acquiring lock to minimize contention post-initialization
  • Atomic initialization: All field assignments and directory creation complete within lock before marking initialized
  • Fail-safe behavior: Exceptions during directory creation prevent _isInitialized from being set, allowing retry
public static void Initialize(IWebHostEnvironment env, IConfiguration? config = null)
{
    // Fast path: if already initialized, return immediately
    if (_isInitialized)
        return;

    lock (_initLock)
    {
        // Double-check after acquiring lock
        if (_isInitialized)
            return;

        _contentRoot = env.ContentRootPath;
        // ... set overrides, create directories ...
        _isInitialized = true;
    }
}

The volatile fields remain necessary for memory ordering guarantees on the initialization flag.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 3 commits January 19, 2026 23:52
Co-authored-by: joirunner <6373131+joirunner@users.noreply.github.com>
Co-authored-by: joirunner <6373131+joirunner@users.noreply.github.com>
…hrows

Co-authored-by: joirunner <6373131+joirunner@users.noreply.github.com>
@joirunner joirunner marked this pull request as ready for review January 19, 2026 23:55
Copilot AI review requested due to automatic review settings January 19, 2026 23:55
Copilot AI changed the title [WIP] WIP address feedback on local dev paths stabilization Add thread-safe double-checked locking to MotelyPaths.Initialize Jan 19, 2026
Copilot AI requested a review from joirunner January 19, 2026 23:55
Copy link

Copilot AI left a comment

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 implements thread-safe initialization for the MotelyPaths static class using a double-checked locking pattern to address concurrency concerns raised in code review feedback.

Changes:

  • Added thread-safe initialization using double-checked locking pattern with a dedicated lock object
  • Updated documentation to clarify thread-safety guarantees and behavior
  • Ensured atomic initialization where directory creation failures allow for retry
Comments suppressed due to low confidence (1)

Motely.API/MotelyPaths.cs:18

  • The volatile keyword on the string fields (_contentRoot, _jamlFiltersOverride, etc.) is unnecessary and potentially misleading. In the double-checked locking pattern, only the _isInitialized flag needs to be volatile to ensure proper memory ordering. The lock in the Initialize method already provides the necessary memory barriers to ensure that all field writes inside the lock are visible to threads that read _isInitialized as true. These volatile keywords can be removed from the string fields while keeping it only on _isInitialized.
    private static volatile string _contentRoot = Directory.GetCurrentDirectory();
    private static volatile string? _jamlFiltersOverride;
    private static volatile string? _seedSourcesOverride;
    private static volatile string? _searchResultsOverride;

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +104 to +105
// Kept inside the lock to ensure atomic initialization: if directory creation fails,
// _isInitialized remains false, allowing retry on next Initialize call.
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

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

The comment states "Kept inside the lock to ensure atomic initialization" but the actual reason is more nuanced. Directory creation is a side effect that can fail, and keeping it inside the lock ensures that if it fails and throws an exception, _isInitialized remains false, allowing retry. However, the operations themselves are not truly "atomic" - if directory creation partially succeeds then fails, some directories may exist while others don't. Consider clarifying this comment to explain the retry-on-failure behavior more explicitly.

Suggested change
// Kept inside the lock to ensure atomic initialization: if directory creation fails,
// _isInitialized remains false, allowing retry on next Initialize call.
// Kept inside the lock so that if any directory creation fails and throws,
// _isInitialized remains false and a future Initialize call can safely retry.

Copilot uses AI. Check for mistakes.
@joirunner joirunner merged commit 587a40e into feat/stabilize-local-dev-paths Jan 20, 2026
6 checks passed
@joirunner joirunner deleted the copilot/sub-pr-1-one-more-time branch January 20, 2026 00:01
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