Ejemplo n.º 1
0
        /// <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="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);
            }
        }