FileSharer 개발 노트 5 — 폴더 ZIP을 매번 만들지 않기 위한 캐시 설계
FileSharer 개발 노트 · 05 / 10

폴더 공유에서 첫 응답이 늦는 이유가 네트워크가 아니라 압축일 수도 있습니다. 다운로드 버튼을 누른 다음 폴더 전체를 ZIP으로 만들면, 그동안 상대는 파일 바이트를 하나도 받지 못합니다. 연결이 끊겨 다시 시도할 때 압축까지 반복하면 기다림이 더 길어집니다.

FileSharer의 ZipCache는 이 준비 비용을 전송과 분리합니다. 폴더를 공유할 때 백그라운드에서 ZIP을 미리 만들고, 내려받을 때는 준비된 파일을 일반 파일처럼 전송합니다. 덕분에 ZIP에도 Range 처리를 같은 방식으로 적용할 수 있습니다.
사전과 압축 작업에 서로 다른 잠금을 둔다
캐시에는 공유 ID별 Entry가 있고, 각 항목에 BuildLock이 있습니다. 항목을 찾거나 만드는 사전 접근에는 mapLock을 사용하고, 실제 ZIP을 만드는 동안에는 해당 항목의 BuildLock을 잡습니다.
이 구분은 하나의 큰 폴더가 압축되는 동안 다른 공유 항목의 사전 조회까지 계속 묶어 두지 않기 위한 구조로 읽을 수 있습니다. 같은 공유를 동시에 요청한 스레드는 같은 결과를 기다립니다. 그렇다고 CPU나 디스크 사용량까지 제한하는 작업 큐가 구현된 것은 아닙니다. 다른 공유의 압축은 동시에 실행될 수 있습니다.
완성되지 않은 ZIP은 다른 이름으로 둔다
GetOrBuild는 .part 파일에 ZIP을 작성한 다음 최종 이름으로 이동합니다. 압축 단계는 다음과 같습니다.
ZipFile.CreateFromDirectory(
item.FilePath, partPath, CompressionLevel.Fastest, false);
File.Move(partPath, finalPath);
최종 파일명이 있다는 이유로 아직 쓰는 중인 결과를 재사용하지 않게 하려는 설계입니다. 압축 수준은 Fastest로 지정돼 있지만, 이번 확인에서는 다른 수준과의 시간·용량 비교를 실행하지 않았습니다. 따라서 몇 배 빨라진다는 수치는 제시하지 않습니다.
캐시를 언제 버릴지가 더 어렵다
캐시 재사용 여부는 폴더의 지문으로 결정합니다. 원본 TryStampFolder가 만드는 값은 다음 세 가지의 조합입니다.
파일 수 : 총 바이트 수 : 가장 최신 파일의 수정 시각
폴더 전체의 내용을 다시 해시하지 않고 비교할 수 있어 계산이 단순합니다. 그러나 이것이 폴더 내용의 완전한 식별자는 아닙니다. 파일 이름 목록이나 각 파일의 내용을 직접 포함하지 않습니다.
이 차이를 원본 함수로 확인했습니다. 샘플 파일의 내용을 AAAA에서 BBBB로 바꾸고 수정 시각을 동일하게 맞췄습니다. 파일 개수와 길이는 그대로입니다.
| 변경 | 지문 비교 결과 |
|---|---|
| 내용만 변경, 크기와 수정 시각 유지 | 동일함 |
| 4바이트에서 5바이트로 길이 변경 | 달라짐 |
첫 결과는 캐시 판정이 이 종류의 변경을 구분하지 못한다는 뜻입니다. 원본 GetOrBuild는 지문이 같고 캐시 파일이 있으면 재사용하므로, 오래된 ZIP을 반환할 가능성이 소스 흐름상 있습니다. 이번 시험은 지문 함수의 결과를 직접 확인한 것이며, ZIP 전체를 내려받아 비교한 통합 시험은 아닙니다.
갱신 정책은 자료의 성격에 맞춘다
전달할 자료를 한 번 묶고 더 이상 수정하지 않는 사용 방식이라면 공유 시점의 스냅숏을 만드는 방법이 명확합니다. 계속 수정되는 작업 폴더라면 경로·파일 크기·개별 수정 시각을 포함하는 목록이나 내용 해시, 명시적인 버전 증가처럼 더 강한 변경 기준을 검토할 수 있습니다.
어떤 방법도 공짜는 아닙니다. 내용 해시는 파일을 읽는 비용이 들고, 목록을 읽는 동안에도 파일이 바뀔 수 있습니다. 먼저 “공유 당시의 묶음”인지 “항상 최신 폴더”인지를 제품 기능으로 정해야 캐시가 무엇을 보장해야 하는지 결정됩니다.
캐시 정리도 수명 관리의 일부다
원본에는 공유별 삭제와 종료 시 전체 정리 함수가 있습니다. 압축 전에는 원본 용량에 256MiB 여유를 더해 디스크 공간을 확인하려고 하지만, 확인 자체가 실패하면 통과시키는 경로도 있습니다. 이 값만으로 압축 도중 디스크 부족을 배제할 수는 없습니다.
ZIP 캐시의 효과는 준비된 결과를 재사용하는 데서 나옵니다. 그 결과가 언제까지 같은 자료를 뜻하는지까지 정의하면, 성능 개선과 내용의 정확성을 함께 설명할 수 있습니다.
FileSharer.cs:1239–1329 ZipCache.GetOrBuild · FileSharer.cs:1336–1349 PrebuildAsync · FileSharer.cs:1394–1427 TryStampFolder / HasFreeSpace · FileSharer.cs:4951–4970 ZIP 전송
본문의 개선안은 현재 구현된 기능과 구분합니다.
댓글
댓글 쓰기