Skip to content

[Store] Add shared thread-local random helpers#2954

Open
Aionw wants to merge 5 commits into
kvcache-ai:mainfrom
Aionw:codex/store-thread-local-random
Open

[Store] Add shared thread-local random helpers#2954
Aionw wants to merge 5 commits into
kvcache-ai:mainfrom
Aionw:codex/store-thread-local-random

Conversation

@Aionw

@Aionw Aionw commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Description

Add a shared thread-local random facility for Mooncake Store and migrate Store-owned production call sites to use it.

  • Provide one lazily seeded std::mt19937_64 engine per thread.
  • Provide unbiased randomIndex() and randomUniform() helpers, including explicit-engine overloads for deterministic tests.
  • Consolidate random selection in allocation strategies, MasterService shard/source selection, and AutoPortBinder.
  • Add scoped AGENTS.md guidance so future Store code extends the shared API instead of creating local random sources.
  • Leave src/cachelib_memory_allocator/ unchanged.

No matching open issue or pull request was found.

Module

  • Transfer Engine (mooncake-transfer-engine)
  • Mooncake Store (mooncake-store)
  • Mooncake EP (mooncake-ep)
  • Mooncake PG (mooncake-pg)
  • Integration (mooncake-integration)
  • P2P Store (mooncake-p2p-store)
  • Python Wheel (mooncake-wheel)
  • Common (mooncake-common)
  • Mooncake RL (mooncake-rl)
  • CI/CD
  • Docs
  • Other

Type of Change

  • Bug fix
  • New feature
  • Refactor
  • Breaking change
  • Documentation update
  • Performance improvement
  • Other

How Has This Been Tested?

Test commands:

cmake --build /tmp/mooncake-store-thread-local-random-build \
  --target utils_test allocation_strategy_test mooncake_master -j 16
/tmp/mooncake-store-thread-local-random-build/mooncake-store/tests/utils_test \
  --gtest_filter='RandomTest.*'
ctest --test-dir /tmp/mooncake-store-thread-local-random-build \
  --output-on-failure -R '^allocation_strategy_test$'

Test results:

  • Unit tests pass
  • Integration tests pass (not applicable)
  • Manual testing done (not applicable)

The six focused random tests passed, the allocation strategy suite passed, and mooncake_master built successfully.

Checklist

  • I have performed a self-review of my own code
  • I have formatted the touched code using the repository formatter
  • I have run pre-commit run --all-files and all hooks pass
  • I have updated the documentation (not applicable)
  • I have added tests to prove my changes are effective
  • For changes >500 LOC: I have filed an RFC issue (not applicable; under 500 LOC)

The repository-wide format hook rewrites unrelated baseline files; those rewrites were reverted. All remaining pre-commit hooks passed on the touched files.

AI Assistance Disclosure

  • No AI tools were used
  • AI tools were used (specified below)

Codex implemented the shared random facility, migrated call sites, added tests, and ran the validation commands. Before marking this PR ready, the human submitter must review every changed line and be able to defend the change end-to-end.

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request centralizes random number generation by introducing a shared thread-local random utility in include/random.h and refactoring various allocation strategies, services, and utilities to use it. Feedback on the changes points out that std::uniform_int_distribution is only defined for standard integer types (excluding smaller types like int8_t or char), which can lead to undefined behavior or compilation failures. A suggestion is provided to promote smaller integral types to int or unsigned int within randomUniform to ensure safety across all platforms.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread mooncake-store/include/random.h Outdated
Comment on lines +39 to +51
template <typename Integer, typename Generator>
Integer randomUniform(Integer lower_bound, Integer upper_bound,
Generator& generator) {
static_assert(std::is_integral_v<Integer>,
"randomUniform requires an integral result type");
if (lower_bound > upper_bound) {
throw std::invalid_argument(
"randomUniform lower bound must not exceed upper bound");
}
std::uniform_int_distribution<Integer> distribution(lower_bound,
upper_bound);
return distribution(generator);
}

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.

medium

The C++ standard specifies that std::uniform_int_distribution is only defined for short, int, long, long long, unsigned short, unsigned int, unsigned long, and unsigned long long. Instantiating it with other integral types (such as char, int8_t, uint8_t, or bool) results in undefined behavior and can cause compilation failures on some standard library implementations (e.g., libc++ on macOS).

To prevent this, we can use std::conditional_t to promote types smaller than int to int or unsigned int for the distribution, and then cast the result back to the requested Integer type.

template <typename Integer, typename Generator>
Integer randomUniform(Integer lower_bound, Integer upper_bound,
                      Generator& generator) {
    static_assert(std::is_integral_v<Integer>,
                  "randomUniform requires an integral result type");
    if (lower_bound > upper_bound) {
        throw std::invalid_argument(
            "randomUniform lower bound must not exceed upper bound");
    }
    using DistType = std::conditional_t<
        sizeof(Integer) < sizeof(int),
        std::conditional_t<std::is_signed_v<Integer>, int, unsigned int>,
        Integer>;
    std::uniform_int_distribution<DistType> distribution(
        static_cast<DistType>(lower_bound),
        static_cast<DistType>(upper_bound));
    return static_cast<Integer>(distribution(generator));
}

@Aionw
Aionw marked this pull request as ready for review July 16, 2026 09:33
@Aionw
Aionw requested review from XucSh, YiXR, stmatengss and ykwd as code owners July 16, 2026 09:33
@codecov-commenter

codecov-commenter commented Jul 16, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 95.14563% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
mooncake-store/include/allocation_strategy.h 80.00% 4 Missing ⚠️
mooncake-store/src/master_service.cpp 87.50% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@he-yufeng he-yufeng left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nice consolidation — reads well and the correctness-sensitive parts are right. A few things I checked:

  • The sampling is unbiased because it goes through std::uniform_int_distribution rather than engine() % n, and randomIndex/randomUniform reject invalid bounds (upper_bound == 0, lower > upper) instead of silently wrapping. That also quietly fixes the old call sites: uniform_int_distribution<size_t>(0, names.size() - 1) on an empty names would have underflowed to SIZE_MAX and indexed out of bounds; randomIndex(names.size()) throws instead (and the callers already guard non-empty upstream, so it isn't reachable in practice).
  • Seeding is an improvement over what it replaces: the per-thread engine is a mt19937_64 seeded from a seed_seq of eight random_device draws, versus the old std::mt19937 generator(std::random_device{}()) that fed a single 32-bit value into the engine's state. More entropy into the seed is the right call for a 64-bit engine.
  • Thread-local storage keeps it race-free by construction, the explicit-engine overloads make the samplers deterministically testable, and the AGENTS.md note plus the cachelib_memory_allocator carve-out set the convention clearly.

One forward-looking nit, not a blocker: randomUniform's static_assert(std::is_integral_v<Integer>) is looser than what std::uniform_int_distribution actually permits — the standard only allows short/int/long/long long and their unsigned forms, so instantiating with char, signed/unsigned char, bool, or int8_t compiles but is UB. Every current caller uses int, so nothing is wrong today, but since random.h is now the sanctioned shared entry point, it'd be worth tightening the assert to the permitted set (or documenting the constraint) so a future caller following the AGENTS.md rule can't reach for a narrow type and land in UB.

Approving — correctness, the seeding upgrade, and the test coverage all look good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants