Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
af2ce95
[TENT] Add native UB endpoint bootstrap and READ/WRITE data path
Le1zyCatt Jul 28, 2026
4446194
[TENT] Prefer UB bonding devices when device_filter is empty
Connor-Matthew Aug 20, 2026
6f4e2fc
[TENT] Port UB bonding runtime patches into urma_adapter
Connor-Matthew Aug 21, 2026
fb5b25a
[TENT] Unify UB bonding detection and harden segment teardown
Connor-Matthew Aug 21, 2026
698aab3
[TENT] Fix clang-format for UB transport files
Connor-Matthew Aug 31, 2026
3066465
[CI/Build] Ignore gflags exit code in UB tebench smoke test
Connor-Matthew Aug 31, 2026
39c9198
Merge branch 'ub/bonding-device-selection' into ub/bonding-upstream
Connor-Matthew Aug 31, 2026
9c06073
[CI/Build] Restore UB tebench smoke step after main sync
Connor-Matthew Aug 31, 2026
4251eac
[TransferEngine] Add per-target tebench metrics (#3779)
jacklin78911-collab Aug 31, 2026
88230cb
[CI] Stop run-e2e-ci from retriggering Build & Test (#3756)
staryxchen Aug 31, 2026
6e1dd41
[Store] Introduce stateful region resource drivers (#3703)
Aionw Aug 31, 2026
73471dc
[CI/Build] Keep non-CUDA wheels CUDA-free (#3745)
Aionw Aug 31, 2026
964b8cf
Fix data copy while not on same device (#3476)
XiaokunDing Sep 1, 2026
27e0020
[TENT]: Map MOONCAKE_LOCAL_HOSTNAME to TENT rpc_server_hostname (#3790)
Colors-111 Sep 1, 2026
40aefcc
[TENT] Prefer the LAG-effective port speed from ibv_query_port_speed …
SongOf Sep 1, 2026
82a90a9
[Store] Add batch OpLog snapshot coordinator (#3794)
Icedcoco Sep 1, 2026
a14168c
[Store] Structure ClientAutoPortConfig environment settings (#3785)
bitborne Sep 1, 2026
4956149
[Store] Remove redundant per-file deletion delay (#3758)
zupengwang Sep 1, 2026
3fc731a
[Bugfix][Store] Allow explicit host identity for local-first allocati…
zupengwang Sep 1, 2026
c5f1023
[TE] Increase kDefaultQueuedTransfersPerPeer and kDefaultPendingAdmis…
alogfans Sep 1, 2026
f8b78a1
[CI] Keep Ascend mirror retry on actions/checkout (#3802)
staryxchen Sep 1, 2026
1377172
[Bugfix][TransferEngine] Serialize RDMA endpoint lifecycle by peer ow…
alogfans Sep 1, 2026
0f66684
feat: Add strict_local_numa to hard-exclude cross-NUMA RDMA rails (#3…
XiaokunDing Sep 1, 2026
6bfdb18
[Bugfix][TENT] Preserve ownership after failed memory free (#3582)
982945902 Sep 1, 2026
8b8ec70
[Store] Fix snapshot test eviction race (#3813)
Icedcoco Sep 1, 2026
91f8f89
[TENT][UB] Address PR #3796 review: reclaim provider-lost inflight to…
Connor-Matthew Sep 1, 2026
9fc660e
[TENT][UB] Fix clang-format in ub_native_data_path_test
Connor-Matthew Sep 1, 2026
511245f
[Bugfix][TENT] Drain the async event queue and recover contexts whose…
TTThanos Sep 2, 2026
dfe977f
[Store] Structure DistributedStorageConfig environment settings (#3763)
bitborne Sep 2, 2026
0d3ef5e
[Store] Structure ClientMetricConfig environment settings (#3773)
bitborne Sep 2, 2026
1d760de
[Store] Structure LocalHotCacheConfig environment settings (#3781)
bitborne Sep 2, 2026
ebe3864
[Store] Structure RegisteredPinnedMemoryConfig environment settings (…
bitborne Sep 2, 2026
5f37e14
[Bugfix][TENT] Register notify recv slots with one MR per endpoint (#…
staryxchen Sep 2, 2026
889c9c6
[TENT][UB] Cap slices per task and harden endpoint cleanup against in…
Connor-Matthew Sep 2, 2026
f04927f
[CI/Build] Restore RISC-V support without README badge (#3816)
stmatengss Sep 2, 2026
128ba6c
[Bugfix][TENT] Stop tebench workers from aborting on peer death (#3768)
staryxchen Sep 2, 2026
5c0cef2
[Store] Support 512MB hugepage size for client buffer allocation (#3789)
Kevin-XiongC Sep 2, 2026
1ce7ba6
[Bugfix][TENT] TENT store warmup failure on multi-NUMA RDMA hosts (#3…
Colors-111 Sep 2, 2026
2024669
[TENT][Draft] Add correctness-first high-performance TCP foundation (…
jacklin78911-collab Sep 2, 2026
e54826c
Merge branch 'main' of https://github.com/kvcache-ai/Mooncake into ub…
Connor-Matthew Sep 2, 2026
f21bf22
[TENT][UB] Fix clang-format in tent_backend
Connor-Matthew Sep 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions .github/workflows/_build-wheel.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ jobs:
VERSION: ${{ env.VERSION }}

- name: Smoke test repaired wheel
shell: bash
run: |
smoke_venv=$(mktemp -d)
python -m venv "$smoke_venv"
Expand All @@ -223,11 +224,20 @@ jobs:
if [ "${VARIANT_FLAG:-}" = "NON_CUDA_BUILD" ]; then
site_packages=$("$smoke_venv/bin/python" -c \
'import sysconfig; print(sysconfig.get_paths()["purelib"])')
master="$site_packages/mooncake/mooncake_master"
if readelf -d "$master" | grep -Eq \
'Shared library: \[(libcuda|libcudart)\.so'; then
echo "Non-CUDA mooncake_master depends on CUDA"
readelf -d "$master" | grep 'Shared library:'
cuda_dependency_found=false
for package_path in "$site_packages"/mooncake*; do
[ -e "$package_path" ] || continue
while IFS= read -r -d '' file; do
cuda_dependencies=$(readelf -d "$file" 2>/dev/null | grep -E \
'Shared library: \[(libcuda|libcudart|libcublas|libcufft|libcurand|libcusolver|libcusparse|libcufile|libcupti|libnvrtc|libnvJitLink|libnvToolsExt|libnvfatbin|libnvidia|libnccl)\.so' || true)
if [ -n "$cuda_dependencies" ]; then
echo "::error file=$file::Non-CUDA wheel artifact depends on CUDA"
echo "$cuda_dependencies"
cuda_dependency_found=true
fi
done < <(find "$package_path" -type f -print0)
done
if [ "$cuda_dependency_found" = true ]; then
exit 1
fi
fi
Expand Down
53 changes: 53 additions & 0 deletions .github/workflows/ci-on-label.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Retrigger CI on run-ci label

# Same-SHA retrigger for Build & Test. This is a separate workflow so labels
# other than `run-ci` (especially `run-e2e-ci`) cannot start or cancel
# `.github/workflows/ci.yml`.
#
# pull_request_target is required so fork PRs can rerun Actions. This
# workflow only calls the GitHub API; it does not check out PR code.
on:
pull_request_target:
branches:
- "main"
- "release/**"
types: [labeled]

permissions:
actions: write
contents: read

jobs:
retrigger:
if: >
github.event.label.name == 'run-ci' &&
github.actor != 'github-actions[bot]'
runs-on: ubuntu-latest
steps:
- name: Re-run Build & Test for this SHA
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
SHA: ${{ github.event.pull_request.head.sha }}
shell: bash
run: |
set -euo pipefail

run_json=$(gh api \
"repos/${REPO}/actions/workflows/ci.yml/runs?head_sha=${SHA}&per_page=20")
run_id=$(echo "$run_json" | jq -r '.workflow_runs[0].id // empty')
status=$(echo "$run_json" | jq -r '.workflow_runs[0].status // empty')

if [ -z "$run_id" ]; then
echo "No Build & Test run found for SHA ${SHA}."
echo "Open or push to the PR first so ci.yml has a run to rerun."
exit 1
fi

echo "Matched workflow run ${run_id} (status=${status})"
if [ "$status" != "completed" ]; then
echo "Build & Test is still ${status}; not starting a duplicate."
exit 0
fi

gh run rerun "$run_id" --repo "$REPO"
17 changes: 16 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ on:
branches:
- "main"
- "release/**"
types: [opened, synchronize, reopened, labeled]
# `labeled` is intentionally omitted. Auto-labeler already applies
# `run-ci`, so any new label (including `run-e2e-ci`) would retrigger
# this whole workflow and cancel the in-progress run. Same-SHA
# retrigger via the `run-ci` label lives in ci-on-label.yml.
types: [opened, synchronize, reopened]
workflow_dispatch: {}

permissions:
Expand Down Expand Up @@ -945,6 +949,17 @@ jobs:
run: ./scripts/ci/run_transfer_engine_rust_smoke.sh
shell: bash

- name: Smoke test TENT UB benchmark CLI
if: matrix.name == 'ub-mock'
run: |
cd build-tent
help_output="$(./mooncake-transfer-engine/benchmark/tebench \
--backend=tent --xport_type=ub --tent_transport_hint=ub \
--help 2>&1 || true)"
grep -q 'iouring|ub|sunrise_link' <<< "${help_output}"
grep -q 'ascend|ub|sunrise_link' <<< "${help_output}"
shell: bash

- name: Run sccache stat for check
if: ${{ env.SCCACHE_PATH != '' }}
shell: bash
Expand Down
37 changes: 16 additions & 21 deletions .github/workflows/ci_ascend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,13 @@ jobs:
fetch-depth: 1
persist-credentials: false

- name: Retry checkout via GitHub mirror
# Mirror is only a git transport fallback. Keep retry on actions/checkout so
# pull_request_target fork checks still run; do not fetch with raw git.
- name: Configure GitHub mirror rewrite
if: steps.checkout_code.outcome == 'failure'
shell: bash
env:
ASCEND_GITHUB_MIRROR_URLS: 'https://ghfast.top/'
CHECKOUT_REF: ${{ inputs.checkout_ref || github.sha }}
run: |
set -euo pipefail

Expand Down Expand Up @@ -83,27 +84,21 @@ jobs:

workdir="${GITHUB_WORKSPACE}"
git config --global --add safe.directory "$workdir"
find "$workdir" -mindepth 1 -maxdepth 1 -exec rm -rf {} +

for base in "${candidates[@]}"; do
mirror_url="${base}https://github.com/${GITHUB_REPOSITORY}.git"
echo "Retrying checkout with ${mirror_url}"

find "$workdir" -mindepth 1 -maxdepth 1 -exec rm -rf {} +
git init "$workdir"
git -C "$workdir" remote add origin "$mirror_url"

if git -C "$workdir" fetch --depth=1 origin "$CHECKOUT_REF" && \
git -C "$workdir" checkout --force --detach FETCH_HEAD; then
echo "Mirror checkout succeeded via ${base}"
exit 0
fi

echo "Mirror checkout failed via ${base}"
rm -rf "$workdir/.git"
done
# insteadOf only rewrites github.com fetches; checkout still runs
# assertSafePrCheckout before any git network I/O.
mirror_base="${candidates[0]}"
echo "Rewriting https://github.com/ to ${mirror_base}https://github.com/"
git config --global url."${mirror_base}https://github.com/".insteadOf "https://github.com/"

echo "Direct GitHub checkout failed and all mirror retries failed"
exit 1
- name: Retry checkout via GitHub mirror
if: steps.checkout_code.outcome == 'failure'
uses: actions/checkout@v4
with:
ref: ${{ inputs.checkout_ref || github.sha }}
fetch-depth: 1
persist-credentials: false

- name: Configure CMake
shell: bash
Expand Down
2 changes: 1 addition & 1 deletion docs/source/api-reference/cpp/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
|--------|-------------|
| [Transfer Engine C++ API](transfer-engine) | `TransferEngine` class — memory registration, batch transfer, segment management, RDMA transport |
| [TENT C++ API](tent) | `mooncake::tent::TransferEngine` — next-gen transfer engine with automatic transport selection and fault tolerance |
| [Mooncake Store Client C++ API](mooncake-store) | `Client` class — `Put`/`Get`/`Remove`/`Replicate` operations, `BufferAllocatorBase` interface |
| [Mooncake Store Client C++ API](mooncake-store) | `Client` class — `Put`/`Get`/`Remove`/`Replicate` operations |

:::{toctree}
:maxdepth: 1
Expand Down
20 changes: 18 additions & 2 deletions docs/source/deployment/mooncake-store-deployment-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -929,7 +929,23 @@ allocation_strategy: "local_first"

When enabled, the master applies local-first allocation only for memory replicas with `replica_num == 1`. Explicit `preferred_segment` or `preferred_segments` are tried first; if they are unavailable or full, Mooncake falls back through active hosts in cyclic lexicographic host-id order, starting from the writer host when it has active segments, or otherwise from the next greater active host id. Within the same host, segment names are sorted and rotated by key hash so multiple segments on one host do not always receive the first allocation attempt.

The client derives the host id from `local_hostname` by removing the port. For example, `host-a:50051` and `host-a:50052` map to the same host id, `host-a`. For local-first allocation to work correctly, all writer and store processes on the same physical or logical host must use the same stable, globally unique host part in `local_hostname`. In deployments with multiple NIC IPs, hostname aliases, or container/pod networking, choose one canonical host name or IP and use it consistently across processes on that host. Empty, loopback, and wildcard values such as `localhost`, `127.0.0.1`, `0.0.0.0`, `::1`, and `::` are treated as unknown and do not trigger automatic local-first placement for that client.
By default, the client derives the host id from `local_hostname` by removing the port. For example, `host-a:50051` and `host-a:50052` map to the same host id, `host-a`. Set `MOONCAKE_HOST_ID` to override this derived value with a stable, globally unique node identifier. The override is read directly by the C++ client, so it applies to every client initialization method. It must be set before creating the client, and all writer and store processes on the same physical or logical host must use the same value. An empty or whitespace-only override falls back to `local_hostname`. Loopback and wildcard values such as `localhost`, `127.0.0.1`, `0.0.0.0`, `::1`, and `::` are treated as unknown and do not trigger automatic local-first placement.

In Kubernetes, keep `MOONCAKE_LOCAL_HOSTNAME` as the routable pod IP for the transfer endpoint and use `spec.nodeName` as the shared placement identity:

```yaml
env:
- name: MOONCAKE_LOCAL_HOSTNAME
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: MOONCAKE_HOST_ID
valueFrom:
fieldRef:
fieldPath: spec.nodeName
```

Apply the same `MOONCAKE_HOST_ID` mapping to every writer and store pod. This separates the per-pod network address from the node-level placement identity, allowing colocated pods with different IPs to match for local-first allocation.

---

Expand Down Expand Up @@ -1186,7 +1202,7 @@ Do not run binaries from before and after checksum support was introduced in the
| Variable | Default | Description |
|----------|---------|-------------|
| `MC_STORE_USE_HUGEPAGE` | unset | Set `1` to request HugeTLB-backed `mmap()` |
| `MC_STORE_HUGEPAGE_SIZE` | `2MB` | Supported: `2MB`, `1GB` |
| `MC_STORE_HUGEPAGE_SIZE` | `2MB` | Supported: `2MB`, `512MB`, `1GB` |
| `MC_MMAP_ARENA_POOL_SIZE` | unset | Pre-allocated arena pool size (e.g., `8gb`). Explicitly set to enable the arena |
| `MC_DISABLE_MMAP_ARENA` | unset | Disable arena, fall back to per-call `mmap()`. Accepts `1`/`true`/`yes`/`on` (or `0`/`false`/`no`/`off`) |

Expand Down
6 changes: 4 additions & 2 deletions docs/source/design/store/mooncake-store.md
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ Valid values are: `random` (default), `free_ratio_first`, `ssd_free_ratio_first`
| `free_ratio_first` | Balanced utilization, dynamic scaling | Slightly lower throughput due to sampling and sorting overhead |
| `ssd_free_ratio_first` | SSD-aware memory allocation when SSD offloading is enabled | Depends on SSD usage metrics; falls back to random allocation when needed |
| `cxl` | CXL memory hardware | CXL-specific; single-replica only |
| `local_first` | Colocated inference workers and memory store segments | Requires stable host identity in `local_hostname`; single memory replica only |
| `local_first` | Colocated inference workers and memory store segments | Requires stable host identity from `MOONCAKE_HOST_ID` or `local_hostname`; single memory replica only |

**Use `random`** (default) when your cluster is relatively stable (segments rarely join or leave) and you want the highest possible allocation throughput.

Expand All @@ -566,7 +566,7 @@ Valid values are: `random` (default), `free_ratio_first`, `ssd_free_ratio_first`

**Use `cxl`** only when your hardware includes CXL (Compute Express Link) memory devices and you want to allocate data exclusively on CXL segments.

**Use `local_first`** when inference workers and Mooncake Store memory segments are colocated and you want writes to prefer the writer's host before falling back to other hosts. For this strategy to work correctly, all writer and store processes on the same physical or logical host must use the same stable, globally unique host part in `local_hostname`.
**Use `local_first`** when inference workers and Mooncake Store memory segments are colocated and you want writes to prefer the writer's host before falling back to other hosts. For this strategy to work correctly, all writer and store processes on the same physical or logical host must use the same stable, globally unique `MOONCAKE_HOST_ID`. When the variable is unset or empty, Mooncake derives the host identity from `local_hostname` by removing the port.

For benchmark data comparing `random` and `free_ratio_first` across segment counts, replica counts, and skewed capacities, see [AllocationStrategy Performance](../../performance/mooncake/allocation-strategy-benchmark-result.md).

Expand Down Expand Up @@ -605,6 +605,8 @@ An SSD-aware variant of the free-ratio-first strategy. It first tries preferred

Host-aware local-first allocation reuses the normal preferred-segment flow. The master derives the writer host id from the request's client host identity and builds an ordered preferred segment list: active hosts are visited in cyclic lexicographic host-id order, starting from the writer host when it has active segments, or otherwise from the next greater active host id. Within the same host, segment names are sorted and rotated by key hash so multiple local segments do not always receive the first allocation attempt.

The C++ client reads `MOONCAKE_HOST_ID` as an explicit deployment override for the client identity carried in allocation requests and the identity recorded for mounted segments. This lets containerized deployments keep `local_hostname` as a routable per-pod transfer endpoint while using a shared node-level placement identity. Loopback and wildcard overrides are rejected; an empty override preserves the derived-hostname behavior.

This strategy currently applies to memory allocation with `replica_num == 1`. Explicit `preferred_segment` or `preferred_segments` in `ReplicateConfig` are still tried first; if they are unavailable or full, allocation continues with the local-first ordered fallback list.

**`cxl` — CxlAllocationStrategy**
Expand Down
95 changes: 95 additions & 0 deletions docs/source/design/tent/hp-tcp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# TENT High-Performance TCP

`hp_tcp` is a standalone TENT transport for CPU DRAM transfers over
data-center TCP. Standard `tcp` remains the RPC-based compatibility path.
The first version intentionally excludes GPU memory, TLS, multi-endpoint
routing, multi-NIC striping, transparent replay after an ambiguous WRITE and
dynamic lane scheduling.

## Architecture

Each worker owns one `asio::io_context` and one thread. Each peer has a
configured number of persistent lanes, and request IDs distribute operations
across them. A stable hash of peer and lane selects the owner; socket state
never moves between workers, and operations on a lane are FIFO. ASIO provides
the event queue; process-wide task and byte admission limits bound all accepted
work, including callbacks waiting in that queue.

The server uses the same worker pool. Accepted sockets are assigned to workers
and stored in worker-owned session sets. A global connection limit bounds live
sessions; closing a session removes it immediately rather than retaining one
thread per historical connection.

```text
TENT request -> bounded admission -> owner worker -> persistent lane
-> versioned TCP protocol -> registered remote buffer
```

## Protocol and memory safety

Requests contain a version, opcode, request ID, registration ID, remote
address and length. Responses contain the request ID, status and committed
byte count. A WRITE completes only after the target has copied the full payload
and returned an acknowledgement. A READ completes after the full response
payload arrives.

Every registered buffer has an ID formed from a per-registry random namespace
and a monotonic sequence, plus a remote permission. This prevents a stale ID
from a previous server incarnation from becoming valid after restart. The
target validates the ID, range and permission before access. An operation holds
a lease until its final I/O callback retires; unregister hides the range from
new work and waits for existing leases. Stale registration metadata causes one
bounded metadata refresh and retry on the same transport. Permission and range
failures are terminal.

If a WRITE request may have reached the peer but no valid acknowledgement is
received, the remote outcome is unknown. That failure is terminal and is not
replayed through another transport; otherwise a committed WRITE whose ACK was
lost could execute twice.

## Timeouts and shutdown

Resolve/connect use `connect_timeout_ms`. Header, payload and response progress
use `progress_timeout_ms` on both client and server. A newly accepted connection
must send its first header byte before the deadline, and every partial header
or payload must continue to make progress. After a valid request completes,
pure idle time on its persistent connection is not treated as stalled I/O; the
deadline resumes as soon as the next header begins. A timeout cancels the
resolver or socket; terminal completion is published only after the
corresponding callback retires.

Shutdown closes admission and the listener, drains queued dispatch callbacks,
cancels every client lane and server session on its owner, waits for operations
and leases, then stops and joins worker threads. This makes shutdown bounded
even when a peer sends only part of a request.

This ordering is a lifecycle invariant, not an incidental destructor detail:
the client and server are destroyed before the worker contexts they use. In a
debug build, normal teardown asserts that admission, client operations and
server sessions have all drained before their owners are destroyed.

An exception escaping an ASIO handler marks the runtime failed and blocks
further admission. The owner event loop continues only to retire previously
committed work and process teardown cancellation with the same affinity. Once
those resources drain, shutdown joins the workers and reports the failure.
Likewise, admission-release underflow is fail-closed: counters are preserved,
new work is rejected, and drain returns an error instead of treating live work
as complete.

## Configuration

The transport is configured under `transports.hp_tcp`:

| Field | Meaning |
| --- | --- |
| `enable` | Enable `hp_tcp`; set `transports.tcp.enable` to `false`. The two transports cannot be enabled together because control-plane notification ownership is singular. |
| `bind_address`, `advertise_address`, `port` | Listener and published endpoint. |
| `worker_count` | ASIO event-loop threads. |
| `connections_per_peer` | Persistent lanes per peer. |
| `max_outstanding_tasks`, `max_outstanding_bytes` | Global admission bounds. |
| `max_transfer_bytes` | Maximum request size. I/O progress is tracked in fixed internal steps. |
| `connect_timeout_ms`, `progress_timeout_ms` | Connection and I/O deadlines. |

Tests cover wire validation, admission, buffer leases, connection reuse,
session reaping, client/server timeout, stale-registration recovery, ambiguous
WRITE completion and a two-process READ/WRITE smoke test.
8 changes: 8 additions & 0 deletions docs/source/design/tent/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,14 @@ metrics
transport-selector
:::

## TENT High-Performance TCP

:::{toctree}
:maxdepth: 1

hp-tcp
:::

## TENT Quality of Service

:::{toctree}
Expand Down
Loading
Loading