본문으로 건너뛰기

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 adaptergap
진입RustRawBlockBackend (plugin)RawBlockL2Adapter다른 클래스, 다른 config 인터페이스
Device 모델rank마다 다른 device (per_tp_device_paths)단일 device 공유 + per-key 격리ankit#1 정책이 그대로는 못 들어감
TP rank 식별self.metadata.worker_idObjectKey.kv_rank 비트 패킹rank 정보 전달 경로 다름
Config 인터페이스extra["rust_raw_block.*"] (dict)RawBlockL2AdapterConfig (dataclass-like) + JSONankit#1의 5개 키 별도 매핑 필요
FDP 정책 적용 위치plugin __init__adapter __init__RawBlockCorecore 시그니처 확장 또는 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는 그대로 forwardAPI 변경 표면 큼. 모든 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를 받으면:

  1. RawBlockCore 초기화 후 raw_dev.fetch_fdp_status() 호출 가능 (ankit#1 #5의 _configure_fdp_placements() 그대로 재사용 가능).
  2. 정책 객체에 (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_uringplacement_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_paths validation 경로 — 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 환경에서 확인이 필요한 것들:

  1. dongdongju PoC가 MP에서 실제로 어떻게 동작하는지 (사용자가 PoC 코드가 MP mode 기준으로 되어있을 거라고 진술 — RawBlockCoreRawBlockL2Adapter를 통해 어떻게 사용되는지 직접 trace 필요).
  2. ankit#1의 _data_placement_ids_cache reuse pattern이 MP의 ThreadPoolExecutor 기반 store 경로에서 thread-safe한가.
  3. ObjectKey의 kv_rank 비트 패킹(global_rank bits [16,23])이 MP에서 어떤 caller(L1 scheduler? worker?)에 의해 결정되는지.
  4. RawBlockCore.put_many 시그니처 확장이 다른 caller(예: dax_backend)에 영향 주는지.