본문 바로가기
C.W.K.
Stream
Lesson 04 of 04 · published

스냅샷은 지우지 않고 쌓아

~11 min · snapshots, append-only, content-addressed, preservation

Level 0꺼진 심지
0 XP0/33 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"인덱스는 처음부터 다시 만들 수 있어. 스냅샷은 그럴 수 없으니, 완전히 다른 규칙으로 지켜야 해."

함부로 버릴 수 없는 저장소

인덱스는 파생 상태라서 의심스러우면 버리고 다시 만들면 돼. 하지만 captured 코퍼스의 변환된 텍스트를 담은 스냅샷 저장소에는 같은 규칙을 적용할 수 없어. 원본 PDF가 이미 사라졌는데 스냅샷까지 지우면 그 내용은 다시 만들 길이 없거든. 그래서 스냅샷은 재구축 대상이 아니라 보존 대상이야.

내용으로 주소를 만들고 덧붙이기만 해

변환된 텍스트의 sha256을 계산해 스냅샷의 id와 디스크 주소로 사용해. 내용이 같으면 해시도 같아서 한 번만 저장되고, 내용이 달라지면 새 주소가 생겨. captured 소스가 바뀌어도 예전 스냅샷을 덮어쓰지 않아. 새 텍스트를 새 해시 아래 덧붙이고, 옛 버전은 그대로 읽을 수 있게 남겨. 역사는 수정되는 대신 차곡차곡 쌓여.

삭제는 일부러 어렵게 만들어

코퍼스를 제거하거나 다시 색인하는 동작이 스냅샷까지 지워서는 안 돼. 삭제하려면 정확한 해시를 대상과 확인값으로 두 번 제시하는 별도 명령을 써야 해. 살아 있는 문서가 그 스냅샷을 참조하고 있다면 그마저도 충돌 오류로 거절하지. 다른 작업의 부수 효과나 대량 정리로 귀한 데이터가 사라질 길을 막은 거야.

대체할 수 있는 상태와 대체할 수 없는 상태에 같은 규칙을 쓰지 마. 파생 인덱스는 싸게 버리고 다시 만들 수 있어야 해. captured 원본인 스냅샷은 덧붙이기만 하고, 내용으로 주소를 만들며, 삭제는 명시적인 두 단계 확인을 거쳐야 해. 두 저장소가 같은 삭제 경로를 타면 언젠가 값싼 쪽의 부주의가 귀한 쪽을 지워.

변환 규칙도 과거를 설명할 수 있어야 해

스냅샷을 만든 변환기도 버전을 가져야 해. 태그 제거 규칙이나 필터 기준을 바꾸고 싶다면 기존 id의 동작을 고치는 대신 새 변환기 id를 발행해. 그래야 예전 스냅샷이 어떤 규칙으로 만들어졌는지 언제든 재현하고 설명할 수 있어. 스냅샷과 그 변환기 버전을 함께 남겨야 텍스트의 탄생 기록이 완성돼.

Code

덧붙이기 전용 스냅샷, 확인값을 요구하는 단일 삭제 경로·python
from pathlib import Path
import hashlib

class SnapshotStore:
    root = Path("~/lantern/snapshots").expanduser()

    def append(self, text: str) -> str:
        sha = hashlib.sha256(text.encode("utf-8")).hexdigest()
        path = self.root / sha[:2] / f"{sha}.md"      # addressed by content
        if not path.exists():                          # identical text: store once
            path.parent.mkdir(parents=True, exist_ok=True)
            path.write_text(text)                       # write-once, never mutate
        return sha

    def delete(self, sha: str, confirm: str) -> None:
        if confirm != sha:
            raise ValueError("arm the delete: pass the sha as confirmation")
        if live_documents_deriving_from(sha):
            raise Conflict("snapshot still cited by a live document")  # 409
        (self.root / sha[:2] / f"{sha}.md").unlink()    # the ONLY deletion path

Exercise

네 도구들이 뭘 어떻게 삭제하는지 봐. 한 가지를 삭제하거나 바꾸면 다른 게 조용히 삭제되거나 덮어써지는 곳 하나를 찾아(데이터를 데려가는 앱 삭제, 삭제를 미러링하는 동기화). 이제 그 연쇄 삭제가 다시 만들 수 없는 데이터까지 지운다고 상상해. 그걸 막았을 규칙을 설계해: 그 도구한테 '이 삭제는 명시적인 두 단계 확인을 거쳐야 해'라는 규칙은 그 도구에서 어떤 모습일까?
Hint
패턴은: 귀한 저장소를 분리하고, 유일한 삭제 경로가 정확한 해시를 두 번 입력하게 만들고, 뭔가 아직 의존하는 동안엔 삭제를 거부해. 삭제가 부작용이면, 사고는 이미 예고된 거야.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.