/// <summary> /// Clear WAL index links and cache memory. Used after checkpoint and rebuild rollback /// </summary> public void Clear(bool crop) { _indexLock.TryEnterWriteLock(-1); try { // reset _confirmTransactions.Clear(); _index.Clear(); _lastTransactionID = 0; _currentReadVersion = 0; // clear cache _disk.Cache.Clear(); // clear log file (sync) and shrink database _disk.ResetLogPosition(crop); } finally { _indexLock.ExitWriteLock(); } }
/// <summary> /// Do checkpoint operation to copy log pages into data file. Return how many pages as saved into data file /// Soft checkpoint try execute only if there is no one using (try exclusive lock - if not possible just exit) /// If crop = true, reduce data file removing all log area. If not, keeps file with same size and clean all isConfirmed pages /// </summary> public async Task <int> Checkpoint() { LOG($"checkpoint", "WAL"); var counter = 0; // getting all "good" pages from log file to be copied into data file async IAsyncEnumerable <PageBuffer> source() { // collect all isConfirmedPages var confirmedPages = new List <long>(); var finalDataPosition = (_disk.Header.LastPageID + 1) * PAGE_SIZE; await foreach (var buffer in _disk.ReadLog(false)) { // read direct from buffer to avoid create BasePage structure var transactionID = buffer.ReadUInt32(BasePage.P_TRANSACTION_ID); // only confirmed pages can be write on data disk if (_confirmTransactions.Contains(transactionID)) { // if page is confirmed page and are after data area, add to list var isConfirmed = buffer.ReadBool(BasePage.P_IS_CONFIRMED); if (isConfirmed && buffer.Position >= finalDataPosition) { confirmedPages.Add(buffer.Position); } // clear isConfirmed/transactionID buffer.Write(uint.MaxValue, BasePage.P_TRANSACTION_ID); buffer.Write(false, BasePage.P_IS_CONFIRMED); // update buffer position to data area position var pageID = buffer.ReadUInt32(BasePage.P_PAGE_ID); buffer.Position = BasePage.GetPagePosition(pageID); counter++; yield return(buffer); } } } // write all log pages into data file (sync) await _disk.WriteDataPages(source()); // clear log file, clear wal index, memory cache, _confirmTransactions.Clear(); _index.Clear(); _lastTransactionID = 0; _currentReadVersion = 0; // clear cache _disk.Cache.Clear(); _disk.ResetLogPosition(true); return(counter); }