internal TransactionService(IDiskService disk, PageService pager, CacheService cache) { _disk = disk; _pager = pager; _cache = cache; _cache.MarkAsDirtyAction = page => _disk.WriteJournal(page.PageID, page.DiskData); _cache.DirtyRecicleAction = () => Save(); }
internal TransactionService(IDiskService disk, PageService pager, CacheService cache) { _disk = disk; _pager = pager; _cache = cache; _cache.MarkAsDirtyAction = (page) => _disk.WriteJournal(page.PageID, page.DiskData); _cache.DirtyRecicleAction = () => this.Save(); }
/// <summary> /// Save all dirty pages to disk /// </summary> public void Commit() { // get header page var header = _pager.GetPage <HeaderPage>(0); // increase file changeID (back to 0 when overflow) header.ChangeID = header.ChangeID == ushort.MaxValue ? (ushort)0 : (ushort)(header.ChangeID + (ushort)1); // mark header as dirty _pager.SetDirty(header); // write journal file _disk.WriteJournal(_cache.GetDirtyPages() .Select(x => x.DiskData) .Where(x => x.Length > 0) .ToList(), header.LastPageID); // enter in exclusive lock mode to write on disk using (_locker.Exclusive()) { // set final datafile length (optimize page writes) _disk.SetLength(BasePage.GetSizeOfPages(header.LastPageID + 1)); foreach (var page in _cache.GetDirtyPages()) { // page.WritePage() updated DiskData with new rendered buffer var buffer = _crypto == null || page.PageID == 0 ? page.WritePage() : _crypto.Encrypt(page.WritePage()); _disk.WritePage(page.PageID, buffer); } // mark all dirty pages in clean pages (all are persisted in disk and are valid pages) _cache.MarkDirtyAsClean(); // ensure all pages from OS cache has been persisted on medium _disk.Flush(); // discard journal file _disk.ClearJournal(header.LastPageID); } }
/// <summary> /// Checkpoint is a safe point to clear cache pages without loose pages references. /// Is called after each document insert/update/deleted/indexed/fetch from query /// </summary> public void CheckPoint() { // works only when journal are enabled if (_disk.IsJournalEnabled && _pager.CachePageCount >= _cacheSize) { _log.Write(Logger.CACHE, "cache checkpoint reached at {0} pages in cache", _pager.CachePageCount); // write all dirty pages in data file (journal foreach (var page in _pager.GetDirtyPages()) { // first write in journal file original data _disk.WriteJournal(page.PageID, page.DiskData); // then writes no datafile new changed pages _disk.WritePage(page.PageID, page.WritePage()); } // empty all cache pages _pager.ClearCache(); } }
/// <summary> /// Save all dirty pages to disk /// </summary> public void PersistDirtyPages() { // get header page var header = _pager.GetPage <HeaderPage>(0); // increase file changeID (back to 0 when overflow) header.ChangeID = header.ChangeID == ushort.MaxValue ? (ushort)0 : (ushort)(header.ChangeID + (ushort)1); // mark header as dirty _pager.SetDirty(header); _log.Write(Logger.DISK, "begin disk operations - changeID: {0}", header.ChangeID); // write journal file in desc order to header be last page in disk _disk.WriteJournal(_cache.GetDirtyPages() .OrderByDescending(x => x.PageID) .Select(x => x.DiskData) .Where(x => x.Length > 0) .ToList(), header.LastPageID); // mark header as recovery before start writing (in journal, must keep recovery = false) header.Recovery = true; // get all dirty page stating from Header page (SortedList) foreach (var page in _cache.GetDirtyPages()) { // page.WritePage() updated DiskData with new rendered buffer var buffer = _crypto == null || page.PageID == 0 ? page.WritePage() : _crypto.Encrypt(page.WritePage()); _disk.WritePage(page.PageID, buffer); } // re-write header page but now with recovery=false header.Recovery = false; _log.Write(Logger.DISK, "re-write header page now with recovery = false"); _disk.WritePage(0, header.WritePage()); // mark all dirty pages as clean pages (all are persisted in disk and are valid pages) _cache.MarkDirtyAsClean(); // flush all data direct to disk _disk.Flush(); // discard journal file _disk.ClearJournal(header.LastPageID); }
/// <summary> /// Save all dirty pages to disk /// </summary> public void PersistDirtyPages() { // get header page var header = _pager.GetPage <HeaderPage>(0); // increase file changeID (back to 0 when overflow) header.ChangeID = header.ChangeID == ushort.MaxValue ? (ushort)0 : (ushort)(header.ChangeID + (ushort)1); // mark header as dirty _pager.SetDirty(header); _log.Write(Logger.DISK, "begin disk operations - changeID: {0}", header.ChangeID); // write journal file in desc order to header be last page in disk if (_disk.IsJournalEnabled) { _disk.WriteJournal(_cache.GetDirtyPages() .OrderByDescending(x => x.PageID) .Select(x => x.DiskData) .Where(x => x.Length > 0) .ToList(), header.LastPageID); // mark header as recovery before start writing (in journal, must keep recovery = false) header.Recovery = true; // flush to disk to ensure journal is committed to disk before proceeding _disk.Flush(); } else { // if no journal extend, resize file here to fast writes _disk.SetLength(BasePage.GetSizeOfPages(header.LastPageID + 1)); } // write header page first. if header.Recovery == true, this ensures it's written to disk *before* we start changing pages var headerPage = _cache.GetPage(0); var headerBuffer = headerPage.WritePage(); _disk.WritePage(0, headerBuffer); _disk.Flush(); // get all dirty page stating from Header page (SortedList) // header page (id=0) always must be first page to write on disk because it's will mark disk as "in recovery" foreach (var page in _cache.GetDirtyPages()) { // we've already written the header, so skip it if (page.PageID == 0) { continue; } // page.WritePage() updated DiskData with new rendered buffer var buffer = _crypto == null || page.PageID == 0 ? page.WritePage() : _crypto.Encrypt(page.WritePage()); _disk.WritePage(page.PageID, buffer); } if (_disk.IsJournalEnabled) { // ensure changed pages are persisted to disk _disk.Flush(); // re-write header page but now with recovery=false header.Recovery = false; _log.Write(Logger.DISK, "re-write header page now with recovery = false"); _disk.WritePage(0, header.WritePage()); } // mark all dirty pages as clean pages (all are persisted in disk and are valid pages) _cache.MarkDirtyAsClean(); // flush all data direct to disk _disk.Flush(); // discard journal file _disk.ClearJournal(header.LastPageID); }