DB

Logs

아뵹젼 2022. 4. 21.

Recovery approach

- log-based recovery : write 연산을 수행하기 전에 로그를 stable storage에 남기는 방법이다.
- shadow-paging : 더 이상 사용되지 않는 오래된 방식으로 데이터를 업데이트 하면 old page의 copy를 갖고 있는 것이다. 

 

Shadowing

atomicity 와 durability 를 지원하는 아주 간단한 방법이다.

concurrent transaction 상황에서는 너무 많은 shadow 가 존재하기 때문에 다루기가 어렵다.

또한 큰 데이터베이스에서는 매우 비효율적이다. -> 데이터 clustsering 이 불가능하다.

텍스트 에디터에서 유용하게 사용된다.

 

모든 업데이트는 데이터베이스의 shadow copy에서 이루어지며, db_pointer 은 항상 가장 최신의 copy 를 가리킨다.

트랜잭션이 partially commited 상태라면, OS는 모든 업데이트된 페이지를 disk에 쓴다. 
그리고 데이터베이스 시스템은 db-pointer를 새로운 사본을 가리키도록 update한다.
이전 old copy는 삭제된다. 이제 트랜잭션은 committed state가 된다.

-> 이는 concurrency에 취약하기 때문에 큰 데이터베이스에서는 사용되기 어렵다.

db 데이터를 업데이트하면 page를 추가하여 새로운 페이지에 업데이트하는 값을 쓰는 방식이다.

before updated에 페이지 p1,p2,p3 이 존재했다고 가정하자. p2를 업데이트 하려고 할 때, p2에 데이터를 업데이트하는 것이 아니라 새로운 페이지 p4를 만들어서 그 곳에 업데이트 된 값을 쓰는 방식이다. 

 

Simple Logging: Normal Processing

log 는 stable storage 에 유지된다.

작업을 성공적으로 마친 뒤 반드시 로그를 write 한다.

log 는 log 기록의 연속이며, 데이터베이스에 업데이트된 활동 기록들을 가지고 있다.

<Ti start> : 트랜잭션 Ti 가 시작할 때 로그를 남긴다.

<Ti, X, V1, V2> : 트랜잭션 Ti 가 X 값을 V1에서 V2 로 업데이트할 때 로그를 남긴다.

<Ti commit> : 트랜잭션 Ti 가 마지막 구문까지 완료한 후에 로그를 남긴다.

 -> 이러한 로그 기록들은 로그 DB에 저장된다.

 

여러 트랜잭션이 동시에 실행되더라도 모든 트랜잭션은 하나의 디스크 버퍼와 로그를 공유한다.

앞으로는 concurrency control 이 Strict two-phase 기법을 사용한다고 가정할 것이다.

항상 commit 된 값만 read 한다.

 

Checkpoint

recovery 절차에서 생길 수 있는 문제는 다음과 같다.

  • 전체 log 를 모두 검색하는 것은 시간이 많이 든다.
  • 이미 데이터베이스에 업데이트를 한 트랜잭션에 대해 불필요한 redo 를 진행할 수도 있다.

-> checkpoint 이후의 statement 만 redo 한다. 즉, checkpoint 이전의 statement 는 이미 disk 에 저장이 되어있다고 보장한다.

<checkpoint L> : stable storage 에 다음과 같은 로그를 write 한다. // L = 현재 active 상태인 트랜잭션의 리스트

T1 은 이미 commit 된 상태이므로 무시한다.

T2, T3 : Redo -> 로그에 따라 재실행하며 disk 에 저장함 (checkpoint 이후에 commit 된 적이 있으므로)

T4 : Undo : rollback 으로, 아예 실행된 적이 없는 것처럼 되돌린다.

T3은 failure 시점에 이미 commit된 트랜잭션이다. 따라서 <T3, W, X , 10, 15> 의 로그 기록을 보고 failure 가 발생하여 redo하게 되면 X의 값을 15로 바꾸면 된다.

T4 의 경우 failure 시점에 commit이 되지 않은 상태라 로그 디비에 아무 기록이 없을 것이다. 따라서 했던 작업들을 롤백 (undo) 해야 한다.

 

Recovery 과정

undo-list(start 는 했는데, commit 이 이뤄지지 않은 것) 와 redo-list(commit 이 완료된 것) 를 모두 초기화한다.

로그를 맨 끝에서부터 backwards 로 스캔하면서, 첫 번째 <checkpoint L> 레코드가 발견될 때까지 scan 을 계속하며 리스트에 추가한다.

scan 을 하면서 발견한 레코드들의 처리는 다음과 같다.

  • <Ti, commit> -> Ti 를 redo-list 에 추가한다.
  • <Ti, start> -> 만약 Ti 가 redo-list 에 있지 않다면, undo-list 에 추가한다.

L 에 존재하는 모든 Ti 에 대해서, Ti가 redo-list 에 존재하지 않다면, undo-list 에 추가한다. (active 상태로, 트랜잭션이 commit 된 것은 아니나 checkpoint 이후에 어떠한 명령어도 등장하지 않아 backward scan 에서 처리되지 못한 케이스이다.)

undo-list 는 완료되지 않은 불완전한 트랜잭션들을 포함할 것이며, redo-list 는 모두 완료된 트랜잭션을 포함할 것이다.

 

undo 실행

이제 맨 끝에서부터 undo-list 에 존재하는 모든 Ti 에 대해서 <Ti, start> record 를 만날 때까지 backwards 스캔을 계속한다.

스캔을 하는 동안, undo-list 에 있는 로그에 대해서 undo 를 실행한다.

redo 실행

제일 최근의 <checkpoint L> record 에서 시작하여 log의 끝까지 forwards 스캔을 진행하면서, redo-list 에 들어있는 트랜잭션에 대해 redo 를 실행한다.

 

Steal vs Force

  • Force : commit 된 순간에 버퍼에 있던 해당 페이지들을 강제로 디스크에 쓴다. -> 비싸다.
  • Not-force : 트랜잭션이 커밋되어도 디스크에 쓸 필요가 없다.(Redo 필요) 
  • Steal : 트랜잭션이 커밋되지 않았더라도 디스크에 쓸 수 있다.(Undo 필요)
  • Not-Steal : 트랜잭션이 커밋되지 않았으면 디스크에 쓰지 않는다.

주로 Steal + Not-force 조합을 사용한다. -> Redo and Undo

 

'DB' 카테고리의 다른 글

Log-Based Recovery  (0) 2022.04.21
Failure and Recovery  (0) 2022.04.21
Insert and Delete Operations  (0) 2022.04.20
Deadlock  (0) 2022.04.20
Multiple Granularity Locking  (0) 2022.04.20

댓글