MP mode 통합 gap: ankit#1 (in-process) → MP adapter 이식 시 막히는 지점
목표: daegyu의 ankit#1이 dev에 머지된 후, 그 base를 우리의 지향점인 MP mode에서 동작시키려면 무엇이 추가/변경되어야 하는가.
주의: 이 문서의 일부 진술은 Plan 작성 시점 코드 읽기 기반 추론이다. 실제 PoC 통합 시점에 검증되어야 한다 —
items.md의 §검증 필요 항목 참조.
1. 한눈에 보기
| 측면 | ankit#1 (in-process plugin) | MP adapter | gap |
|---|---|---|---|
| 진입 | RustRawBlockBackend (plugin) | RawBlockL2Adapter | 다른 클래스, 다른 config 인터페이스 |
| Device 모델 | rank마다 다른 device (per_tp_device_paths) | 단일 device 공유 + per-key 격리 | ankit#1 정책이 그대로는 못 들어감 |
| TP rank 식별 | self.metadata.worker_id | ObjectKey.kv_rank 비트 패킹 | rank 정보 전달 경로 다름 |
| Config 인터페이스 | extra["rust_raw_block.*"] (dict) | RawBlockL2AdapterConfig (dataclass-like) + JSON | ankit#1의 5개 키 별도 매핑 필요 |
| FDP 정책 적용 위치 | plugin __init__ | adapter __init__ → RawBlockCore | core 시그니처 확장 또는 caller stamp |
2. 결정적 충돌: per_tp_device_paths 명시적 거부
MP adapter는 per_tp_device_paths를 명시적으로 reject한다.
# lmcache/v1/distributed/l2_adapters/raw_block_l2_adapter.py:154-157
if "per_tp_device_paths" in d:
raise ValueError(
"per_tp_device_paths is not supported in MP raw_block mode"
)
→ ankit#1의 multi-TP FDP 경로(예제에서 --per_tp_device_paths /dev/ng0n1 /dev/ng0n2로 노출)는
MP에서 JSON 단계에서 ValueError. 즉:
- ankit#1의 rank-based 정책은 "rank → 다른 device" 가정인데
- MP는 "단일 device 공유, 모든 rank가 같은 device" 가정.
해석: 같은 단어 "rank isolation"이라도 두 모드에서 의미가 다르다.
- in-process: device 자체를 분리 → physical isolation
- MP: 같은 device 안에서 RUH PID로 분리 → logical isolation (= FDP의 본 가치)
→ MP에서는 오히려 FDP placement_id가 isolation의 유일한 수단이라는 뜻이고, 이게 FDP 효과 입증의 자연스러운 setup.
3. MP에서 FDP placement_id가 들어갈 자리
3-1. Write 경로 (어디서 placement_id가 결정되어 NVMe까지 전달되는가)
탐색 결과 (에이전트 보고 정리):
ObjectKey → RawBlockL2Adapter._run_store_task() → encode_object_key → RawBlockKeySpec
→ RawBlockCore.put_many(specs, objects)
→ RawBlockCore._write_one()
→ RawBlockCore._write_buffers()
→ raw_dev.batched_write() / pwrite_from_buffer()
→ Rust nvme_uring_cmd_prep → cdw13/cdw12
FDP placement_id가 들어갈 후보 지점:
| 지점 | 장점 | 단점 |
|---|---|---|
(a) ObjectKey 또는 RawBlockKeySpec에 placement 메타 필드 추가 | caller(=L1/스케줄러)가 의도를 stamp, core는 그대로 forward | API 변경 표면 큼. 모든 caller가 결정 책임. |
(b) RawBlockCore.put_many() 시그니처에 placement_hints 파라미터 추가 | core 안에서 policy plug-in 가능, ObjectKey 무변경 | placement_hints를 생성하는 정책 객체가 별도 필요 |
(c) RawBlockCore가 ObjectKey를 보고 자체 결정 (current ankit#1 in-process 스타일) | caller 단순 | policy가 core에 박힘, core를 PoC harness가 우회 불가 |
dongdongju PoC는 사실상 (b)+(c) 혼합 (harness가 storage_class별 RUH list를 config로 내려주고,
core가 worker_index로 분배). 자세한 path는
01_branch_audit/placement_policy_notes.md.
ankit#1은 (c) 형태 (plugin이 init에서 결정 후 _data_placement_ids_cache로 캐시).
MP에서 권장: (b) 또는 (a) — caller가 의도를 보유한 채 core에 전달하는 형태가 정책 ②(cache_salt)/③(model)으로 확장 시 유연.
3-2. RUH status 자동 조회 (init 시점)
RawBlockL2AdapterConfig.from_dict() 단계에서 use_fdp=True를 받으면:
RawBlockCore초기화 후raw_dev.fetch_fdp_status()호출 가능 (ankit#1 #5의_configure_fdp_placements()그대로 재사용 가능).- 정책 객체에
(pid, ruhid)튜플 리스트 전달.
→ 이 부분은 MP adapter에 메서드 하나 추가하면 끝. 핵심 충돌 아님.
3-3. Metadata RUH 분리 (ankit#1의 lifetime isolation)
ankit#1: 체크포인트 metadata는 default RUH 사용 (FDP directive 안 붙임).
MP adapter도 RawBlockCore._save_meta_checkpoint() 경로는 동일 — core 수준에서 처리하면 변경 없음.
4. ankit#1 코드 중 MP에서 그대로 쓸 수 있는 부분 / 못 쓰는 부분
그대로 재사용 가능 (Rust side)
fetch_fdp_status()PyO3 (24ae8ab8+2be75bb5)batched_write/write_uring의placement_id파라미터 (8bb1f36a+2be75bb5)- NVMe directive 인코딩 (
cdw13 = (dspec) << 16,cdw12 |= dtype)
거의 그대로 (Python side, 메서드 이식)
_fetch_fdp_status()Python wrapper_get_data_placement_id()getter_build_data_placement_ids(num_requests)batched helper
재설계 필요
_configure_fdp_placements()— MP에서는metadata.worker_id대신 ObjectKey의 rank 정보(kv_rank>>16) 또는 caller hint 사용_assign_fdp_placement_rank_based()placeholder → 실제 정책 (rank/cache_salt/model) 결정per_tp_device_pathsvalidation 경로 — MP에서는 reject되므로 다른 검증 로직 필요 (single device + valid RUH count)
폐기 또는 새로 만들기
_resolve_max_data_transfer_size()(sysfs auto) — MP adapter에서도 필요하면 재구현 (FDP와는 독립 기능이지만 같은 PR에 묶여있음)
5. MP에서 FDP가 들어가는 표면 (제안)
RawBlockL2AdapterConfig에 추가될 키 (제안):
use_fdp: bool = False
# RUH 할당 정책: "single" | "rank_based" | "by_salt" | "by_model" | "manual"
fdp_policy: str = "single"
# manual mode일 때 데이터 RUH PID 리스트
fdp_data_ruh_ids: list[int] = []
# metadata RUH 분리 모드: "default_ruh" (ankit#1) | "explicit" | "per_ruh" (PoC)
fdp_metadata_mode: str = "default_ruh"
fdp_metadata_ruh_ids: list[int] = []
# NVMe directive type (default 0x2 = FDP)
fdp_directive_type: int = 0x2
→ 01_branch_audit/03_fdp_implementation_audit.md의 PR-A 단위와 정렬 가능.
6. 검증 필요 항목 (items.md로 이어짐)
이 문서의 추론 중 PoC 환경에서 확인이 필요한 것들:
- dongdongju PoC가 MP에서 실제로 어떻게 동작하는지 (사용자가 PoC 코드가 MP mode 기준으로 되어있을 거라고 진술 —
RawBlockCore가RawBlockL2Adapter를 통해 어떻게 사용되는지 직접 trace 필요). - ankit#1의
_data_placement_ids_cachereuse pattern이 MP의 ThreadPoolExecutor 기반 store 경로에서 thread-safe한가. - ObjectKey의
kv_rank비트 패킹(global_rank bits [16,23])이 MP에서 어떤 caller(L1 scheduler? worker?)에 의해 결정되는지. RawBlockCore.put_many시그니처 확장이 다른 caller(예: dax_backend)에 영향 주는지.