注:Condolination array 的 slot 部分理解有問題
Abstract
4個缺陷限制了 logging-related 的數(shù)據(jù)庫系統(tǒng)的可擴(kuò)展性:
- 大量小 I/O 請求可能過載 disk
- 事務(wù)在等待 log flush 期間持有鎖
- 外延的而上下文切換羡滑,帶來的線程執(zhí)行 log I/O 給操作系統(tǒng)調(diào)度器帶來的壓力
- 事務(wù)順序訪問內(nèi)從中的 log 數(shù)據(jù)結(jié)構(gòu)帶來的競爭
本文介紹了這些問題门驾,并用一種全面的个榕、可擴(kuò)展的 log 方式來解決這些問題鸟缕,展示出了可觀的性能。
Introduction
以前的 DBMS 的硬件環(huán)境是:單核泻帮、高 I/O 延遲筏养,現(xiàn)在這一情況已經(jīng)改變谭胚。新的 DBMS 盡可能利用并發(fā)性來交織大量事務(wù)的執(zhí)行。雖然理論上硬件提升后颈嚼,并發(fā)性也就更高毛秘,但是 DBMS 內(nèi)部的很多瓶頸限制了這一提升。這些瓶頸如 Abstract 里所列舉的粘舟,目前的研究都只是分段或部分地解決這些問題熔脂,沒有提出一個充分適應(yīng)當(dāng)前多核環(huán)境下的,可擴(kuò)展的 log manager柑肴。
Write-ahead Logging and Log Bottlenecks
幾乎所有數(shù)據(jù)庫系統(tǒng)都使用中心化的 write-ahead logging (WAL) 技術(shù)霞揉。WAL 技術(shù)的目的和好處這里就不另外說明了,文中給出了四種存在的 delay晰骑,如下所示适秩。
- I/O-related delays
這個好理解绊序,就是每次日志要寫到非易失性存儲上,一般是磁盤秽荞,I/O 有延遲骤公。 - Log-induced lock contetention
寫操作需要持有日志的寫鎖,在 flush 期間一直持有寫鎖扬跋,會導(dǎo)致其它線程無法并發(fā)阶捆。 - Excessive context switching
CPU 可能將正在執(zhí)行事務(wù)的線程給切換出去了,因為時間片到了钦听。 - Log buffer contention
中心化的設(shè)計導(dǎo)致只有一個中央日志洒试,大量線程同時嘗試往日志里寫的時候,因為日志是先寫到緩沖區(qū)的朴上,這樣就算沒有邏輯鎖垒棋,也會產(chǎn)生“競爭”。
async logging 異步日志可以有效解決上述問題的前三個痪宰,并且很多數(shù)據(jù)庫系統(tǒng)叼架,如 Oracle 和 PostgreSQL 都提供,但是可能會產(chǎn)生數(shù)據(jù)丟失的問題衣撬。這里不展開闡述乖订。目前為止,還沒有方法全部解決上述四個問題淮韭。
A Holistic Approach to Scalable Logging
- Early Lock Release (ELR)
ELR 用來解決寫鎖競爭垢粮。ELR 在研究工作中多次被提到,但是目前沒有實現(xiàn)到任何數(shù)據(jù)庫引擎中靠粪。(注:這個 ELR 可能存在設(shè)計問題) - Flush Pipelining
用來解決上寫問切換的問題蜡吧。 - Log Buffer Redesign
重新設(shè)計了 log buffer, 來實現(xiàn)線程數(shù)量、日志大小與日志競爭之間無關(guān)占键。但可能導(dǎo)致內(nèi)存帶寬成為新的瓶頸昔善。
Related Work
ARIES (Algorithms for Recovery and Isolation Exploiting Semantics) 技術(shù)在 DBMS 中廣泛被應(yīng)用,來實現(xiàn)并發(fā)控制畔乙、事務(wù)回滾和錯誤恢復(fù)君仆。ARIES 技術(shù)下的 log 被實現(xiàn)為一個所有事務(wù)共享的全局?jǐn)?shù)據(jù)結(jié)構(gòu),從而造成了性能瓶頸牲距。
固態(tài)硬盤能極大地減少 I/O 帶來的開銷返咱,但是因為同步 flush 操作還是會造成線程阻塞,從而觸發(fā)線程調(diào)度牍鞠,還是不能消除所有開銷咖摹。
Log 組提交策略將多個 flush 操作合并為單個 I/O 操作,從而減少了上面提到的開銷难述。
TODO 沒看懂 Unfortunately, group commit does not eliminate unwanted context switches because transactions merely block pending notification from the log rather than blocking on I/O requests directly.
異步提交繼承了組提交的思想萤晴,但還包括異步吐句。異步就可能造成數(shù)據(jù)丟失。
一個研究結(jié)論:事務(wù)可以安全地在 flush 日志到磁盤上之前就釋放鎖店读。ELR 基于這個結(jié)論做了實現(xiàn)嗦枢。
內(nèi)存數(shù)據(jù)庫面臨的挑戰(zhàn)就是,log I/O 相比之下成為很大的性能瓶頸屯断,因為這是唯一需要訪問磁盤的操作文虏,體現(xiàn)在磁盤 I/O 本身的延遲和對 log buffer 的競爭。
Moving Log I/O Latency off the Critical Path
Early Lock Release
事務(wù)的鎖可以在日志提交到磁盤之前被釋放裹纳,只要它不會在持久化之前返回給客戶端任何結(jié)果择葡。但是如果有預(yù)提交事務(wù)要讀這個結(jié)果紧武,那么就存在一個依賴關(guān)系剃氧,DBMS 保證在它所依賴的事務(wù)被完成之前,即寫到磁盤上之前阻星,不會返回任何結(jié)果朋鞍。順序日志實現(xiàn)天生保證了這一特點,因為日志只能順序?qū)憽?br> ELR 系統(tǒng)必須包含兩個條件來保證可恢復(fù)性:
- 每一個事務(wù)的日志必須在它所依賴的事務(wù)完成預(yù)提交階段后妥箕,才能提交滥酥。
這里涉及到一個數(shù)據(jù)庫事務(wù)的三階段提交的概念。詳細(xì)可以查閱博客畦幢。與本文相關(guān)的坎吻,pre-commit 后,所有操作已經(jīng)計入日志宇葱,而 do-commit 只是根據(jù)日志去寫入磁盤瘦真。所以只要 pre-commit 完成,實際上就可以釋放日志的寫鎖了黍瞧。
- 當(dāng)一個 pre-commit 事務(wù)被 abort 掉后诸尽,依賴該事務(wù)的所有事務(wù)也要被 abort。這個很好理解印颤,需要注意的是實現(xiàn)上您机。
一篇博客中 關(guān)于 WAL 的工作流程的解釋。
1.在SQL Server的緩沖區(qū)的日志中寫入”Begin Tran”記錄
2.在SQL Server的緩沖區(qū)的日志頁寫入要修改的信息
3.在SQL Server的緩沖區(qū)將要修改的數(shù)據(jù)寫入數(shù)據(jù)頁
4.在SQL Server的緩沖區(qū)的日志中寫入”Commit”記錄
5.將緩沖區(qū)的日志寫入日志文件
6.發(fā)送確認(rèn)信息到客戶端(SMSS,ODBC等)
7.將緩沖區(qū)內(nèi)的頁寫入到磁盤
一篇博客中 關(guān)于事務(wù)提交的工作流程解釋年局。
0.begin transaction;
1.search & lock tuple for update;
2.update tuple & generate log;
3.write commit log;
4.flush logs;
5.unlock tuples;
6.commit & notify user;
容易發(fā)現(xiàn)际看,事務(wù)在寫出并且持久化日志的時候會帶來 IO,而 IO 通常而言比較耗時矢否。如果事務(wù)中此前的操作都是內(nèi)存操作的話(在內(nèi)存數(shù)據(jù)庫或 LSM 結(jié)構(gòu)的系統(tǒng)中更明顯)仲闽,這些 IO 的相對耗時就會顯得更大。IO 雖然可以做成異步的兴喂,但是在 IO 結(jié)束之前鎖都仍然會被持有蔼囊,從而會阻塞其他的并發(fā)事務(wù)焚志。如果可以把第 5 步釋放鎖的操作提前,放到第 4 步刷出日志之前畏鼓,則可以讓并發(fā)操作同一記錄(試圖獲得鎖)的事務(wù) t2 提前開始執(zhí)行酱酬,從而可以增加系統(tǒng)的吞吐量。顯然云矫,第 6 步的 commit 操作不能提前膳沽,仍然必須等到日志持久化完成之后才能通知用戶提交成功,因此用戶事務(wù)的響應(yīng)時間不會縮短让禀。
現(xiàn)有 DBMS 沒有采用 ELR 的挑社,作者文中認(rèn)為是因為異步更高效,但根據(jù)前面的博客巡揍,MySQL 是做過嘗試的痛阻,但失敗了,同時也有臟讀的問題腮敌。
Evaluation of ELR
鎖競爭越激烈阱当,ELR 帶來的性能提升越大;I/O 耗時越長(持有鎖的時間越長)糜工,ELR 帶來的性能提升越大弊添。
Decoupling OS Scheduling from Log Flush Operations
log flush 造成的延遲來自兩個方面:
- I/O 造成的等待
- I/O 導(dǎo)致阻塞一個線程和解阻塞一個線程帶來的上下文切換
I/O 的時候 CPU 可以做其它的工作,但是調(diào)度的時候捌木,CPU 是被占用了幾毫秒的時間的油坝。
調(diào)度和上下文切換越來越重要的原因:
- 固態(tài)硬盤的速度越來越快,調(diào)度和上下文切換帶來的耗時占比越來越大刨裆。
- 指數(shù)增長的核數(shù)讓 OS 調(diào)度線程的時候考慮的更多澈圈,更復(fù)雜。
測試發(fā)現(xiàn)崔拥,隨著 client 線程的增加极舔,系統(tǒng)耗時線性增長,所以單獨使用組提交并不能完全解決擴(kuò)展性的問題链瓦,異步提交很快但是可能不安全拆魏。
Flush Pipelining
Flush Pipelining 的思想主要是將線程在事務(wù)提交后,與等待 flush 操作完成進(jìn)行分離慈俯。分為以下步驟:
- 線程異步提交事務(wù)后渤刃,不等待 flush 操作完成,但是也不是直接就返回了贴膘,而是退出當(dāng)前事務(wù)卖子,將狀態(tài)寫入 log 里,然后繼續(xù)執(zhí)行其它事務(wù)刑峡。
- 一個守護(hù)線程按時洋闽、按次玄柠、按大小等策略自動觸發(fā) flush。
- flush 完成后诫舅,守護(hù)線程通知執(zhí)行線程 newly-hardened transactions羽利,which eventually reattach to each transaction, finish the commit process and return results to the client.
這里具體的事務(wù)操作沒看懂,猜測是執(zhí)行線程重新執(zhí)行上次的事務(wù)刊懈,完成事務(wù)提交后面要做的工作这弧,然后返回值給 caller 函數(shù)。hardened 的意思貌似是指日志寫到磁盤上虚汛,而不是緩沖區(qū)中匾浪。
產(chǎn)生日志記錄后 abort 掉的事務(wù)也必須 hardened 才能回滾。
TODO 有點沒看懂
Evaluation of Flush Pipelining
略
Scalable Log Buffer Design
大部分?jǐn)?shù)據(jù)庫引擎使用 ARIES 的一個變體卷哩,給每個 log 記錄一個唯一的 Log Sequential Number (LSN)蛋辈。LSN 編碼了記錄的磁盤位置,同時作為數(shù)據(jù)頁寫到磁盤的時間戳殉疼,還作為指向內(nèi)存和磁盤中的 log 記錄的指針梯浪。LSN 也可以用來做 log buffer 中的地址,這樣一來生成一個 LSN 的同時也就預(yù)留了 buffer 中的空間瓢娜。
為了保證數(shù)據(jù)庫的一致性,ARIES 對 LSN 有嚴(yán)格排序要求礼预。技術(shù)上并不需要全局排序來保證正確性眠砾,正確的偏序又可能太復(fù)雜且互相依賴,不值得作為性能優(yōu)化的備選項托酸。
插入一條記錄到 log buffer 中包括如下三個階段:
- LSN generation and log buffer acquire.
線程必須先申請打算寫 log 進(jìn)去的空間褒颈。雖然 LSN 是個線性操作,但是很快且可預(yù)測励堡,除非一些異常情況谷丸,比如 buffer wraparound 和 buffer 滿。 - Log record insertion.
線程把 log 寫進(jìn)之前申請的空間应结。 - Log buffer release.
事務(wù)釋放 buffer刨疼,從而允許 log manager 把 log 中的記錄寫到磁盤上。
最簡單的方法鹅龄,log insert 之前獲取到 log 的鎖揩慕,這個鎖只有一個,然后做完 2扮休,3操作后迎卤,釋放 buffer 的同時釋放這個鎖。但很明顯玷坠,這樣做就把 insert log 線性化了蜗搔,并發(fā)高的時候就成了性能瓶頸劲藐;同時,如果 log record 大小不同樟凄,那么這部分工作的性能損耗就不可預(yù)測瘩燥。
解決這個問題的思路:使得 insert log 操作和并發(fā)數(shù)、log record 的大小無關(guān)不同。
Consolidating Buffer Allocation
log record 由一個標(biāo)準(zhǔn)的 header 和任意數(shù)據(jù)載荷組成厉膀。log buffer 分配申請由兩個連續(xù)的請求組成,內(nèi)容也是一樣的形式二拐。利用這一點服鹅,通過類似組提交的思想,把多個 buffer 分配申請進(jìn)行合并百新,從而擴(kuò)大吞吐量企软。
TODO 看不懂。擴(kuò)展了 elimination-based backoff 的思想饭望,同時利用 elimination trees 和 backoff仗哨。。铅辞。
TODO 看不懂厌漂。When elimination is successful threads satisfy their requests without returning to the shared resource at all, making the backoff very effective. For example, stacks are amenable to elimination because push and pop requests which encounter each other while backing off can cancel each other directly via the elimination array
and leave.
遇到 log insert 競爭的線程,回退到一個叫 consolidation array 的地方斟珊,合并它們的寫操作苇倡,再嘗試對 log buffer 進(jìn)行寫操作。這里叫 consolidation 而不是 elimination 是因為囤踩,線程在合并請求后旨椒,還要進(jìn)行協(xié)調(diào):最后一個執(zhí)行 insert 的線程得釋放自己組的 log buffer。
這樣一來堵漱,log buffer 支持的最大并發(fā)數(shù)就變成了數(shù)組的容量综慎,而不是系統(tǒng)內(nèi)的線程數(shù)。
這里的 allocation 首先揭示了一個思想勤庐,后面也用到了 insert 上:一個線程嘗試去鎖 buffer 的時候示惊,如果沒有鎖,這個線程就拿到鎖埃元,執(zhí)行自己的操作涝涤,再釋放鎖;如果這個時候鎖被占用著的岛杀,那么這個線程就回退到一個 consolidation array阔拳,在里面繼續(xù)嘗試拿鎖。不同的是,這個時候如果再來一個請求糊肠,這個請求也進(jìn)入 consolidation array辨宠,然后兩個整合、協(xié)調(diào)一下货裹,計算一共要分配多大的空間嗤形,誰去申請這個空間,可能是根據(jù)自己寫的 record 大小來決定誰釋放這個空間(不過我感覺這種簡單的機(jī)制不靠譜弧圆,因為萬一來個調(diào)度赋兵,record 小的可能后做完,所以并不靠譜)搔预。做完之后霹期,繼續(xù)嘗試獲取鎖。這個時候再來個請求的話拯田,如上历造。
但是作者并沒有講一個 consolidation array 內(nèi)是怎么并發(fā)執(zhí)行對 buffer 的寫操作的,看圖的話應(yīng)該是并發(fā)執(zhí)行的船庇,但是 buffer 的執(zhí)行應(yīng)該是線性的吭产。感覺圖畫的有問題。個人理解是將多個寫操作合并成一個寫操作了鸭轮。
總之臣淤,只有第一個線程需要請求分配 buffer ,只有最后一個線程需要等待釋放 buffer张弛。但是也存在一個問題荒典,如果兩組線程先后嘗試寫 log,第一組的第一個線程鎖了 buffer 后吞鸭,寫很大一個 record,這時候第二組還是得等覆糟。并發(fā)性只是被保證在了同一組內(nèi)刻剥。
Decoupling Buffer Fill
因為 buffer fill 操作不是必須順序的 (records 不會重疊),并且有不同的耗時滩字,可以考慮把這些操作從關(guān)鍵路徑上移出來造虏。只要線程以 LSN 順序釋放它們寫入的區(qū)域,線程可以安全地以任意順序?qū)戇@些區(qū)域麦箍。
作者修改了原來的算法漓藕,線程一旦分配到 buffer 之后就釋放鎖。這樣做了之后挟裂,就要解決 buffer 釋放的問題享钞。Buffer 釋放的操作必須以 LSN 順序來避免在 record 之間產(chǎn)生 gap;Recovery 必須在遇到第一個 gap 的時候就停下來诀蓉,在一個 crash 中栗竖,gap 之后的操作都會丟失掉暑脆。雖然無鎖,但是每一個線程都必須等它前面的 region 被釋放之后才能釋放自己的 region狐肢。
這里的思想有點類似于樂觀鎖添吗。所有線程都先樂觀地寫,只有在需要同步的時候才同步份名,這里“同步”即是前面的 region 必須先寫完碟联。為什么要保證這個順序要求,可能是為了 crash failover 的考慮:如果用一個類似 CountDownLatch 的實現(xiàn)僵腺,一旦 crash鲤孵,因為不知道哪些寫完了,所以這個 CountDownLatch 上對應(yīng)的操作都得被作廢了想邦。如果保證以 LSN 順序來寫裤纹,哪里 crash 掉是知道的。
這樣一來丧没,就解決了第二組遇上一個寫大 record 的另一組線程鹰椒,必須一直等別人寫完才能自己開始寫的情況。并發(fā)性得到了提高呕童。
但是因為釋放操作有依賴關(guān)系漆际,整體上還是會被寫大 log 的拖累,可能會導(dǎo)致大量線程等著前序線程釋放夺饲。(這誰頂?shù)米“?jpg)
Putting it all Together: Hybrid Log Buffer
前面提到的包括兩個工作:
- 一個基于整合隊列的方法來減少進(jìn)入臨界區(qū)的線程數(shù)
- 一種分離策略使得線程能在臨界區(qū)外寫 log buffer
組合起來奸汇,就能使得整體性能相對來說,不對并發(fā)數(shù)和 log record 大小敏感往声。
下面解釋一下這個圖:
幾種優(yōu)化措施的原理和對耗時的影響
- (B) 是基準(zhǔn)對照擂找,箭頭入口表明操作被提交的時間,可見短時間內(nèi)來了三個操作浩销,第一個操作拿到鎖后贯涎,往 buffer 里寫,然后釋放慢洋;然后第二塘雳、第三個操作順序執(zhí)行。
- (C) 是采用了整合隊列后的示例普筹。這里第一個操作是第一組線程败明,因為這里只有它一個線程,申請分配 log space 是它太防,申請完了后寫 record 也是它妻顶,釋放鎖的還是它。
第二組操作等到第一組操作釋放鎖后,第二組操作所有的線程被組合成一個整合隊列盈包,由其中第一個線程去申請鎖沸呐,申請 log space,然后隊列里的線程以不知道的某種并發(fā)方式都開始往 buffer 里寫 record呢燥,然后最后一個寫完的釋放鎖崭添。 - (D) 是采用了分離 buffer insert 之后的示例。來一個請求叛氨,除了在申請分配 buffer 空間的時候經(jīng)歷短暫的串行執(zhí)行呼渣,就執(zhí)行一個請求。各自寫各自的區(qū)域寞埠,寫完了屁置,檢查一下前面的區(qū)域?qū)懲隂]有,沒寫完了就等仁连,寫完了就釋放自己寫的 region蓝角,這樣下一個寫完的線程才能釋放自己的 region。
- (CD) 組合兩種策略饭冬。與 D 類似辨绊,但是現(xiàn)在后面的兩個線程被劃分到同一個 consolidating array 里熊响,所以這兩個線程可以并發(fā)執(zhí)行寫 log 操作宙刘。
Performance Evaluation
略
Appendix
Details of the Log Buffer Algorithms
baseline
一個最簡單轨功、最直接的 log insert實現(xiàn)由以下幾個步驟組成:
- 獲取到一個全局鎖
- 進(jìn)入臨界區(qū)
2.1 一個線程申請分配 log buffer 空間
2.2 寫 record 到 buffer 里
2.3 釋放 buffer,增加一個專用指針的指炊苫,讓這次寫入操作對負(fù)責(zé) flush 的守護(hù)線程可見裁厅。 - 釋放鎖
這個算法有兩個問題:
- 競爭程度與工作線程數(shù)量線性相關(guān)
- 臨界區(qū)的(時間)長度與持有鎖的工作現(xiàn)場的工作量線性相關(guān)
Consolidation array
Consolidation-based backoff 目的是為了減少競爭,同時更重要的是侨艾,讓性能與訪問 log 的線程數(shù)無關(guān)执虹。
主要的數(shù)據(jù)結(jié)構(gòu)是一個固定大小的數(shù)組,用來讓線程合并請求唠梨。線程首先以非阻塞的方式請求鎖声畏,而不是無條件地等。什么意思呢姻成?如果成功了,那就直接執(zhí)行 log insert愿棋,與上面提到的算法一樣科展。如果失敗了,那么線程就回退到 consolidation array 糠雨,位置 index 用一個 offset 變量來表示才睹。
第一個進(jìn)入 consolidation array 的線程是這個 array 的擁有者,下面稱為 leader。所有在 array 里等待獲取鎖的線程是一個組琅攘,leader 繼續(xù)嘗試獲取鎖并一直阻塞垮庐。一旦進(jìn)入臨界區(qū),leader 讀取 group 的 size坞琴,通過一條原子寫操作標(biāo)記這個 array 已經(jīng)關(guān)閉了哨查。
leader 然后請求分配 buffer 空間,在開始寫 buffer 之前通知其它組員剧辐。同時寒亥,組內(nèi)的線程通過組大小來推測自己在 meta-request (TODO 沒看懂)中的相對位置。leader 匯報 LSN 和 buffer 的位置荧关,其余線程就可以計算自己的 LSN 和 buffer 的位置溉奕。每一個線程寫完自己的 record,就對 group 的 size 減1忍啤,返回加勤。最后一個返回的,即檢測到 size = 0 的同波,釋放掉 buffer 上的鎖(即全局鎖)鳄梅。
關(guān)閉后的 array 仍然不可被后續(xù)的線程訪問,因為要等 array 里的線程完成寫 record 操作参萄。為了避免新到的線程一直等著卫枝,在 array 關(guān)閉的時候,每個 slot 上的線程釋放掉 array 里的數(shù)據(jù)結(jié)構(gòu)讹挎,相當(dāng)于清空 array校赤,讓后續(xù)的線程可以進(jìn)入。
Decoupled buffer fill
分離 buffer 寫操作可以減少臨界區(qū)的(時間)長度筒溃,競爭的程度就不會隨著 log record 的大小的增長而加劇马篮。具體實現(xiàn)如下:
- 一個線程獲取到 log 的鎖,生成 LSN怜奖,分配 buffer 空間浑测。
- 釋放鎖
- 所有線程各自往自己的 region 里寫 log record。每個線程都自旋等待自己的前序 region 寫完后再釋放自己的 region歪玲。釋放操作就是將當(dāng)前寫完的 offset 增加迁央,其它線程通過對比 offset 來判斷前面的是否寫完了。
Consolidation-based Backoff
Slot Join Operation
slot_join 函數(shù)包括以下幾個步驟:
- 線程獲取到一個隨機(jī)的 offset滥崩,得到 array 里對應(yīng)的 slot 的數(shù)據(jù)結(jié)構(gòu)
- 查看 slot 是否 open岖圈,如果否的話,返回步驟 1 里钙皮,重新申請一個 slot蜂科。
這里引入了不確定性顽决,因為隨機(jī)到的 slot 開沒開完全取決于隨機(jī)到的 offset。
- open 后通過 CAS 來更新當(dāng)前 slot 的狀態(tài)导匣,表明被占用才菠。如果失敗的話,需要回退到步驟 2贡定。
- 返回 <slot, offset> pair赋访。
Slot close operation
在 leader 獲取到 buffer 的鎖后,關(guān)閉 group 來計算需要申請多大的 buffer厕氨,同時防止后續(xù)線程在已經(jīng)提交分配申請后又加入到 group 里进每。
這個操作是通過使用一個原子交換,返回當(dāng)前狀態(tài)命斧,并賦一個 PENDING 的新值田晚。這個狀態(tài)改變,會讓后續(xù)調(diào)用 slot_join 方法的線程都失敗国葬,但是大部分的線程不會遇到失敗的情況贤徒,因為一個 slot 關(guān)閉的時候,這個 slot 經(jīng)過短暫的操作汇四,前面已經(jīng)提到接奈,就把 slot 給空出來了。線程會試探整個 array通孽,直到找到一個空 slot序宦。因為 array 很大,所以基本上都能一發(fā)入魂背苦。TODO 沒看懂The pool allocation need not be atomic because the caller already holds the log mutex. 一個 slot 關(guān)閉后互捌,函數(shù)返回整個組的大小,用來讓調(diào)用者知道申請多少空間行剂。
Slot notify and wait operations
Slot release and free operations
Delegated Log Buffer Release and Skew
對線程釋放 buffer region 的順序要求秕噪,造成了一個潛在的性能問題。許多很小的寫操作可以跟很大的寫操作并發(fā)執(zhí)行厚宰,但是需要等大的寫完了才能釋放自己的 region腌巾。TODO 沒看懂 Buffer and log file wraparounds complicate matters further, because they prevent threads from consolidating buffer releases. 而這些 wrapping buffer 的釋放必須被識別出來并單獨處理,因為它們會在 log flush 的時候產(chǎn)生額外的工作铲觉。
TODO 沒看懂
CDME 算法比 CD 更健壯澈蝙,但是沒必要。幾乎所有 records 都很小且大 record 出現(xiàn)的頻率很低撵幽,在一般情況下碉克,因為復(fù)雜的實現(xiàn),反而會導(dǎo)致系統(tǒng)吞吐率的降低并齐。但是漏麦,對于一些奇奇怪怪的場景,這個算法還是提供穩(wěn)定的保證的况褪。
Sensitivity to consolidation array size
線程數(shù)與 consolidation array 的大小的關(guān)系撕贞。理想情況下,性能應(yīng)該只跟硬件有關(guān)测垛,而與線程數(shù)無關(guān)捏膨。線程很多的時候,實驗表明食侮,3-4 個 slots 最好号涯,文中用的 4 個;線程很少的時候锯七,這個時候無所謂链快。
原因:TODO 沒看懂 The optimal slot number corresponds closely with the number of threads required to saturate the baseline log which the consolidation array protects
A Case Against Distributed Logging
分布式的日志不適合用在數(shù)據(jù)庫中,因為依賴太多眉尸,幾乎無法有效地跟蹤域蜗。所以作者認(rèn)為,為了解決 log buffer 上的競爭噪猾,這個思路是 unattractive 和 unfeasible的霉祸。