Skip to content

fix(orm): replace data race in ENTITY_METADATA with std::call_once#558

Merged
kcenon merged 1 commit into
mainfrom
fix/issue-556-entity-metadata-race-condition
Apr 10, 2026
Merged

fix(orm): replace data race in ENTITY_METADATA with std::call_once#558
kcenon merged 1 commit into
mainfrom
fix/issue-556-entity-metadata-race-condition

Conversation

@kcenon

@kcenon kcenon commented Apr 10, 2026

Copy link
Copy Markdown
Owner

What

Summary

Replaces a data race in the ENTITY_METADATA() macro by swapping the unsafe static bool initialized check-then-act pattern with std::call_once + std::once_flag, guaranteeing thread-safe one-time initialization of entity metadata.

Change Type

  • Bugfix (fixes an issue)
  • Feature (new functionality)
  • Refactor (no functional changes)

Affected Components

  • database/orm/entity.hENTITY_METADATA() macro definition

Why

Problem Solved

The ENTITY_METADATA() macro used a plain static bool initialized flag with a manual check-then-act pattern that is not thread-safe under the C++11 memory model. When multiple threads call get_metadata() for the first time concurrently, initialize_metadata() could be called multiple times, leading to undefined behavior (data race) and potential duplicate field entries in the metadata.

Related Issues

Alternative Approaches Considered

  1. std::atomic<bool> with double-checked locking — More complex, same overhead as call_once
  2. Eager initialization in constructor — Would change entity construction order

Where

Files Changed

File Type of Change
database/orm/entity.h Replace static bool with std::call_once, add #include <mutex>
docs/README.kr.md Fix pre-existing broken markdown anchors

How

Implementation Details

// Before (data race)
static bool initialized = false;
if (!initialized) {
    initialize_metadata();
    initialized = true;
}

// After (thread-safe)
static std::once_flag init_flag;
std::call_once(init_flag, [this]() { initialize_metadata(); });

This aligns with the existing threading discipline in backend_base::initialized_ which correctly uses std::atomic<bool>.

Breaking Changes

None — get_metadata() return type and behavior are unchanged.

The ENTITY_METADATA() macro used a plain static bool for one-time
initialization, creating a data race when multiple threads call
get_metadata() concurrently for the first time. Replace with
std::call_once + std::once_flag for guaranteed thread-safe
initialization.

Add #include <mutex> for std::once_flag and std::call_once.

Fix pre-existing broken markdown anchors in docs/README.kr.md
(emoji-prefixed headings generating mismatched TOC anchors,
cross-file links to non-indexed guides/ directory).

Closes #556
@github-actions

Copy link
Copy Markdown
Contributor

Benchmark Results

No comparison reports available. Baseline may not be established yet.

@kcenon kcenon merged commit 4d889d7 into main Apr 10, 2026
31 checks passed
kcenon added a commit that referenced this pull request Apr 13, 2026
)

The ENTITY_METADATA() macro used a plain static bool for one-time
initialization, creating a data race when multiple threads call
get_metadata() concurrently for the first time. Replace with
std::call_once + std::once_flag for guaranteed thread-safe
initialization.

Add #include <mutex> for std::once_flag and std::call_once.

Fix pre-existing broken markdown anchors in docs/README.kr.md
(emoji-prefixed headings generating mismatched TOC anchors,
cross-file links to non-indexed guides/ directory).

Closes #556
@kcenon kcenon deleted the fix/issue-556-entity-metadata-race-condition branch May 1, 2026 13:24
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.

[Bug] ENTITY_METADATA() macro has data race on static bool initialized

1 participant