Skip to content
isdnetworks
Go back

이름만으로 판정하지 않은 파일

(수정됨)

KYC 증빙 서류를 저장할 때 이름이 겹치는지만 보고 겹치면 이름 뒤에 (1) 을 붙여서 넣었다. 이름이 안 겹치는데도 같은 파일이 여러 벌씩 쌓이는 문제가 생겼다.

Table of contents

Open Table of contents

증상 — 이름이 안 겹쳐도 겹치는 내용

신분증_v2.jpg 와 신분증_최종.jpg 처럼 버전이 붙은 이름과 최종이라는 이름으로 같은 서류가 여러 번 올라오고 있었다. 이름이 다르니 충돌 검사에 안 걸리고 전부 별개 파일로 들어갔다.

이름은 회원이 정하는 값이고 같은 내용에 다른 이름을 붙이는 것을 막을 방법이 없다. 이름의 충돌과 내용의 중복은 서로 다른 문제였다.

조치 — 내용 해시와 참조 분리

MessageDigest 로 SHA-256 해시를 계산해서 같은 것이 이미 있으면 새로 넣지 않고 기존 것을 가리키게 했다. 처음 돌렸을 때 4만 개 중 8천 개가 같은 내용이었다.

두 가지 방법이 있었다. 같은 해시를 전부 하나로 합치는 것과, 실체 file_blobs 는 하나만 두고 회원별 참조 file_refs 를 여럿 두는 것이다. 뒤쪽을 골랐다. 이유는 서로 다른 회원이 같은 서류를 올린 자리에서 한쪽이 지우면 다른 쪽 서류가 사라져서다. 대신 마지막 참조가 사라질 때 실체를 지우는 참조 계수를 관리해야 하는 것을 감수했다.

주의 — 확장자와 실제 내용의 불일치

내용 말고도 크기와 형식과 안전성을 봐야 했다. 특히 확장자가 pdf 인데 앞부분을 읽어 보면 MZ 로 시작하는 실행 파일인 것이 섞여 있었다.

파일 앞부분의 서명을 읽어 확장자와 맞는지 비교하니 그런 것이 걸렸다. 이름이 무엇을 주장하는지와 내용이 무엇인지는 별개이므로 이름만 믿을 수 없었다.

판단 기준 — 싼 검사부터 두는 순서

검사를 크기와 확장자와 서명과 해시 중복 순서로 배치했다. 앞의 둘은 Content-Length 와 이름만 보면 되고 서명은 앞 몇 바이트만 읽으면 되지만 중복 판정은 파일 전체를 읽어야 한다.

싼 것에서 걸리면 비싼 것을 하지 않아도 되므로 큰 파일에서 시간이 크게 갈렸다. 검사 순서를 비용순으로 두는 것만으로 전체 처리 시간이 눈에 띄게 줄었다.

옮겼다는 것과 저장됐다는 것은 다르다

Files.move() 하고 나서 실제로 존재하는지와 Files.size() 가 기대값과 맞는지를 다시 확인하게 했다. 디스크가 찼을 때 예외가 나지 않고 파일이 잘린 채로 옮겨진 적이 있었기 때문이다.

실패했을 때 임시 파일이 남아 며칠 만에 /tmp 가 차는 문제도 있었다. 예외 처리에서 지우게 하되 프로세스가 죽으면 그것도 안 돌므로 find /tmp -mtime +1 로 오래된 임시 파일을 지우는 정리를 따로 뒀다.

저장 이름은 해시로 정하고 회원이 올린 이름은 original_name 에 따로 담았다. 저장 이름을 우리가 정하니 경로 문자나 운영체제가 못 다루는 글자나 지나치게 긴 이름이 들어와도 문제가 되지 않았다.

정리


Share this post on:

Previous Post
착수 전에 미해결을 세어 본다
Next Post
다시 하려면 무엇이 0이어야 하나