"반쯤 쓰인 파일이 진짜 파일 이름을 절대 못 입게 해. 증명될 때까지 분장을 시키고, 그다음 한 번에 진짜로 변신하게 해."
목적지에 곧장 쓰는 것의 문제
report.pdf 를 목적지 볼륨의 최종 경로에 직접 복사한다고 상상해. 절반쯤에서 볼륨이 떨어져. 이제 정확히 맞는 위치에 report.pdf 라는 파일이 있어 — 근데 잘린 쓰레기야. 디스크에서 아무것도 그걸 끝난 복사와 구별 안 해. 다음에 그걸 여는 사람, 다음에 그걸 동기화하는 도구가 시체를 믿어. 목적지 이름에 곧장 쓰는 게 부분 복사가 진짜 파일인 척하는 방식이야.
스테이징: 증명될 때까지 분장
Waygate 는 목적지 볼륨의 오퍼레이션-명명 스테이징 항목에 복사해 — 오퍼레이션 id 에 묶인 임시 이름, 명백히 최종 파일이 아닌. 복사 중 플랜이 요구하는 걸 보존해: 지원되는 메타데이터, 리소스 포크, ACL, 확장 속성, 타임스탬프. 그다음 스테이징된 결과를 플랜 기대에 대해 검증해. 그 검증이 통과할 때까지 진짜 목적지 이름은 존재 안 해 — 성공으로 오인할 게 거기 없어.
Publish: 분장이 한 번에 벗겨져
검증 뒤에만 Waygate 는 publish 해: 스테이징된 파일을 진짜 목적지 이름에 나타나게 해, 가능하면 같은 볼륨 이름변경으로. 스테이징 항목이랑 목적지가 같은 볼륨에 있으니, 그 이름변경은 사실상 원자적이야 — 파일이 진짜 이름을 가졌거나 안 가졌지, 절반은 절대 없어. 진짜 이름이 나타나는 순간, 그 뒤 파일은 이미 완전하고 검증됐어. Publish 가 복사가 참이 되는 순간이야.
오퍼레이션-명명 스테이징에 복사하고, 검증하고, 그다음 같은 볼륨 이름변경으로 publish 해. 반쯤 쓰인 파일은 절대 진짜 목적지 이름을 차지 안 해. 스테이징이 불완전한 복사를 오퍼레이션 소유 이름 아래 두고; 검증이 publish 를 막고; 원자적 이름변경이 진짜 이름을 그 뒤 바이트가 이미 올바를 때만 나타나게 해.
목적지 볼륨에 스테이징하는 게 요령이야. 스테이징 항목은 최종 목적지랑 같은 볼륨에 살아야 해, 그게 publish 를 또 다른 볼륨 넘는 복사가 아니라 싼 원자적 이름변경으로 만드니까. 소스 볼륨에 스테이징하고 또 복사하면 스테이징이 제거하려 존재하는 바로 그 비원자적 위험을 다시 들여올 뿐이야.
Code
op 소유 이름으로 스테이지, 검증, 그다음 원자적 publish·swift
func copyThenPublish(_ src: URL, to dest: URL, _ plan: OperationPlan) async throws -> URL {
// Staging item lives on the DESTINATION volume, named for the operation:
let staging = dest.deletingLastPathComponent()
.appendingPathComponent(".waygate-stage-\(plan.id)")
try await copyPreservingMetadata(src, to: staging) // forks, ACLs, xattrs, dates
try await verify(staging, matches: plan.expectedMetadata)
try await journal.mark(plan.id, .verified)
// Same-volume rename -> effectively atomic. The real name appears
// only now, and the file behind it is already complete + verified.
try FileManager.default.moveItem(at: staging, to: dest)
return dest
}
// A crash before the rename leaves only `.waygate-stage-<id>` -- an obviously
// incomplete artifact the journal owns, never a fake `report.pdf`.
분장, 그다음 공개·text
during copy: .waygate-stage-op_7a3f <- obviously not the real file
crash here? only the staging item exists; report.pdf never appeared
verify passes: bytes confirmed against the plan
publish: .waygate-stage-op_7a3f --(atomic rename)--> report.pdf
after publish: report.pdf exists AND is already complete + verified.
There is no instant where report.pdf is half-written.
중단돼서 완전해 보이지만 손상된 파일을 남긴 다운로드를 떠올려봐 — 잘린 비디오, 깨진 zip. 이제 그 다운로드를 stage-verify-publish 로 다시 설계해봐: 다운로드 중 어느 이름에 쓰고, 뭘 검사하고, 진짜 파일명은 언제 나타나? 왜 이 버전은 진짜 이름에 손상된 파일을 절대 못 남겨?
Hint
다운로드 중엔 file.part 같은 데 쓰고, 끝나면 크기나 체크섬을 검증하고, 그러고서야 file.part 를 file 로 이름변경해. 진짜 이름이 검증 후 이름변경으로만 나타나니까, 중단된 다운로드는 file.part — 명백히 불완전한 아티팩트 — 만 남기지 진짜 이름을 입은 손상 파일을 절대 안 남겨. 그게 딱 Waygate 의 스테이징 규율이야.
Progress
Progress is local-only — sign in to sync across devices.