跳到主要内容

Concurrent Prefix Recovery: Performing CPR on a Database

TL;DR

  • 可以做到紀錄每個session的最後一個commit紀錄
  • epoch的方式來做,直接做snapshot寫進storage,避免WAL需要大量append的overhead
  • 呈上,因為每個session各自完成自己的部分,不需要lock來synchronization

CPR

Transactionally Consistent

如果一個snapshot包含所有被committed的資料,但沒有任何沒被committed的資料,那就可以被稱為Transactionally Consistent

Prefix Recovery

Prefix recoverytransactionally consistent更嚴格。一個snapshot必須要能recover system-wide、所有transaction的行為,也就是說,所有issued的操作。

一個簡單的方式是在確保consistent之前,停止accept新的transactions,這種作法稱作commit-consistent checkpointing

另外一種asynchronous的做法是將database分成兩個版本: stablelive。屬於prefixTransactions會同時更新stablelive,不屬於prefix的transaction只更新liveStable的版本會asynchronous的被做成snapshot。

Concurrent Prefix Recovery

定義: 對每個client CC,database state包含了所有的某個時間點TCT_C之前commited的紀錄,但不包含此TCT_C之後的紀錄。

State Machine

CPR state machine

Algorithm

state machine algorithm

Rest Phase

rest phase的時候才transaction可以commit,在commit的時候,就是執行CommitCommit function,把global phase改成PREPARE,然後在epoch註冊PrepareToInProg,在bump的時候執行。

Prepare Phase

在這個phase會改變database version。任何一個transaction只有在它所有的read write instrcution set都屬於當前的verstion vv才會被執行。如果transaction含有對大於vv的資料做讀寫,就abort。

In-Progress Phase

如果所有的threads都進入PREPARE phase,PrepareToInProgPrepareToInProg就會被執行。這時候如果refresh自身的狀態,就會進入IN-PROGRESS,並且在v+1v+1的時候執行transaction,並且把records的version都更新成v+1v+1

Wait-Flush Phase

當所有的thread都進入IN-PROGRESS,epoch framework會執行InProgToWaitFlushInProgToWaitFlush。首先,global phase設定成WAIT-FLUSH。然後,database的版本vv被capture,如果一個record的version是v+1v+1stable version會被用來commit,不然就用live version。

當這些處理完,global phase被更新成REST,然後版本被更新成v+1v+1

Per Thread Algorithm

thread algorithm

Run

Thread 每loop k次,就refresh local的phaseversion,如果這時候state machine進到in_progress,就記住time tTt_T

Execute

CPR in FASTER

CPR在FASTER上的實作多了一個state (如下圖)。 faster state machine

States

PREPARE

PREPARE phase,thread會嘗試替local的pending list裡的request獲取lock (latch),並且在完成以後才釋放。處理的邏輯如下:

  • acquire latch
  • 如果record在mutable region,in-place update
  • 如果record在fuzzy region,放進pending-list之後處理
  • 如果record在read-only region,做copy-on-write
  • 如果record不在記憶體,把從storage撈進記憶體的請求放進pending-list
  • 如果無法acquire latch或是發現record version > local version,就refresh epoch並且進入IN-PROGRESS

IN-PROGRESS

當所有的thread都進入PREPARE,而且完成acquring latch for pending requests,global state就transition到IN-PROGRESS,而thread在之後也會靠著refresh來進入IN-PROGRESS

設計上,在vv之前的操作都會被commit,而之後的record不會,因此版本是vv的record,如果在記憶體的話,就會嘗試獲取exclusive lock來做copy-on-write,並且把此record append在最後面,設定version為v+1v+1。如果record的版本 > vv,就做in-place update。

WAIT-PENDING

當所有thread都進入IN-PROGRESS,則global state進入WAIT-PENDING。在此phase,所有的thread不是在IN-PROGRESS,就是在WAIT-PENDING,因此做的事跟IN-PROGRESS差不多。

WAIT-FLUSH

當所有request都完成以後,我們紀錄HybridLog的tail offset,並且把read-only的offset移至此offset。

Recovery

在recover的時候,我們scan HybridLog index from S=min(Lsi,Lsh)S = min(L^i_s, L^h_s) to E=max(Lei,Leh)E = max(L^i_e, L^h_e),然後把每個slot 指向record version v\le v的record index。

References