Log包中包含三個類,依次是BasicLogRecord,LogIterator,LogMgr
BasicLogRecord 提供的是一種基礎的日誌記錄。含有的成員對象是Page和Pos,它所完成的功能就是定位Page,定位Offset,然後提供讀寫記錄的方法。
LogMgr,底層的日誌管理器,只是負責日誌記錄的讀寫,它自己並不知道所寫的日誌的記錄的內容是什麼。所謂較進階的日誌管理器是指復原管理員,它可以明確的知道所寫的日誌記錄的內容。
LogIterator,日誌迭代器,提供關於遍曆記錄檔的方法,比如hasNext(),next(),moveToNextBlock()。
在Log包中最核心的東西是日誌的記錄方式。日誌在記錄的時候是從前往後記錄的,但是在讀的時候卻是以相反的方向進行的。在作者所維護的這種機制下,能夠實現這種功能的秘密在於它獨特的日誌記錄的方式。
上面的就是在Log檔案中所具有的記錄的格式。
它是什麼意思呢?
首先,在初始化的時候,在每個Block的開頭都先寫入一個LAST_POS值為0。然後,就開始寫入日誌記錄。關鍵的部分是在寫完日誌之後。在寫完每條日誌之後,會加上一個便宜量,這個位移量用來記錄前一條記錄的offset。
在詳細介紹這個offset之前,需要看幾行代碼:(用以添加記錄)
根據上面的代碼,可以看出,這裡的“記錄”是記錄內容和offset的結合體,在計算空間的時候,會自動加上在記錄結尾offset所需要的空間。
在寫完一條記錄值之後,currentpos的值是真正記錄結束後的便宜,不包含前一條記錄的offset。
利用finalizeRecord來設定offset。
以上的三條語句:
1> 把LAST_POS的值卸載記錄的後面,實際上就是給offset賦值
2> 把currentpos賦值給LAST_POS
3> 給currentpos加上4,跳過offset
通過以上的介紹,很容易明白記錄offset的過程,下面,再看下LogeIterator中的next(),我們從讀記錄的角度,理解下這種記錄方式。
在讀記錄的時候,首先,定位currenrec,這裡是讀取LAST_POS,這樣,就從頭直接到了Block的尾部了,此時currenrec的值是最後一條記錄的offset的pos;然後利用一句“currentrec = pg.getInt(LogMgr.LAST_POS);”,得到的是倒數第二條記錄的offset,在這個情況下,實際上已經從最後一條移動到倒數第二條,這樣就是REVERSE了,在擷取記錄值得時候,“currentrec + ConstantValue.INT_SIZE”,就定位到了最後一條記錄的位置了,讀取完成。
現在看來,實際上,早這個所謂的REVERSE機制中,所用的與原理就是“C++中鏈表的後向插入”,自然能夠REVERSE讀取了。LogRecord記錄相當於鏈表的DataElem而已。只是,由於Java中沒有指標,這裡是利用位移來是虛擬指標罷了。