본문으로 건너뛰기

iouring-batch put_many — 최종 정제 (vs batch-io 비교 + PR 결정)

한 줄 요약: _put_many_batch_io(io_uring+N>1 → 2N 엔트리 단일 batched_write)는 batch-io 와 동일한 core 아이디어. 본 브랜치는 그 core 만 분리해 (1) Phase B 롤백 보완, (2) 부분 슬롯 소진 테스트 추가, (3) 실디바이스/벤치 파일 제거로 PR 을 좁힌 버전. plugin 개선(exists_many dedup 등)은 dev 독립 후속 PR 로 분리.


1. 두 브랜치 비교 (같은 목적, 다른 형태)

항목iouring-batch (1fe16ba, 6/11)batch-io (aad5e37, 6/8 = P0 문서)
core 진입 분기io_uring && len>1 → _put_many_batch_io동일
Phase A 슬롯 예약lock 1회, index/inflight 체크 후 allocate동일
rollback 구조write_succeeded 플래그 + 단일 commit 루프commit 루프 + except 별도 rollback 루프 (중복)
try 범위보완 전: _write_buffers만 / 보완 후: Phase B 까지Phase B+C+D 전체
zip(strict=)strict=Truestrict=False
header payload_len항상 hdr_totalhdr_total if io_uring else len(header) (이 경로는 항상 io_uring → 죽은 분기)
plugin 변경없음 (base PR#3274 가 이미 io_uring+N>1 → 단일 put_many funnel)batched_submit_put_task 대수술 (+67/-28)
테스트fake io_uring device 6종 + 실디바이스 통합/벤치posix core 3종 (io_uring 계약 미검증)

결론: batch-io 의 plugin 변경은 io_uring 배칭과 직교(plugin 단 dedup·lock·refcount). 즉 batch-io = iouring-batch(core) + plugin 리팩토링. "작고 집중된 PR" 관점에서 iouring-batch 를 PR 베이스로 채택, plugin 은 분리.


2. 본 브랜치 PR 결정 사항 (2026-06-11 보완)

2.1 Phase B 롤백 보완 — narrow try 확장 + 단일 루프

문제: 1fe16ba 의 try_write_buffers 만 감쌌다. Phase B(_encode_header / _prepare_write_payload)가 예외를 던지면 Phase A 에서 채운 self._inflight 엔트리와 할당 슬롯이 롤백 없이 누수된다.

방식 비교 → 채택: batch-io 의 broad-try 는 안전하지만 rollback 루프가 commit/except 두 곳에 중복. 본 브랜치는 write_succeeded 플래그 + 단일 Phase D 루프 구조를 유지한 채 try 범위만 Phase B 까지 확장 → batch-io 의 안전성을 얻으면서 중복 없음. 두 원본보다 우수. _inflight_io_count 증감은 실제 write 에만 묶인 inner try/finally 로 유지(Phase B 가 inc 이전에 던지면 inner 블록 미실행 → 과다 감소 없음).

2.2 부분 슬롯 소진 테스트 추가

docstring 이 약속한 "keys with no free slot fail individually, 나머지는 성공" 시맨틱이 1fe16ba 에 미검증이었다. test_raw_block_core_io_uring_put_many_partial_slot_exhaustion 추가: capacity 를 meta(1MB)+3*slot(64KB) 로 줘 슬롯 3개만 두고 5키 put_many → 결과 [T,T,T,F,F], stored_keys 는 앞 3개, batched_write 1회·2*3=6 엔트리, indexed_key_count==3, 가용 슬롯 0, 커밋분 round-trip 로드 성공. 헬퍼 _make_core_with_fakecapacity_bytes override 추가.

2.3 실디바이스 통합/벤치 파일 제거

test_raw_block_put_many_integration.py어떤 CI 에서도 실행되지 않음:

  • 전용 raw-block job(.github/workflows/test.yml:167-172)은 device/core/l2_adapter 3개만 명시
  • 일반 job 은 rust 확장 미빌드 → importorskip 모듈째 skip

fake-device 6종이 이미 계약을 CI(전용 job 의 test_raw_block_core.py)에서 검증하므로 PR 에서 제거. 파일은 로컬 보관: private/work/raw_block/local_real_device_put_many_bench.py. 실디바이스 검증은 LMCACHE_RAWBLOCK_TEST_DEVICE 지정해 로컬 수동 실행.


3. 검증 결과 (테스트 클론 /home/ny/LMCache venv, ws 소스)

  • pytest tests/v1/storage_backend/test_raw_block_core.py11 passed (기존 6 + 신규 partial_slot_exhaustion + 기타). all_or_nothing_rollback 통과로 Phase B 구조 변경이 write-failure 롤백을 깨지 않음 회귀 확인.
  • pre-commit run --files core.py test_raw_block_core.py → 전 항목 Passed (ruff-format 가 test 파일 1회 재포맷 후 재실행 통과).

4. 미해결 / 후속

  • PR 타깃: ✅ 해소·제출 완료 — PR #3274 가 upstream/dev 에 머지된 뒤, 세 브랜치를 git rebase --onto upstream/dev 로 replay. 6/11 시점 upstream/dev HEAD 는 45c02cbe 까지 진전(7021790 이후 추가 머지). 세 브랜치 모두 origin(nayeonikim 포크)에 push 완료: iouring-batch 3b8260a0 / plugin-dedup 1cc5a74d / validate-batched-read dc3f5d36. range-diff 내용 무변, 재검증 통과(11/31/11 passed, pre-commit 전 항목).
  • plugin 개선 후속 PR — ✅ 구현 완료·push 완료, PR 미생성 (브랜치 perf/rawblock-put-many-plugin-dedup, origin 1cc5a74d). 이제 base 는 upstream/dev (45c02cbe) — #3274 머지로 _submit_put_many 가 dev 에 들어와 dev base 가능해짐. batched_submit_put_taskexists_many 배치 dedup + 단일 _put_lock 윈도우 + dispatch 실패 try/except 롤백(ref/_put_tasks) + 빈 keys 조기 None. TDD: fake io_uring backend 테스트 2종(empty-keys, dispatch 실패 ref 롤백) red→green, plugin 전체 31 passed. iouring-batch core 와 직교(병렬 리뷰).
  • validate-batched-read 후속 PR — ✅ 구현 완료·push 완료, PR 미생성 (브랜치 perf/validate-batched-read, origin dc3f5d36). core _validate_loaded_entries 를 io_uring batched_read 로 배치화. 상세는 [[V1-validate-batched-read]].
  • 실측 미검증: batch vs sequential 실디바이스 wall-clock 은 로컬 벤치 스크립트로만.