public override void Read(long pageNumber, byte[] buffer, int offset) { lock (journalMap) { if (!dataOpen) { throw new IOException("Assertion failed: Data file is not open."); } } // The list of all journal entries on this page number var allJournalEntries = new List <JournalEntry>(4); try { // The map index. lock (journalMap) { int i = ((int)(pageNumber & 0x0FFFFFFF) % journalMap.Length); var entry = journalMap[i]; JournalEntry prev = null; while (entry != null) { bool deletedHash = false; JournalFile file = entry.File; // Note that once we have a reference the journal file can not be // deleted. file.Reference(); // If the file is closed (or deleted) if (file.IsDeleted) { deletedHash = true; // Deleted so remove the reference to the journal file.Dereference(); // Remove the journal entry from the chain. if (prev == null) { journalMap[i] = entry.Next; } else { prev.Next = entry.Next; } } // Else if not closed then is this entry the page number? else if (entry.PageNumber == pageNumber) { allJournalEntries.Add(entry); } else { // Not the page we are looking for so remove the reference to the // file. file.Dereference(); } // Only move prev is we have NOT deleted a hash entry if (!deletedHash) { prev = entry; } entry = entry.Next; } } // Read any data from the underlying file if (thereIsBackingData) { long pagePosition = pageNumber * JournaledSystem.PageSize; // First Read the page from the underlying store. Data.Read(pagePosition, buffer, offset, JournaledSystem.PageSize); } else { // Clear the buffer for (int i = offset; i < (JournaledSystem.PageSize + offset); ++i) { buffer[i] = 0; } } // Rebuild from the journal file(s) int sz = allJournalEntries.Count; for (int i = 0; i < sz; ++i) { var entry = allJournalEntries[i]; var file = entry.File; long position = entry.Position; lock (file) { file.BuildPage(pageNumber, position, buffer, offset); } } } finally { // Make sure we remove the reference for all the journal files. int sz = allJournalEntries.Count; for (int i = 0; i < sz; ++i) { var entry = allJournalEntries[i]; JournalFile file = entry.File; file.Dereference(); } } }
public override void Write(long pageNumber, byte[] buffer, int offset, int count) { lock (journalMap) { if (!dataOpen) { throw new IOException("Assertion failed: Data file is not open."); } // Make this modification input the log var journal = JournaledSystem.LogPageModification(Name, pageNumber, buffer, offset, count); // This adds the modification to the END of the hash list. This means // when we reconstruct the page the journals will always be input the // correct order - from oldest to newest. // The map index. int i = ((int)(pageNumber & 0x0FFFFFFF) % journalMap.Length); var entry = journalMap[i]; // Make sure this entry is added to the END if (entry == null) { // Add at the head if no first entry journalMap[i] = journal; journal.Next = null; } else { // Otherwise search to the end // The number of journal entries input the linked list int journalEntryCount = 0; while (entry.Next != null) { entry = entry.Next; ++journalEntryCount; } // and add to the end entry.Next = journal; journal.Next = null; // If there are over 35 journal entries, scan and remove all entries // on journals that have persisted if (journalEntryCount > 35) { entry = journalMap[i]; JournalEntry prev = null; while (entry != null) { bool deletedHash = false; JournalFile file = entry.File; // Note that once we have a reference the journal file can not be // deleted. file.Reference(); // If the file is closed (or deleted) if (file.IsDeleted) { deletedHash = true; // Deleted so remove the reference to the journal file.Dereference(); // Remove the journal entry from the chain. if (prev == null) { journalMap[i] = entry.Next; } else { prev.Next = entry.Next; } } // Remove the reference file.Dereference(); // Only move prev is we have NOT deleted a hash entry if (!deletedHash) { prev = entry; } entry = entry.Next; } } } } }