일반적으로 여러 프로세스에서 UNIX의 파일에 추가 할 때 당연한 것으로 간주 할 수있는 것은 무엇입니까? 데이터가 손실 될 수 있습니까 (한 프로세스가 다른 프로세스의 변경 사항을 덮어 씀)? 데이터가 망가질 수 있습니까? (예를 들어, 각 프로세스는 로그 파일에 추가 할 때마다 한 줄씩 추가합니다. 두 줄이 엉망이 될 수 있습니까?) 위의 의미에서 추가가 원 자성이 아닌 경우 상호 배제를 보장하는 가장 좋은 방법은 무엇입니까?
일반적으로 여러 프로세스에서 UNIX의 파일에 추가 할 때 당연한 것으로 간주 할 수있는 것은 무엇입니까? 데이터가 손실 될 수 있습니까 (한 프로세스가 다른 프로세스의 변경 사항을 덮어 씀)? 데이터가 망가질 수 있습니까? (예를 들어, 각 프로세스는 로그 파일에 추가 할 때마다 한 줄씩 추가합니다. 두 줄이 엉망이 될 수 있습니까?) 위의 의미에서 추가가 원 자성이 아닌 경우 상호 배제를 보장하는 가장 좋은 방법은 무엇입니까?
답변:
'PIPE_BUF'크기 미만의 쓰기는 원자 적이어야합니다. 그것은 쉽게 더 클 수 있지만 최소한 512 바이트 여야합니다 (리눅스는 4096으로 설정되어있는 것 같습니다).
이것은 완전히 POSIX 호환 구성 요소를 모두 이야기하고 있다고 가정합니다. 예를 들어 NFS에서는 그렇지 않습니다.
그러나 'O_APPEND'모드에서 연 로그 파일에 쓰고 줄 (개행 포함)을 'PIPE_BUF'바이트 길이로 유지한다고 가정하면 손상 문제없이 로그 파일에 여러 작성자를 가질 수 있습니다. 인터럽트는 중간이 아닌 쓰기 전후에 도착합니다. 재부팅 fsync(2)
후에도 파일 무결성을 유지하려면 모든 쓰기 후 호출해야 하지만 성능면에서는 끔찍합니다.
설명 : 댓글과 Oz Solomon의 답변을 읽어 보세요. 나는 O_APPEND
그것이 그 PIPE_BUF
크기의 원 자성 을 가져야한다고 확신하지 않습니다 . Linux가 구현 된 방식 write()
일 수도 있고 기본 파일 시스템의 블록 크기 때문일 수도 있습니다.
PIPE_BUF
해당 페이지는 파이프와 FIFO가 아니라 일반 파일에 적용됩니다.
편집 : 2017 년 8 월 최신 Windows 결과로 업데이트되었습니다.
비동기 파일 시스템 및 파일 I / O C ++ 라이브러리를 구현하는 제안 된 Boost.AFIO 의 작성자로서 테스트 코드 및 결과에 대한 링크로 답변을 제공 할 것 입니다.
첫째, Windows에서 O_APPEND 또는 이에 상응하는 FILE_APPEND_DATA는 최대 파일 범위 (파일 "길이")의 증가가 동시 작성자에서 원자 적임을 의미합니다 . 이것은 POSIX에 의해 보장되며 Linux, FreeBSD, OS X 및 Windows는 모두 올바르게 구현합니다. Samba는 또한 올바르게 구현하지만 v5 이전의 NFS는 원자 적으로 추가 할 수있는 유선 형식 기능이 없기 때문에 그렇지 않습니다. 따라서 추가 전용으로 파일을 열면 NFS가 관련되지 않는 한 주요 OS에서 서로에 대해 동시 쓰기가 끊어지지 않습니다 .
그러나 원자 적 추가에 대한 동시 읽기 는 OS, 파일링 시스템 및 파일을 연 플래그에 따라 조각난 쓰기를 볼 수 있습니다. 최대 파일 범위의 증분은 원자 적이지만 읽기와 관련된 쓰기의 가시성은 또는 그렇지 않을 수 있습니다. 원자 적입니다. 다음은 플래그, OS 및 파일링 시스템에 따른 간략한 요약입니다.
NTFS가 포함 된 Microsoft Windows 10 : 원 자성 업데이트 = 10.0.10240까지 1 바이트, 10.0.14393에서 1Mb 이상, 아마도 무한대 (*).
ext4가있는 Linux 4.2.6 : 업데이트 원 자성 = 1 바이트
ZFS가있는 FreeBSD 10.2 : 업데이트 원 자성 = 최소 1Mb, 아마도 무한대 (*)
NTFS가 포함 된 Microsoft Windows 10 : 원 자성 업데이트 = 10.0.10240까지 페이지가 정렬 된 경우에만 최대 4096 바이트, 그렇지 않으면 FILE_FLAG_WRITE_THROUGH가 꺼져 있으면 512 바이트, 그렇지 않으면 64 바이트가 포함됩니다. 이 원자 성은 설계가 아닌 PCIe DMA의 기능 일 수 있습니다. 10.0.14393 이후, 최소 1Mb, 아마도 무한대 (*).
ext4가있는 Linux 4.2.6 : 업데이트 원 자성 = 최소 1Mb, 아마도 무한대 (*). ext4를 사용하는 이전 Linux는 확실히 4096 바이트를 초과하지 않았으며 XFS는 확실히 사용자 지정 잠금을 사용했지만 최근 Linux가 마침내이 문제를 해결 한 것처럼 보입니다.
ZFS가있는 FreeBSD 10.2 : 업데이트 원 자성 = 최소 1Mb, 아마도 무한대 (*)
https://github.com/ned14/afio/tree/master/programs/fs-probe 에서 원시 경험적 테스트 결과를 볼 수 있습니다 . 우리는 512 바이트 배수에서만 찢어진 오프셋을 테스트하므로 512 바이트 섹터의 부분 업데이트가 읽기-수정-쓰기주기 동안 찢어 질지 여부는 말할 수 없습니다.
따라서 OP의 질문에 답하기 위해 O_APPEND 쓰기는 서로 간섭하지 않지만 O_APPEND 쓰기와 동시 읽기는 O_DIRECT가 켜져 있지 않는 한 Linux에서 ext4를 사용하여 조각난 쓰기를 볼 수 있습니다. 그러면 O_APPEND 쓰기는 섹터 크기 배수 여야합니다.
(*) "Probably infinite"는 POSIX 사양의 다음 절에서 비롯됩니다.
다음 함수는 모두 일반 파일 또는 심볼릭 링크에서 작동 할 때 POSIX.1-2008에 지정된 효과에서 서로 원자 적이어야합니다. ... [많은 함수] ... read () ... write ( ) ... 두 스레드가 각각 이러한 함수 중 하나를 호출하는 경우 각 호출은 다른 호출의 지정된 모든 효과를 보거나 전혀 표시하지 않습니다. [출처]
과
쓰기는 다른 읽기 및 쓰기와 관련하여 직렬화 될 수 있습니다. 파일 데이터의 read ()가 데이터의 write () 후에 발생하는 것으로 (어떤 방법 으로든) 입증 될 수있는 경우, 다른 프로세스에서 호출이 이루어 지더라도 해당 write ()를 반영해야합니다. [출처]
그러나 반대로 :
POSIX.1-2008의이 볼륨은 여러 프로세스에서 파일에 대한 동시 쓰기 동작을 지정하지 않습니다. 응용 프로그램은 일종의 동시성 제어를 사용해야합니다. [출처]
최대 원자 추가 크기를 경험적으로 테스트하는 스크립트를 작성했습니다. bash로 작성된 스크립트는 모두 동일한 파일에 작업자 별 서명을 작성하는 여러 작업자 프로세스를 생성합니다. 그런 다음 파일을 읽고 겹치거나 손상된 서명을 찾습니다. 이 블로그 게시물 에서 스크립트의 소스를 볼 수 있습니다 .
실제 최대 원자 추가 크기는 OS뿐만 아니라 파일 시스템에 따라 다릅니다.
Linux + ext3에서 크기는 4096이고 Windows + NTFS에서 크기는 1024입니다. 더 많은 크기는 아래 설명을 참조하십시오.
echo $line >> $OUTPUT_FILE
단일 호출이 발생 한다고 가정하는 것 같습니다 . write
$line
표준에 따르면 http://www.opengroup.org/onlinepubs/009695399/functions/pwrite.html .
경우]
O_APPEND
파일 상태 플래그의 플래그가 설정되어있는 오프셋 파일은 각각의 기록에 앞서 파일의 마지막에 설정되어야하고 중간 파일 수정 작업은 파일 오프셋 및 기록 동작 변화 사이에서 발생하지 아니한다.
fsync(2)
보장하는만큼 보장하며sync(2)
성능에 큰 해머 영향을주지 않습니다.