Review: 356270ae — Harden raw-block checkpoint entry recovery
- Commit:
356270aeea74be335d6d26108becb27cfb64e0b8 - Author: Daegyu Han daegyu94.han@samsung.com
- Date: 2026-05-28
- Files changed:
- lmcache/v1/storage_backend/raw_block/core.py (+66 / −41)
- tests/v1/storage_backend/test_raw_block_core.py (+73 / −0)
1. Summary
RawBlockCore._apply_loaded_state()는 디스크에 저장된 metadata 체크포인트를
복구해 self._index를 다시 채운다. 이전 구현에서는 한 entry 디코딩 도중
예외가 나면 (예: int("not-an-int"), torch.Size(list(non-iterable)) 등)
복구 루프 전체가 터져서 valid entry 까지 모두 손실되는 문제가 있었다.
본 커밋은:
- entry 디코딩 로직을 별도 헬퍼
_decode_checkpoint_entry()로 분리하고 _apply_loaded_state()의 entries 루프에서try/except로 감싸, malformed entry 한 건이 있어도 경고만 남기고 다음 entry 로 진행하도록 변경했다. 즉, "fail open" → "skip-and-continue" 정책으로 전환.- partial-recovery 동작을 검증하는 회귀 테스트를 추가했다.
2. 주요 변경 사항
2.1 새 헬퍼: _decode_checkpoint_entry()
- 단일 entry dict를 받아
_Entry(또는 invalid slot 인 경우None)을 반환. - 기존 로직을 그대로 옮긴 형태이며, 시그니처는
(encoded_key: str, entry: dict[str, Any]) -> _Entry | None. - docstring 에 Args/Returns/Raises 모두 기술되어 있음.
2.2 _apply_loaded_state() 의 entries 루프
for encoded_key, entry in entries.items():
if not isinstance(entry, dict):
continue
try:
decoded_entry = self._decode_checkpoint_entry(
str(encoded_key),
entry,
)
except Exception as e:
logger.warning(
"RawBlockCore skipping invalid checkpoint entry %r: %s",
encoded_key,
e,
)
continue
if decoded_entry is None:
continue
self._index[encoded_key] = decoded_entry
- 핵심은 try/except로 wrap한 것. 예외 발생 시 warning을 남기고 그 entry 만 스킵.
decoded_entry is None분기는 invalid offset/size 인 경우(이때는 예외가 아니라 None을 반환) 처리.
2.3 회귀 테스트
test_raw_block_core.py:128-198 — test_raw_block_core_apply_loaded_state_skips_invalid_entry:
- 1개의 valid entry + 2개의 malformed entry (
bad-offset-entry,bad-shape-entry)로 구성된 체크포인트 state를 만든다. apply_loaded_state()호출 후:- valid entry 는
contains_key()True 이고,load_many_into()로 원본 payload 복원되는지 확인. - malformed entries 는
contains_key()False.
- valid entry 는
- public API (
apply_loaded_state,contains_key,load_many_into)만 사용하므로, coding standards §6 (encapsulation) 위반 없음.
3. Coding standards 점검
| 항목 | 상태 | 비고 |
|---|---|---|
| SPDX 헤더 | Pass | 변경된 파일 모두 기존부터 헤더 있음 |
| 타입 힌트 | Pass | 새 헬퍼 시그니처 (str, dict[str, Any]) -> _Entry | None 명시 |
Any 사용 | Pass | dict value 타입은 외부 JSON 이라 Any 불가피, 적절 |
| docstring | Pass | 새 헬퍼에 Summary/Args/Returns/Raises 모두 기술 |
| 캡슐화 | Pass | 테스트가 public API만 사용 |
assert 미사용 | Pass | 검증은 모두 if/raise 또는 try/except |
| 회귀 테스트 | Pass | partial-recovery 시나리오 1건 추가 |
| PR scope | Pass | 단일 함수 리팩토링 + 동작 변경 + 테스트 1건. 작고 집중됨. |
4. 이슈
4.1 error 이슈
없음.
4.2 warning 이슈
W1. Raises: 문구가 모호함
Raises:
Exception: If the entry cannot be parsed into metadata.
- 어떤 예외가 발생하는지 불분명. 호출 측이
except Exception으로 광범위하게 잡고 있으니 동작상 문제는 없지만, 실제로 발생할 수 있는 예외 (ValueError,TypeError,KeyError) 를 나열해주면 docstring 정확도가 올라간다. - 또는 호출부에서 광범위 catch 하는 의도라면 "may raise any exception while parsing untrusted checkpoint data" 같이 의도를 명시하는 것이 낫다.
W2. 광범위 except Exception 의 의도 명시
except Exception은 의도적이지만 (untrusted 한 디스크 데이터 복구이므로), 코드 리뷰 관점에서 왜 넓게 잡는지 한 줄 주석 또는 docstring 보강이 있으면 좋다. 추후 누가 좁히려 할 위험을 줄임.
4.3 info 이슈
I1. malformed entry 통계 노출 고려
- 현재는 warning log 만 남기고 끝난다. 운영 환경에서 "체크포인트 복구 시 N건 손실" 이라는 사실이 metric/status 로 노출되면 디버깅에 도움이 될 듯.
- 예:
report_status()에"checkpoint_skipped_entries"카운터를 노출하거나,_apply_loaded_state()가 (성공 entry 수, 스킵 entry 수) 를 반환하도록 확장. - 이번 PR scope 를 벗어나므로 follow-up 으로 충분.
I2. 테스트의 bad-shape-entry offset 처리
"offset": valid_offset + config.slot_bytes,
- 이 offset 은
_is_valid_checkpoint_entry()를 통과하는 valid offset. shape 파싱에서 예외 발생을 확인하려는 의도이며 동작은 정확함. - 다만 테스트 의도가 한눈에 안 보이므로 한 줄 주석 ("valid slot이지만 shape 파싱 단계에서 TypeError 발생을 테스트") 가 있으면 명확.
I3. partial-recovery 후 next_slot/free_slots 정합성
- 테스트가 valid entry 가 살아남는 것까지는 검증하지만, 스킵된 entry 의 슬롯이
나중에 재할당 가능한지 (즉
free_slots가 일관 상태인지) 는 검증하지 않음. - 현재
_apply_loaded_state()마지막 부분 (core.py:1375-1381) 가used_slots를self._index로부터 다시 계산해 free list 를 정리하므로 논리적으로는 안전해 보인다. 다만 회귀 테스트가 없으니 follow-up 으로 valid entry put 후 새 key 를 put 했을 때 슬롯 충돌 없이 동작하는지 검증하면 좋다.
5. Caller impact
_apply_loaded_state()의 외부 노출 함수는apply_loaded_state()1곳.- 리턴값 시맨틱 ("payload shape/layout 매칭 + 모든 valid entry 적용 시 True; per-entry record 는 invalid 면 skip") 이 변경되었다.
- 호출자는 core.py:1491 한 곳:
if not self.apply_loaded_state(data):.- 이전: 한 entry라도 망가지면 예외 → 호출자가 잡을 수 있는지 별개. 사실상 복구 실패.
- 이후: malformed entry 는 무음 skip (warning log) → True 반환.
- 즉, "이전엔 망가졌던 케이스" 가 "이제는 부분 복구 성공" 으로 처리되며, 호출자는 동일 코드로 더 관대한 결과를 받는다. breaking change 아님, 안전함.
6. 결론
- 작고 잘 격리된 hardening PR. 헬퍼 분리 + try/except 도입 + 회귀 테스트.
- error 0건 / warning 2건 / info 3건. 머지 가능.
- warning 은 docstring 정확도/주석 보강 수준이라 follow-up 으로 처리해도 무방.
- info 는 운영성 metric 노출 (I1) 정도가 가장 가치 있어 보임.
7. Severity 요약
| Severity | Count | Key items |
|---|---|---|
| error | 0 | — |
| warning | 2 | W1: 모호한 Raises: 문구 / W2: 광범위 except Exception 의도 주석 |
| info | 3 | I1: skipped entry 통계 노출 / I2: 테스트 의도 주석 / I3: free_slots 정합성 회귀 테스트 |