/// <summary> /// Load all confirmed transactions from log file (used only when open datafile) /// Don't need lock because it's called on ctor of LiteEngine /// Update _disk instance with last log position /// </summary> public void RestoreIndex(HeaderPage header) { // get all page positions var positions = new Dictionary <long, List <PagePosition> >(); var last = 0L; // read all pages to get confirmed transactions (do not read page content, only page header) foreach (var buffer in _disk.ReadLog(true)) { // read direct from buffer to avoid create BasePage structure var pageID = buffer.ReadUInt32(BasePage.P_PAGE_ID); var isConfirmed = buffer.ReadBool(BasePage.P_IS_CONFIRMED); var transactionID = buffer.ReadUInt32(BasePage.P_TRANSACTION_ID); if (transactionID == 0 || transactionID == uint.MaxValue) { continue; } var position = new PagePosition(pageID, buffer.Position); if (positions.TryGetValue(transactionID, out var list)) { list.Add(position); } else { positions[transactionID] = new List <PagePosition> { position }; } if (isConfirmed) { // update last IsConfirmed page last = buffer.Position; this.ConfirmTransaction(transactionID, positions[transactionID]); var pageType = (PageType)buffer.ReadByte(BasePage.P_PAGE_TYPE); // when a header is modified in transaction, must always be the last page inside log file (per transaction) if (pageType == PageType.Header) { // copy this buffer block into original header block Buffer.BlockCopy(buffer.Array, buffer.Offset, header.Buffer.Array, header.Buffer.Offset, PAGE_SIZE); header.LoadPage(); } } // update last transaction ID _lastTransactionID = (int)transactionID; } // update last log position acording with last IsConfirmed on log if (last > 0) { _disk.LogEndPosition = last + PAGE_SIZE; } }