Repository navigation
[Store] Add the namespace layer over the object route - #4721
Merged
Merged
Conversation
17 tasks done
The striped object route keeps each key's lock, record and per-object state, but a tenant's metadata needs more kept in step with every write: the keys with work in flight, so the expiry sweep need not walk every object; the order eviction visits objects in, so it need not take a census of every shard; and a seam for policies such as tenant quotas, so they stop being booked by hand on each mutating path. Add that layer, unwired: - The route gives each slot a few owner words (SlotOwnerState) and two intrusive list hooks, which it stores and never reads, and lets the owner reach them through a write guard or write cursor. - metadata::Namespace owns one tenant's route and observes it: as each write guard is released it lists or unlists the key on a striped in-flight list, refiles it in the eviction index, and passes the release on to the namespace policy. - EvictionIndex is the order eviction visits a namespace's objects in; LeaseEvictionIndex ranks keys by lease deadline in 100 ms buckets and needs no read hook, since a read only ever moves a key later. - NamespacePolicy is the seam a policy plugs into (admit a write, approve growth, replace, tear down, write release, restore, capacity change, maintenance), and StoreControl is what the core offers back. - metadata::NamespaceTable maps tenant ids to namespaces. A namespace is created atomically and never moves or goes away while the service runs, so a resolved reference needs no ownership, and the default namespace resolves through an atomic without the map lock. These replace metadata/tenant.h and metadata/tenant_registry.h, the unwired layer they grew from, and their tests. MasterService does not use any of this yet. Co-authored-by: CAICAIIs <3360776475@qq.com>
Aionw
force-pushed
the
refactor/namespace-layer
branch
from
October 19, 2026 03:33
11a3f59 to
397ae5a
Compare
ykwd
approved these changes
Oct 20, 2026
This was referenced Oct 20, 2026
zxpdemonio
added a commit
to zxpdemonio/Mooncake
that referenced
this pull request
Oct 21, 2026
…20261021 * upstream/main: (507 commits) [Reshard] Plan Store KV reuse across TP, PP and host layouts (kvcache-ai#4762) [Store] Walk tenants through shard-backed cursors and build the removes on them (kvcache-ai#4796) [Store-RS][Bugfix] Match TENT Request Layout to the C ABI (kvcache-ai#4732) [TransferEngine] Recover auto GID after data-path retry exhaustion (kvcache-ai#4290) [Store] Add the namespace layer over the object route (kvcache-ai#4721) [Store] Fix silent loss of offload keys deferred to the ungrouped pool (kvcache-ai#3006) (kvcache-ai#3009) [Store] Remove redundant alignment headroom from DFS shard allocation (kvcache-ai#4753) [CI/Build] Gate ROCm hardware tests and bound nightly Docker builds (kvcache-ai#4750) [Bugfix][Store] Fix double-counting of segment OpLog metrics in OpLogApplier (kvcache-ai#4771) [Store] Skip hot-cache writeback for device-resident read destinations (kvcache-ai#4764) [Reshard] Add bounded in-flight execution for weight transfers (kvcache-ai#4628) [Store] Avoid racing with detached hot-cache fills during key scans (kvcache-ai#4334) [Store] HA: drain the master on SIGTERM/SIGINT before exit (part 1 of kvcache-ai#4710) (kvcache-ai#4745) TENT: report a notification the receiver could not take (kvcache-ai#4754) [Store] Reach object metadata through a per-key accessor contract (kvcache-ai#4717) [Store][Bugfix] Fix DFS sync client test retry failure (kvcache-ai#4781) [Wheel] Keep integer dtype for typed_ragged rows when a row is an empty list (kvcache-ai#4611) [Doc] Sync README news onto the docs homepage (kvcache-ai#4767) [CI] remove stale Torch version binding after PG JIT (kvcache-ai#4760) [TransferEngine] Add buffer-protocol and page-gathered batch transfer APIs (kvcache-ai#4763) ...
zxpdemonio
added a commit
to zxpdemonio/Mooncake
that referenced
this pull request
Oct 21, 2026
…-ranges-20261021 * upstream/main: (394 commits) [Reshard] Plan Store KV reuse across TP, PP and host layouts (kvcache-ai#4762) [Store] Walk tenants through shard-backed cursors and build the removes on them (kvcache-ai#4796) [Store-RS][Bugfix] Match TENT Request Layout to the C ABI (kvcache-ai#4732) [TransferEngine] Recover auto GID after data-path retry exhaustion (kvcache-ai#4290) [Store] Add the namespace layer over the object route (kvcache-ai#4721) [Store] Fix silent loss of offload keys deferred to the ungrouped pool (kvcache-ai#3006) (kvcache-ai#3009) [Store] Remove redundant alignment headroom from DFS shard allocation (kvcache-ai#4753) [CI/Build] Gate ROCm hardware tests and bound nightly Docker builds (kvcache-ai#4750) [Bugfix][Store] Fix double-counting of segment OpLog metrics in OpLogApplier (kvcache-ai#4771) [Store] Skip hot-cache writeback for device-resident read destinations (kvcache-ai#4764) [Reshard] Add bounded in-flight execution for weight transfers (kvcache-ai#4628) [Store] Avoid racing with detached hot-cache fills during key scans (kvcache-ai#4334) [Store] HA: drain the master on SIGTERM/SIGINT before exit (part 1 of kvcache-ai#4710) (kvcache-ai#4745) TENT: report a notification the receiver could not take (kvcache-ai#4754) [Store] Reach object metadata through a per-key accessor contract (kvcache-ai#4717) [Store][Bugfix] Fix DFS sync client test retry failure (kvcache-ai#4781) [Wheel] Keep integer dtype for typed_ragged rows when a row is an empty list (kvcache-ai#4611) [Doc] Sync README news onto the docs homepage (kvcache-ai#4767) [CI] remove stale Torch version binding after PG JIT (kvcache-ai#4760) [TransferEngine] Add buffer-protocol and page-gathered batch transfer APIs (kvcache-ai#4763) ...
8 of 36 tasks
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.
Description
Step 6 of #4557: the namespace layer over the object route from step 5 (#4585). Nothing calls it yet;
MasterServicestill serves from its 1024 metadata shards.The route keeps each key's lock, record and
ObjectState, but a tenant's metadata needs more kept in step with every write: the keys that carry work in flight, so the expiry sweep need not walk every object; the order eviction visits objects in, so it need not take a census of every shard; and a place for a policy such as tenant quotas, so it is not booked by hand on each mutating path. This PR adds that layer and replaces the unwiredmetadata/tenant.handmetadata/tenant_registry.hit grew from.KeySlotgains a few words for the route's owner (SlotOwnerState: whether the key is on the in-flight list, whether and at what rank the eviction index files it, two policy words) and two intrusive list hooks. The route stores them and never reads them; the owner reaches them through a write guard's or write cursor'sowner_state(). The owner links a slot only while it holds an object, so a slot the route drops is never linked, and safe-link hooks assert it.metadata::Namespaceowns one tenant'sObjectRouteand is itsRouteObserver. As each write guard is released, with the key still locked, it lists or unlists the key on a 64-stripe in-flight list, refiles it in the eviction index, and passes the release on to the policy. A sweep readsInFlightKeys()as a snapshot to resolve again. Builds with assertions on check that a key left with no object has its owner state back to the initial value.metadata::EvictionIndexis the order eviction visits a namespace's objects in, read through a cursor, lowest rank first.LeaseEvictionIndexfiles the keys eviction can take memory from (not hard pinned, with a completed memory replica) by lease deadline in 100 ms buckets. A read only ever moves a key's deadline later, so it needs no read hook: the cursor'sStillAt, asked under the key's write lock, catches a key that moved on, and that lock's release refiles it.NamespacePolicyis the seam a policy plugs into: admit a write, approve growth before allocation, replace, tear down, write release, restore, capacity change and a maintenance tick, each called at a fixed point under fixed locks.StoreControlis what the core offers a policy back. Tenant quota becomes the first policy in step 8.metadata::NamespaceTablemaps tenant ids to namespaces. A namespace is created atomically through the table's factory and never moves or goes away while the service runs, so a resolvedNamespace&needs no ownership, unlike the registry'sshared_ptr<Tenant>. The default namespace, the only one when multi-tenancy is off, resolves through an atomic without the map lock.The table's get-or-create and walk come from the tenant registry of #4215 by @CAICAIIs.
Not in this PR: the
eviction::Evictorthat merges the namespaces' cursors (step 7), the tenant quota policy (step 8), and anything inMasterService(step 15). The reference design had aNamespaceTable::Clear()for the old snapshot reload; #4406 removed that path, so it is left out.Behavior is unchanged: no RPC, snapshot or OpLog format changes, and no code path in
MasterServicereaches the new layer.Module
mooncake-store)Type of Change
How Has This Been Tested?
Test commands:
make -j12 metadata_namespace_test metadata_namespace_table_test eviction_index_test object_route_test group_index_test master_service_test ctest -R '^(metadata_namespace_test|metadata_namespace_table_test|eviction_index_test|object_route_test|group_index_test|master_service_test)$'Test results:
Unit tests pass
Integration tests pass (if applicable)
Manual testing done (describe below)
Tests:
metadata_namespace_test(12 cases),metadata_namespace_table_test(7),eviction_index_test(6),object_route_test(36),group_index_test(7) andmaster_service_testpass with GCC 16 (Release, assertions on).metadata_namespace_testcovers the in-flight list (listing on release, replacement, teardown, destruction with listed keys, concurrent writers sharing stripes) and the policy calls with their context and policy words; its concurrency case passes 200 repeated runs.metadata_namespace_table_testcovers racing creation for the default and a named namespace, walks that create namespaces, and lookups during creation.They replace
metadata_tenant_testandmetadata_tenant_registry_test, removed with the headers they tested.GCC 11.4 (Ubuntu 22.04, the CI floor): every changed translation unit passes
-fsyntax-only.Formatting:
./scripts/code_format.sh --check --changed-lines --base origin/mainis clean with clang-format 20.1.8.pre-commit on the changed files: the format and codespell hooks pass;
cmake-formatrewrites only pre-existing lines ofmooncake-store/tests/CMakeLists.txtoutside this change, which are left out.Checklist
./scripts/code_format.shcmake-formatfails on pre-existing lines ofmooncake-store/tests/CMakeLists.txt; see above)AI Assistance Disclosure
AI assistance was used to port the namespace layer and its tests and to draft this description. The submitter has reviewed every changed line and can defend the change end to end.