最近看了一個(gè)用go寫的數(shù)據(jù)庫(kù)NYADB2娇唯,
github地址:https://github.com/qw4990/NYADB2。
看到作者關(guān)于存儲(chǔ)模塊的緩存用了引用計(jì)數(shù)法來(lái)寫强胰,而不是常用的LRU算法伴逸。
他在緩存部分用了二級(jí)緩存。
第一級(jí)是page緩存维蒙,在內(nèi)存維持page,實(shí)質(zhì)是byte[]果覆,每個(gè)page都有一個(gè)引用數(shù)p木西,每次引用page,p++随静,釋放page,p--吗讶。一旦p==0燎猛,就把page寫回磁盤(page臟時(shí)),在內(nèi)存中釋放page照皆。
第二級(jí)緩存是dataItem緩存重绷,這里的dataItem實(shí)質(zhì)上是切片(切片是go的一種內(nèi)置結(jié)構(gòu))對(duì)page中一段字節(jié)數(shù)組的引用,并沒(méi)有實(shí)質(zhì)上的緩存膜毁。這里同樣是引用計(jì)數(shù)法昭卓,只不過(guò),當(dāng)p==0時(shí)瘟滨,只是把切片釋放了而已候醒。
在這里作者用了一個(gè)很漂亮的寫法,獨(dú)立寫了一個(gè)引用計(jì)數(shù)法的緩存模塊杂瘸,把緩存的對(duì)象和use緩存和release緩存的接口留了出來(lái)倒淫,所以這里的page緩存和dataItem緩存都是用這個(gè)緩存模塊做的。
整個(gè)使用緩存的流程是
1.查找dataItem(簡(jiǎn)寫為d)-->
2.dataItem緩存存在d,直接返回d,不存在d時(shí),在dataItem緩存中創(chuàng)建d緩存-->
3.創(chuàng)建d緩存會(huì)從其所在的page(簡(jiǎn)寫為p)中創(chuàng)建切片,若page緩存中不存在p,創(chuàng)建p緩存
4.創(chuàng)建p緩存,即從磁盤中寫出相應(yīng)的page
一個(gè)緩存要能維持在內(nèi)存中败玉,那么它的引用數(shù)就必須一直滿足>=1敌土,且不能中斷,即是每時(shí)每刻都有對(duì)緩存的引用运翼,這就意味著返干,如果對(duì)數(shù)據(jù)庫(kù)的訪問(wèn)頻率不夠高,那么引用計(jì)數(shù)法寫的緩存是無(wú)效的血淌【厍罚可想而知,用引用計(jì)數(shù)法寫的緩存一般比用LRU寫的緩存,緩存數(shù)不夠晚顷。
所以在p--的時(shí)候可以考慮異步延遲峰伙,延遲時(shí)間由當(dāng)前緩存數(shù)量決定。其次在這里我認(rèn)為用引用計(jì)數(shù)法寫page緩存并不是一個(gè)好選擇该默,因?yàn)榧僭O(shè)有10%的數(shù)據(jù)(訪問(wèn)頻率夠高)一直被緩存瞳氓,就意味著,那10%數(shù)據(jù)對(duì)應(yīng)的page也會(huì)一直維持在內(nèi)存栓袖。如果這10%的數(shù)據(jù)分步在所有的page中匣摘,那么所有的page都會(huì)維持在緩存,那所謂的分頁(yè)管理就沒(méi)有意義了裹刮。
用引用計(jì)數(shù)法寫可以很容易把鎖表和緩存結(jié)合音榜,在實(shí)現(xiàn)諸如b-link-tree之類需要節(jié)點(diǎn)加讀寫鎖的索引結(jié)構(gòu)時(shí)很方便。