公司主營(yíng)業(yè)務(wù):成都做網(wǎng)站、成都網(wǎng)站設(shè)計(jì)、成都外貿(mào)網(wǎng)站建設(shè)、移動(dòng)網(wǎng)站開(kāi)發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開(kāi)放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來(lái)的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來(lái)驚喜。創(chuàng)新互聯(lián)推出光明免費(fèi)做網(wǎng)站回饋大家。
1、Buffer由數(shù)組BufferDescriptor[]數(shù)組進(jìn)行管理。該數(shù)組由函數(shù)InitBufferPool創(chuàng)建,大小為NBuffers個(gè)成員即BufferDesc。該數(shù)組創(chuàng)建后由StrategyControl進(jìn)行管理,firstFreeBuffer為鏈表頭,指向鏈表第一個(gè)成員;lastFreeBuffer指向鏈表尾;所有free list中成員由freeNext串起來(lái),該值為數(shù)組下標(biāo)。
BufferDescriptor數(shù)組是共享內(nèi)存中申請(qǐng),所有進(jìn)程共享??梢钥吹絻蓚€(gè)進(jìn)程的BufferDescriptors地址相同:
進(jìn)程1: (gdb) p BufferDescriptors $1 = (BufferDescPadded *) 0xa615fb80 (gdb) p *BufferDescriptors $2 = {bufferdesc = {tag = {rnode = {spcNode = 1664, dbNode = 0, relNode = 1262}, forkNum = MAIN_FORKNUM, blockNum = 0}, buf_id = 0, state = {value = 2199126016}, wait_backend_pid = 0, freeNext = -2, content_lock = {tranche = 53, state = {value = 536870912}, waiters = { head = 2147483647, tail = 2147483647}}}, pad = "\200"} 進(jìn)程2: (gdb) p BufferDescriptors $1 = (BufferDescPadded *) 0xa615fb80 (gdb) p *BufferDescriptors $2 = {bufferdesc = {tag = {rnode = {spcNode = 1664, dbNode = 0, relNode = 1262}, forkNum = MAIN_FORKNUM, blockNum = 0}, buf_id = 0, state = {value = 2199126016}, wait_backend_pid = 0, freeNext = -2, content_lock = {tranche = 53, state = {value = 536870912}, waiters = { head = 2147483647, tail = 2147483647}}}, pad = "\200"}
2、同時(shí)還會(huì)通過(guò)一個(gè)環(huán)形區(qū)進(jìn)行管理這些數(shù)組成員。當(dāng)進(jìn)行大表掃描時(shí)使用。由strategy->buffers[]數(shù)組管理,該數(shù)組存儲(chǔ)的是BufferDescriptors[]數(shù)組的下標(biāo)+1后的值,而每次取buf描述符時(shí),從strategy->current值開(kāi)始進(jìn)行選擇。選出的不可用后,依次向后進(jìn)行遍歷,遍歷到頭后從頭再來(lái)進(jìn)行選擇,即形成一個(gè)環(huán)。是否可用的標(biāo)準(zhǔn)后文詳述。
下面說(shuō)下BufferDesc成員變量:
BufferTag tag為一個(gè)描述符對(duì)應(yīng)磁盤物理頁(yè)的映射。即space ID+database ID+文件ID -- forkNum(表文件還是fsm文件或者vm文件)-- 頁(yè)號(hào)
buf_id為buffer數(shù)組BufferBlocks[]的下標(biāo)
state為狀態(tài)標(biāo)記,包括該buffer的refcount和usagecount以及是否合法valid等待
wait_backend_pid:若進(jìn)程A需要?jiǎng)h除的元組所在緩沖塊有其他進(jìn)程訪問(wèn),即refcount>0時(shí),進(jìn)程A不能物理上刪除元組。系統(tǒng)將該進(jìn)程的ID記錄在wait_backend_id上,然后對(duì)緩沖塊加pin,并阻塞自己。當(dāng)refcount為1時(shí)最后一個(gè)使用該緩沖塊的進(jìn)程釋放緩沖區(qū)時(shí),會(huì)向wait_backend_id進(jìn)程發(fā)送消息。
FreeNext為鏈表的下一個(gè)節(jié)點(diǎn)的下標(biāo)
content_lock為buffer鎖,當(dāng)進(jìn)程訪問(wèn)緩沖塊時(shí)加鎖,讀加LW_SHARE鎖,寫加LW_EXCLUSIVE鎖
二、共享buffer分配機(jī)制
1、前期準(zhǔn)備:
1)該buffer分配有4種情況:從hash表SharedBufHash中查找;從環(huán)形緩沖區(qū)查找;從free list查找以及驅(qū)逐策略進(jìn)行分配。
2)hash表SharedBufHash同樣是共享內(nèi)存全局的,所有進(jìn)程公有。下面分別是兩個(gè)會(huì)話連接的server端進(jìn)程打印出的hash表。
(gdb) p SharedBufHash $1 = (HTAB *) 0x87f5b04 (gdb) p SharedBufHash $1 = (HTAB *) 0x87f5b04
3)該hash表同樣在InitBufferPool中進(jìn)行創(chuàng)建:
StrategyInitialize->InitBufTable(NBuffers + NUM_BUFFER_PARTITIONS)-> SharedBufHash = ShmemInitHash
4)該hash表中條目為:[BufferTag,id]即key值為物理磁盤頁(yè)的標(biāo)志,id為對(duì)應(yīng)buffer的ID
5)首先需要?jiǎng)?chuàng)建一個(gè)newTag,對(duì)應(yīng)物理文件的一個(gè)頁(yè)
6)通過(guò)newTag到函數(shù)BufTableHashCode中計(jì)算hash表的key值newHash
7)共有128個(gè)buffer partition鎖,通過(guò)hash的key值以輪詢的方式取鎖
8)此時(shí)對(duì)key值對(duì)應(yīng)的buffer partition加LW_SHARED鎖
2、此時(shí)進(jìn)入第一種獲取buffer描述符的方法:所有進(jìn)程共享的SharedBufHash
1)根據(jù)newTag從hash表SharedBufHash中查找對(duì)應(yīng)的buffer
2)buf_id>0則表示數(shù)據(jù)頁(yè)在hash表中找到,即對(duì)應(yīng)數(shù)據(jù)頁(yè)以加載到內(nèi)存
3)根據(jù)buf_id獲取buffer的描述符BufferDescriptors[buf_id)].bufferdesc
4)通過(guò)函數(shù)PinBuffer將對(duì)應(yīng)buffer pin住,然后就可以將buffer的partition鎖釋放
即,將buf的state的refcount+1,usagecount根據(jù)情況+1,具體流程下文分析。
5)pin失敗,通過(guò)StartBufferIO判斷,返回TRUE,緩沖區(qū)無(wú)效,此時(shí)foundPtr為false,并返回對(duì)應(yīng)buf;返回false,表示別人正在使用,直接返回對(duì)應(yīng)buf。foundPtr表示是否在緩沖區(qū)命中
3、若hash表中不存在,則需要從磁盤讀取。首先釋放buf的partition鎖,進(jìn)入循環(huán)。
1)StrategyGetBuffer取出一個(gè)buf描述符,具體原理見(jiàn)下文。
2)PinBuffer_Locked將buf的refcount+1
3)此時(shí)該buf為臟塊BM_DIRTY,則對(duì)buf->content_lock加LW_SHARED鎖,加鎖失敗釋放pin,返回1)。加鎖成功根據(jù)strategy是否為空處理。
4)使用環(huán)形緩沖區(qū),即strategy不為空:BM_LOCKED鎖內(nèi)獲取buf臟頁(yè)的lsn,根據(jù)lsn判斷其日志是否已經(jīng)刷寫到磁盤,若未則將該buf從環(huán)形緩沖區(qū)刪除;釋放buf->content_lock鎖及pin,返回1)重新循環(huán)進(jìn)行選擇。
5)使用環(huán)形緩沖區(qū)且日志已刷或者未使用環(huán)形緩沖區(qū),則調(diào)用FlushBuffer將臟數(shù)據(jù)刷寫磁盤,最后釋放buf->content_lock鎖。
6)接著進(jìn)入4,當(dāng)該頁(yè)不為臟時(shí)也進(jìn)入4
4、替換為自己的tag
1)先獲取buf的oldTag,是誰(shuí)用過(guò)。其oldPartitionLock和newTag的newPartitionLock按順序加鎖,若同一個(gè)則只加一個(gè)鎖。LW_EXCUSIVE
2)將newTag對(duì)應(yīng)的條目插入到hash表SharedBufHash
3)buf_id>=0,表示該條目已在hash表,那么unpin、oldPartitionLock鎖釋放后,獲取老buf,pin后釋放newPartitionLock
4)pin失敗,通過(guò)StartBufferIO判斷,返回TRUE,緩沖區(qū)無(wú)效,此時(shí)foundPtr為false,并返回對(duì)應(yīng)buf;返回false,表示別人正在使用,直接返回對(duì)應(yīng)buf。foundPtr表示是否在緩沖區(qū)命中 5)buf_id<0,即未在hash表SharedBufHash:buf_state的refcount==1且不為BM_DIRTY,表示無(wú)人使用該buf,退出循環(huán),將buf->tag=newTag,最后釋放相關(guān)鎖
6)否則,需要釋放相關(guān)鎖,并將newTag對(duì)應(yīng)的條目從hash表刪除后,重新回到3進(jìn)行選擇。
1、若buffer的state已為BM_LOCKED即已加鎖,則需等待,該鎖是pin鎖
2、GetPrivateRefCountEntry獲取ref,若ref不為NULL,則表示別人在使用,然后TRUE。是這樣理解嗎?需要理解這個(gè)函數(shù)
3、原子操作讀取state值old_buf_state,并將之保存為buf_state
4、buf_state的refcount+1
5、默認(rèn)策略下,即從free list中選擇空閑描述符,buf_state的usagecount+1;環(huán)形緩沖區(qū)策略下,buf_state的usagecount保持為1
6、通過(guò)CAS操作將buf->state的值替換為buf_state的值
7、函數(shù)返回TRUE表示該buffer的數(shù)據(jù)有效,即合法的數(shù)據(jù)已經(jīng)加載到內(nèi)存;返回false表示數(shù)據(jù)無(wú)效,即數(shù)據(jù)未加載到內(nèi)存
1、每個(gè)buffer都有一個(gè)IO鎖(BufferIOLWLockArray[(bdesc)->buf_id]).lock
2、獲取buf_state狀態(tài),需要先將其置為BM_LOCKED
3、該buf此時(shí)已為BM_IO_IN_PROGRESS,即正在讀寫,需要將上面兩個(gè)鎖釋放后WaitIO等待狀態(tài)變化
4、forInput為TRUE:要向里面寫,需要其為!BM_VALID,若是BM_VALID表示有人已經(jīng)向里寫了合法數(shù)據(jù);FALSE:需要向外讀,若為!BM_DIRTY表示已有人刷寫了。釋放兩個(gè)鎖返回
5、將buf_state置為BM_IO_IN_PROGRESS。
6、返回TRUE,表示buf中數(shù)據(jù)無(wú)效,可以使用。False,表示別人正在使用
1、如果使用strategy,則從環(huán)形緩沖區(qū)取一個(gè)空閑的描述符:bufnum=strategy->buffers[strategy->current];buf = GetBufferDescriptor(bufnum - 1);,若沒(méi)有可用的則GetBufferFromRing返回NULL,否則直接返回該buf。
2、環(huán)形緩沖區(qū)取buffer失敗,則去free list取
3、StrategyControl->firstFreeBuffer>0,此時(shí)list不為空,
4、則先申請(qǐng)spin鎖StrategyControl->buffer_strategy_lock,再次判斷鏈表情況,若StrategyControl->firstFreeBuffer<0鏈表空了,則釋放鎖后退出循環(huán),進(jìn)入第8步
5、獲取StrategyControl->firstFreeBuffer指向的buffer描述符,并將該節(jié)點(diǎn)從free list刪除
6、釋放StrategyControl->buffer_strategy_lock鎖
7、該buf的refcount和usagecount都為0,則表示我們可以用,若strategy不為NULL,則現(xiàn)將該buf放到環(huán)形緩沖區(qū),返回該buffer描述符;否則再次到第4步循環(huán)
8、此時(shí)free list都取了一遍,但是沒(méi)有可用的,通過(guò)時(shí)鐘算法,即循環(huán)StrategyControl->nextVictimBuffer取該buf,看其是否可用。同樣如果找到后,根據(jù)strategy是否為NULL,將其放到環(huán)形緩沖區(qū)。將所有buf都取了一遍后,仍沒(méi)有可用的話就報(bào)錯(cuò):no unpinned buffers available