/// <summary> /// Retrieve physical address of next iterator value /// (under epoch protection if it is from main page buffer) /// </summary> /// <param name="physicalAddress"></param> /// <param name="entryLength"></param> /// <param name="epochTaken"></param> /// <returns></returns> private unsafe bool GetNextInternal(out long physicalAddress, out int entryLength, out bool epochTaken) { physicalAddress = 0; entryLength = 0; epochTaken = false; currentAddress = nextAddress; while (true) { // Check for boundary conditions if (currentAddress < allocator.BeginAddress) { Debug.WriteLine("Iterator address is less than log BeginAddress " + allocator.BeginAddress + ", adjusting iterator address"); currentAddress = allocator.BeginAddress; } if ((currentAddress >= endAddress) || (currentAddress >= fasterLog.CommittedUntilAddress)) { nextAddress = currentAddress; return(false); } if (frameSize == 0 && currentAddress < allocator.HeadAddress) { throw new Exception("Iterator address is less than log HeadAddress in memory-scan mode"); } var currentPage = currentAddress >> allocator.LogPageSizeBits; var offset = currentAddress & allocator.PageSizeMask; var headAddress = allocator.HeadAddress; if (currentAddress < headAddress) { BufferAndLoad(currentAddress, currentPage, currentPage % frameSize); physicalAddress = frame.GetPhysicalAddress(currentPage % frameSize, offset); } else { epoch.Resume(); headAddress = allocator.HeadAddress; if (currentAddress < headAddress) // rare case { epoch.Suspend(); continue; } physicalAddress = allocator.GetPhysicalAddress(currentAddress); } // Get and check entry length entryLength = fasterLog.GetLength((byte *)physicalAddress); if (entryLength == 0) { if (currentAddress >= headAddress) { epoch.Suspend(); } nextAddress = (1 + (currentAddress >> allocator.LogPageSizeBits)) << allocator.LogPageSizeBits; if (0 != fasterLog.GetChecksum((byte *)physicalAddress)) { var curPage = currentAddress >> allocator.LogPageSizeBits; throw new Exception("Invalid checksum found during scan, skipping page " + curPage); } else { // We are likely at end of page, skip to next currentAddress = nextAddress; continue; } } int recordSize = headerSize + Align(entryLength); if ((currentAddress & allocator.PageSizeMask) + recordSize > allocator.PageSize) { if (currentAddress >= headAddress) { epoch.Suspend(); } nextAddress = (1 + (currentAddress >> allocator.LogPageSizeBits)) << allocator.LogPageSizeBits; throw new Exception("Invalid length of record found: " + entryLength + ", skipping page"); } // Verify checksum if needed if (currentAddress < headAddress) { if (!fasterLog.VerifyChecksum((byte *)physicalAddress, entryLength)) { var curPage = currentAddress >> allocator.LogPageSizeBits; nextAddress = (1 + (currentAddress >> allocator.LogPageSizeBits)) << allocator.LogPageSizeBits; throw new Exception("Invalid checksum found during scan, skipping page " + curPage); } } if ((currentAddress & allocator.PageSizeMask) + recordSize == allocator.PageSize) { nextAddress = (1 + (currentAddress >> allocator.LogPageSizeBits)) << allocator.LogPageSizeBits; } else { nextAddress = currentAddress + recordSize; } epochTaken = currentAddress >= headAddress; return(true); } }
/// <summary> /// Retrieve physical address of next iterator value /// (under epoch protection if it is from main page buffer) /// </summary> /// <param name="physicalAddress"></param> /// <param name="entryLength"></param> /// <param name="currentAddress"></param> /// <param name="nextAddress"></param> /// <returns></returns> private unsafe bool GetNextInternal(out long physicalAddress, out int entryLength, out long currentAddress, out long nextAddress) { while (true) { physicalAddress = 0; entryLength = 0; currentAddress = NextAddress; nextAddress = NextAddress; // Check for boundary conditions if (currentAddress < allocator.BeginAddress) { currentAddress = allocator.BeginAddress; } var _currentPage = currentAddress >> allocator.LogPageSizeBits; var _currentFrame = _currentPage % frameSize; var _currentOffset = currentAddress & allocator.PageSizeMask; var _headAddress = allocator.HeadAddress; if (disposed) { return(false); } if ((currentAddress >= endAddress) || (currentAddress >= fasterLog.CommittedUntilAddress)) { return(false); } if (currentAddress < _headAddress) { if (BufferAndLoad(currentAddress, _currentPage, _currentFrame, _headAddress)) { continue; } physicalAddress = frame.GetPhysicalAddress(_currentFrame, _currentOffset); } else { physicalAddress = allocator.GetPhysicalAddress(currentAddress); } // Get and check entry length entryLength = fasterLog.GetLength((byte *)physicalAddress); if (entryLength == 0) { // We are likely at end of page, skip to next currentAddress = (1 + (currentAddress >> allocator.LogPageSizeBits)) << allocator.LogPageSizeBits; Utility.MonotonicUpdate(ref NextAddress, currentAddress, out _); if (0 != fasterLog.GetChecksum((byte *)physicalAddress)) { epoch.Suspend(); var curPage = currentAddress >> allocator.LogPageSizeBits; throw new FasterException("Invalid checksum found during scan, skipping page " + curPage); } else { continue; } } int recordSize = headerSize + Align(entryLength); if (entryLength < 0 || (_currentOffset + recordSize > allocator.PageSize)) { currentAddress = (1 + (currentAddress >> allocator.LogPageSizeBits)) << allocator.LogPageSizeBits; if (Utility.MonotonicUpdate(ref NextAddress, currentAddress, out _)) { epoch.Suspend(); throw new FasterException("Invalid length of record found: " + entryLength + " at address " + currentAddress + ", skipping page"); } else { continue; } } // Verify checksum if needed if (currentAddress < _headAddress) { if (!fasterLog.VerifyChecksum((byte *)physicalAddress, entryLength)) { var curPage = currentAddress >> allocator.LogPageSizeBits; currentAddress = (1 + (currentAddress >> allocator.LogPageSizeBits)) << allocator.LogPageSizeBits; if (Utility.MonotonicUpdate(ref NextAddress, currentAddress, out _)) { epoch.Suspend(); throw new FasterException("Invalid checksum found during scan, skipping page " + curPage); } else { continue; } } } if ((currentAddress & allocator.PageSizeMask) + recordSize == allocator.PageSize) { currentAddress = (1 + (currentAddress >> allocator.LogPageSizeBits)) << allocator.LogPageSizeBits; } else { currentAddress += recordSize; } if (Utility.MonotonicUpdate(ref NextAddress, currentAddress, out long oldCurrentAddress)) { nextAddress = currentAddress; currentAddress = oldCurrentAddress; return(true); } } }
/// <summary> /// Retrieve physical address of next iterator value /// (under epoch protection if it is from main page buffer) /// </summary> /// <param name="physicalAddress"></param> /// <param name="entryLength"></param> /// <param name="currentAddress"></param> /// <param name="outNextAddress"></param> /// <param name="commitRecord"></param> /// <returns></returns> private unsafe bool GetNextInternal(out long physicalAddress, out int entryLength, out long currentAddress, out long outNextAddress, out bool commitRecord) { while (true) { physicalAddress = 0; entryLength = 0; currentAddress = nextAddress; outNextAddress = nextAddress; commitRecord = false; // Check for boundary conditions if (currentAddress < allocator.BeginAddress) { currentAddress = allocator.BeginAddress; } var _currentPage = currentAddress >> allocator.LogPageSizeBits; var _currentFrame = _currentPage % frameSize; var _currentOffset = currentAddress & allocator.PageSizeMask; var _headAddress = allocator.HeadAddress; if (disposed) { return(false); } if ((currentAddress >= endAddress) || (currentAddress >= (scanUncommitted ? fasterLog.SafeTailAddress : fasterLog.CommittedUntilAddress))) { return(false); } if (currentAddress < _headAddress) { var _endAddress = endAddress; if (fasterLog.readOnlyMode) { // Support partial page reads of committed data var _flush = fasterLog.CommittedUntilAddress; if (_flush < endAddress) { _endAddress = _flush; } } if (BufferAndLoad(currentAddress, _currentPage, _currentFrame, _headAddress, _endAddress)) { continue; } physicalAddress = frame.GetPhysicalAddress(_currentFrame, _currentOffset); } else { physicalAddress = allocator.GetPhysicalAddress(currentAddress); } // Get and check entry length entryLength = fasterLog.GetLength((byte *)physicalAddress); // We may encounter zeroed out bits at the end of page in a normal log, therefore, we need to check // whether that is the case if (entryLength == 0) { // Zero-ed out bytes could be padding at the end of page, first jump to the start of next page. var nextStart = (1 + (currentAddress >> allocator.LogPageSizeBits)) << allocator.LogPageSizeBits; if (Utility.MonotonicUpdate(ref nextAddress, nextStart, out _)) { var pageOffset = currentAddress & ((1 << allocator.LogPageSizeBits) - 1); // If zeroed out field is at page start, we encountered an uninitialized page and should signal up if (pageOffset == 0) { throw new FasterException("Uninitialized page found during scan at page " + (currentAddress >> allocator.LogPageSizeBits)); } } continue; } // commit records have negative length fields if (entryLength < 0) { commitRecord = true; entryLength = -entryLength; } int recordSize = headerSize + Align(entryLength); if (_currentOffset + recordSize > allocator.PageSize) { currentAddress += headerSize; if (Utility.MonotonicUpdate(ref nextAddress, currentAddress, out _)) { throw new FasterException("Invalid length of record found: " + entryLength + " at address " + currentAddress); } continue; } // Verify checksum if needed if (currentAddress < _headAddress) { if (!fasterLog.VerifyChecksum((byte *)physicalAddress, entryLength)) { currentAddress += headerSize; if (Utility.MonotonicUpdate(ref nextAddress, currentAddress, out _)) { throw new FasterException("Invalid checksum found during scan, skipping"); } continue; } } if ((currentAddress & allocator.PageSizeMask) + recordSize == allocator.PageSize) { currentAddress = (1 + (currentAddress >> allocator.LogPageSizeBits)) << allocator.LogPageSizeBits; } else { currentAddress += recordSize; } if (Utility.MonotonicUpdate(ref nextAddress, currentAddress, out long oldCurrentAddress)) { outNextAddress = currentAddress; currentAddress = oldCurrentAddress; return(true); } } }