개발자의 길/Database

[SQLite3][C++] Sqlite3 의 journal file 에 대해

토아드 2021. 7. 28. 09:23
반응형

SQLite 의 Journal file

 SQLite 에서는 갑작스러운 power failure 등으로 인한 쓰기 작업이 중단되었을 경우 DB 손상을 막기 위해 Rollback Journal 이라는 기법을 사용한다.

 DB 에 write 작업이 발생하게 되면, rollback journal 이라는 곳에 데이터가 write 로 인해 변경되기 전으로 돌아갈 수 있도록 하는 정보들을 기록하게 된다. 데이터 write 및 commit 이 종료되면 journal file 을 삭제하게 되며, 쓰기작업 도중에 종료될 경우 삭제하지 않은 journal file 이 남아있는 상태로 남아있게 된다. rollback journal 을 이용해 무결성 복원을 해야하는 경우 이 journal 을 hot journal 이라고 부르는데, DB 를 열 때 이 hot journal 이 존재할 경우 hot journal 을 이용해서 이전 상태로 되돌리게 된다.

 정리하자면 DB 를 열고 사용중에 쓰기가 발생할 경우 아래와 같은 과정을 거치게 된다.

 

 DB Open -> hot journal 존재할시 이전 상태로 복원 -> .... -> Write 발생 (=BEGIN)-> journal file 에 롤백 정보 기록 -> db write 실시 -> journal file 삭제 (=COMMIT)

 

journal file 을 사용할 것인지, 삭제할 것인지에 대한 PRAGMA 또한 존재한다. ( pragma journal_mode=? )

default 로는 DELETE 모드인데, DELETE 모드에서는 journal file 을 디스크에 write 하며 journal file 이 필요없게 된 경우 삭제한다.

 

PRAGMA Synchronous 

journal file 을 관리하는데 있어 밀접하게 연관된 PRAGMA 가 이 Synchronous 라는 옵션이다.

 이 옵션값을 이해하기 위해서는 먼저 sync() 함수에 대한 이해가 간단히 필요한데 간단히 말하자면, linux file system 에서 file write 작업은 실제 Disk 가 아닌 OS 가 관리하는 file system 의 임시 영역에 이루어 지다가 한꺼번에 Disk 에 적용되는데, 이때 임시 공간에서 Disk 에 변경된 내용을 적용하는 작업이 sync 라고 이해하면 될 것 같다. ( 즉 sync 작업 없이 시스템 종료가 일어나게 된다면 write 한 file 은 다음 부팅때 적용이 되지 않은 채로 남아있게 될 것이다 )

 

옵션값과 각 옵션값에 대한 설명은 아래와 같다. 

EXTRA : FULL mode 의 동작에 더하여, DB 가 존재하는 Directory 에 대한 sync 작업을 한번 더 수행한다.

FULL ( default ): DB 가 write 되는 것에 대한 거의 완전한 동기화 작업을 수행한다. 갑작스런 power failure 에 대한 DB 손상을 막을 수 있다.

NOMAL: 기본적인 수준의 동기화 작업을 수행하지만 FULL 보다는 낮다.
OFF : DB Write 가 발생할 경우 disk 와의 동기화 작업을 하지 않는다.

 

기본적으로 FULL 이면 DB 손상을 막을 수 있으나, 한번 Wirte 된 DB 가 COMMIT 후에 데이터가 journal file 로 인해 절대 rollback 되면 안된다면 EXTRA 모드를 사용해야 한다.

 FULL 모드는 db 파일과 journal file 에 대한 fsync() 호출을 하며 DB Write 를 끝낸 후 COMMIT 을 종료하지만, journal file 이 삭제되는 것에 대해서는 보장을 하지 않는다. 즉 사용자가 DB Write 를 하고 COMMIT 이 종료된 것을 확인한 후에 즉시 power failure 가 일어나서 전원이 끊기게 된다면, journal file 이 남아있어 다음에 DB 를 Open 할 경우 write 가 되기 이전으로 rollback 하고 만다.

 EXTRA 모드는 db 파일과 journal file 이 존재하는 directory 에 대한 fsync 호출도 하기 때문에, journal file 이 삭제되는 것 까지 보장을 할수 있다.

2021.07.30 추가

 journal file 이 남아 있는데 DB 가 존재하는 partition 이 read-only 상태라면, sqlite3_preapre_v2 를 호출하는 단계에서 SQLITE_READONLY 를 리턴할 것이다. preapre 를 호출하면서 table 을 보려고 접근하는데, journal file 로 rollback 을 시키고자 write 를 시도하기 때문이다.

마무리

 Journal mode 에 대해 WAL 모드라는 것을 설명하지 않았는데, 이는 위에서 설명한 journal mode 와는 동작 메커니즘 자체가 다른 것으로 제외하였다. 성능도 좋고 DB 무결성에 대한 보장이 강력하고 Read 와 Write 의 병목 현상도 없어서 좋으나, 실제로 내가 도입하려고 테스트 해 보았을 때 DB Read 를 할 때 log 파일이 무조건적으로 생긴다는 제약이 있어서 사용하지 않았다(rollback journal 의 경우 write 가 발생할 때만 journal file 을 생성한다). 실제로 사용을 고려한다면 이런 부분도 고려해보면 좋을 것 같다.

 

참고자료

https://runebook.dev/ko/docs/sqlite/lockingv3

https://www.sqlite.org/lockingv3.html

https://gywn.net/2013/08/let-me-intorduce-sqlite/

반응형