입출력을 동기화하는 것은 분명 중요합니다. 하지만, 그 문제를 너무 확대 해석하고 크게 신경 쓸 필요는 없습니다. 요즘의 운영체제들은 버퍼를 통한 지연된 쓰기 작업을 구현하고 있습니다. 그렇기에 앞에 write() 시스템 콜 이용 시 주의해야 될 사항들을 그렇게 신경쓰지 않으셔도 됩니다.
하지만, 개발을 하다보면 개발자가 직접 데이터가 디스크에 기록되는 시점을 제어하고 싶을 때가 있습니다. 이런 상황에 맞춘 몇몇의 시스템 콜을 확인해 보겠습니다.
1. fsync() 시스템 콜과 fdatasync() 시스템 콜
첫 번째는 fsync() 시스템 콜과 fdatasync() 시스템 콜입니다.
먼저, fsync() 시스템 콜에 대해 알아보겠습니다.
#include <unistd.h> int fsync (int fd) | ||
입력인자 | int fd | open() 시스템 콜로 열린 파일을 가리키는 파일 지정 번호 |
반환값 | int | 파일 쓰기 성공 : 0 ( 특별한 의미는 없음) 파일 쓰기 실패 : -1 |
fsync() 시스템 콜을 호출하면 파일 디스크립터에 맵핑된 파일의 모든 변경점을 디스크에 기록합니다.
이 말을 쉽게하면, 파일에 변경된 내역 즉, 파일에 쓰여진 내용을 디스크에 기록하는 것 입니다.
그럼, 파일은 어떻게 열려야 될까요? 네 맞습니다. 반드시 쓰기모드로 열려야만 write()등의 시스템 콜로 파일을 변경하고 디스크에 쓸 수 있습니다.
fsync() 시스템 콜은 파일의 inode까지 모두 디스크에 기록하게 되고, write() 시스템 콜과 다르게 하드 디스크에 데이터가 성공적으로 기록되야만 쓰기 여부를 반환하게 된답니다.
하지만, 이 시스템 콜에도 하나의 문제가 있는데요, 만약 하드디스크에 write cache가 존재하게 되면 실제 캐시까지 전달된 데이터를 확인하게 되고 디스크에 진짜 기록되었는지는 확인 할 방법이 없습니다.
안타깝게도 말이죠.. 하지만 cache buffer에 데이터가 보관되는 시간은 굉장히 짧다는 것 아시죠?
이정도로만 해도 충분히 디스크에 써졌다고 판단해도 될 것 같습니다.
다음, fdatasync() 시스템 콜에 대해 한번 알아봅시다.
#include <unistd.h> int fdatasync (int fd) | ||
입력인자 | int fd | open() 시스템 콜로 열린 파일을 가리키는 파일 지정 번호 |
반환값 | int | 파일 쓰기 성공 : 0 ( 특별한 의미는 없음) 파일 쓰기 실패 : -1 |
함수의 꼴을 보면 fsync와 똑같이 생겼습니다. 하는 일도 똑같습니다.
디스크에 데이터를 쓰는 일은 똑같다는 것이죠. 하지만 분명한 한 가지 차이점을 가지고 있는데요,
fdatasync() 시스템 콜은 너무 디스크에 데이터 기록에 집중한 나머지 메타데이터 즉, 파일의 inode는 갱신하지 않는다는 것이죠.
그 말은 바로 파일이 변경되었다는 작업 등이 디스크에 기록되지 않습니다.
일은 한 가지로 마무리하니 fsync() 보단 성능적으로는 더 이득일 수 있죠.
그리고 두 시스템 콜의 공통점 또한 한가지 있습니다. file의 메타데이터가 아닌 파일이 포함된 디렉토리의
메타데이터, 디렉터리 엔트리에 대한 동기화는 보장하지 않는다는 것입니다. 이게 무슨 상관이냐고 말씀하시는 분들도 있으시겠지만 관련 디렉토리 엔트리가 동기화 되지 않을 경우 그 파일에 접근하는 것이 불가능하답니다.
2. sync() 시스템 콜
sync() 시스템 콜은 위에서 설명한 두 가지 시스템 콜보다 더 많이 활용됩니다.
#include <unistd.h> void sync (void) | ||
입력인자 | void | |
반환값 | void |
sync() 시스템 콜은 입력, 반환값이 모두 없습니다. 그냥 호출하여 사용하면 되는데요, 모든 데이터를 디스크에 동기화하는 시스템 콜입니다. 데이터와 메타데이터 모두 기록하게 되죠.
기본적인 표준과 리눅스에서의 함수는 기능이 약간 다른데요, 표준은 모든 버퍼를 디스크에 기록하는 과정 기작하도록 요청만 하는 것으로 끝이지만, 리눅스에서는 모든 버퍼가 디스크에 모두 기록되어 동기화 될때까지 기다리게 됩니다. 하지만, 약간 오래 걸릴 순 있겠죠.
그 외에도 파일 오픈 시 플래그를 이용하여 입출력을 동기화 하는 방법이 있습니다.
FLAG 명 | 모드 |
O_SYNC | write() 시스템 콜이 파일을 기록하는 작업 동기화 |
O_DSYNC | 쓰기 작업 직후 데이터만 동기화(메타데이터 동기화 X) |
O_RSYNC | 쓰기,읽기 모두 동기화 O_SYNC, O_DSYNC와 같이 사용해야 함 |
이렇게 파일 입출력에 대해 정리를 해보았습니다.
정리해 보니 저도 잘 이해가 안되게 주절주절 말한 것 같은데요, 도움이 되셨으면 좋겠습니다.
'Linux > System Programming' 카테고리의 다른 글
[파일입출력] 6. 파일 안의 데이터 잘라내기 (0) | 2015.02.12 |
---|---|
[파일입출력] 5. lseek()으로 파일 탐색하기 (0) | 2015.02.10 |
[파일입출력] 3. write()로 파일에 쓰기 (2) | 2015.02.03 |
[파일입출력] 2. read()로 파일 읽기 (2) | 2015.02.01 |
[파일입출력] 1. 파일열기 (0) | 2015.01.18 |