예제 #1
0
        /// <summary>
        /// Get next record in iterator
        /// </summary>
        /// <param name="entry">Copy of entry, if found</param>
        /// <param name="entryLength">Actual length of entry</param>
        /// <param name="currentAddress">Logical address of entry</param>
        /// <param name="nextAddress">Logical address of next entry</param>
        /// <returns></returns>
        public unsafe bool GetNext(out byte[] entry, out int entryLength, out long currentAddress, out long nextAddress)
        {
            epoch.Resume();
            if (GetNextInternal(out long physicalAddress, out entryLength, out currentAddress, out nextAddress))
            {
                if (getMemory != null)
                {
                    // Use user delegate to allocate memory
                    entry = getMemory(entryLength);
                    if (entry.Length < entryLength)
                    {
                        throw new FasterException("Byte array provided has invalid length");
                    }
                }
                else
                {
                    // We allocate a byte array from heap
                    entry = new byte[entryLength];
                }

                fixed(byte *bp = entry)
                Buffer.MemoryCopy((void *)(headerSize + physicalAddress), bp, entryLength, entryLength);

                epoch.Suspend();
                return(true);
            }

            entry = default;
            epoch.Suspend();
            return(false);
        }
예제 #2
0
        private bool WaitForFrameLoad(long currentAddress, long currentFrame)
        {
            if (loaded[currentFrame].IsSet)
            {
                return(false);
            }

            try
            {
                epoch?.Suspend();
                loaded[currentFrame].Wait(loadedCancel[currentFrame].Token); // Ensure we have completed ongoing load
            }
            catch (Exception e)
            {
                loadedPage[currentFrame]   = -1;
                loadedCancel[currentFrame] = new CancellationTokenSource();
                Utility.MonotonicUpdate(ref nextAddress, (1 + (currentAddress >> logPageSizeBits)) << logPageSizeBits, out _);
                throw new FasterException("Page read from storage failed, skipping page. Inner exception: " + e.ToString());
            }
            finally
            {
                epoch?.Resume();
            }
            return(true);
        }
예제 #3
0
        /// <summary>
        ///     Protects later processing from concurrent version changes until Leave() is called. Method may block if
        ///     version change is under way. Leave() must eventually be called on the same thread so the rest of the
        ///     system makes meaningful progress.
        /// </summary>
        /// <returns>
        ///     current version number. This guarantees that any version change logic from smaller version numbers
        ///     have finished, and not version change logic to larger versions will begin during protection.
        /// </returns>
        public long Enter()
        {
            epoch.Resume();
            // Temporarily block if a version change is under way --- depending on whether the thread observes
            // versionChanged, they are either in the current version or the next
            while (true)
            {
                var ev = versionChanged;
                if (ev == null)
                {
                    break;
                }
                // Allow version change to complete by leaving this epoch.
                epoch.Suspend();
                ev.Wait();
                epoch.Resume();
            }

            return(Interlocked.Read(ref version));
        }
예제 #4
0
        /// <summary>
        /// Try to enqueue entry to log (in memory). If it returns true, we are
        /// done. If it returns false, we need to retry.
        /// </summary>
        /// <param name="entry">Entry to be enqueued to log</param>
        /// <param name="logicalAddress">Logical address of added entry</param>
        /// <returns>Whether the append succeeded</returns>
        public unsafe bool TryEnqueue(byte[] entry, out long logicalAddress)
        {
            logicalAddress = 0;

            epoch.Resume();

            var length = entry.Length;

            logicalAddress = allocator.TryAllocate(headerSize + Align(length));
            if (logicalAddress == 0)
            {
                epoch.Suspend();
                return(false);
            }

            var physicalAddress = allocator.GetPhysicalAddress(logicalAddress);

            fixed(byte *bp = entry)
            Buffer.MemoryCopy(bp, (void *)(headerSize + physicalAddress), length, length);

            SetHeader(length, (byte *)physicalAddress);
            epoch.Suspend();
            return(true);
        }
예제 #5
0
        /// <summary>
        /// Get next record
        /// </summary>
        /// <param name="recordInfo"></param>
        /// <returns>True if record found, false if end of scan</returns>
        public bool GetNext(out RecordInfo recordInfo)
        {
            recordInfo = default;

            while (true)
            {
                currentAddress = nextAddress;

                // Check for boundary conditions
                if (currentAddress >= endAddress)
                {
                    return(false);
                }

                epoch?.Resume();
                var headAddress = hlog.HeadAddress;

                if (currentAddress < hlog.BeginAddress)
                {
                    epoch?.Suspend();
                    throw new FasterException("Iterator address is less than log BeginAddress " + hlog.BeginAddress);
                }

                if (frameSize == 0 && currentAddress < headAddress)
                {
                    epoch?.Suspend();
                    throw new FasterException("Iterator address is less than log HeadAddress in memory-scan mode");
                }

                var currentPage = currentAddress >> hlog.LogPageSizeBits;
                var offset      = currentAddress & hlog.PageSizeMask;

                if (currentAddress < headAddress)
                {
                    BufferAndLoad(currentAddress, currentPage, currentPage % frameSize);
                }

                long physicalAddress;
                if (currentAddress >= headAddress)
                {
                    physicalAddress        = hlog.GetPhysicalAddress(currentAddress);
                    currentPhysicalAddress = 0;
                }
                else
                {
                    currentPhysicalAddress = physicalAddress = frame.GetPhysicalAddress(currentPage % frameSize, offset);
                }

                // Check if record fits on page, if not skip to next page
                var recordSize = hlog.GetRecordSize(physicalAddress).Item2;
                if ((currentAddress & hlog.PageSizeMask) + recordSize > hlog.PageSize)
                {
                    nextAddress = (1 + (currentAddress >> hlog.LogPageSizeBits)) << hlog.LogPageSizeBits;
                    epoch?.Suspend();
                    continue;
                }

                nextAddress = currentAddress + recordSize;

                ref var info = ref hlog.GetInfo(physicalAddress);
                if (info.Invalid || info.IsNull())
                {
                    epoch?.Suspend();
                    continue;
                }

                recordInfo = info;
                if (currentPhysicalAddress == 0)
                {
                    currentKey   = hlog.GetKey(physicalAddress);
                    currentValue = hlog.GetValue(physicalAddress);
                }
                epoch?.Suspend();
                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);
            }
        }
예제 #7
0
        /// <summary>
        /// Get next record in iterator
        /// </summary>
        /// <param name="recordInfo"></param>
        /// <returns></returns>
        public bool GetNext(out RecordInfo recordInfo)
        {
            recordInfo   = default;
            currentKey   = default;
            currentValue = default;

            while (true)
            {
                currentAddress = nextAddress;

                // Check for boundary conditions
                if (currentAddress >= endAddress)
                {
                    return(false);
                }

                epoch?.Resume();
                var headAddress = hlog.HeadAddress;

                if (currentAddress < hlog.BeginAddress)
                {
                    epoch?.Suspend();
                    throw new FasterException("Iterator address is less than log BeginAddress " + hlog.BeginAddress);
                }

                if (frameSize == 0 && currentAddress < headAddress)
                {
                    epoch?.Suspend();
                    throw new FasterException("Iterator address is less than log HeadAddress in memory-scan mode");
                }

                var currentPage = currentAddress >> hlog.LogPageSizeBits;

                var offset = (currentAddress & hlog.PageSizeMask) / recordSize;

                if (currentAddress < headAddress)
                {
                    BufferAndLoad(currentAddress, currentPage, currentPage % frameSize);
                }

                // Check if record fits on page, if not skip to next page
                if ((currentAddress & hlog.PageSizeMask) + recordSize > hlog.PageSize)
                {
                    nextAddress = (1 + (currentAddress >> hlog.LogPageSizeBits)) << hlog.LogPageSizeBits;
                    epoch?.Suspend();
                    continue;
                }

                nextAddress = currentAddress + recordSize;

                if (currentAddress >= headAddress)
                {
                    // Read record from cached page memory
                    var page = currentPage % hlog.BufferSize;

                    if (hlog.values[page][offset].info.Invalid)
                    {
                        epoch?.Suspend();
                        continue;
                    }

                    recordInfo   = hlog.values[page][offset].info;
                    currentKey   = hlog.values[page][offset].key;
                    currentValue = hlog.values[page][offset].value;
                    epoch?.Suspend();
                    return(true);
                }

                var currentFrame = currentPage % frameSize;

                if (frame.GetInfo(currentFrame, offset).Invalid)
                {
                    epoch?.Suspend();
                    continue;
                }

                recordInfo   = frame.GetInfo(currentFrame, offset);
                currentKey   = frame.GetKey(currentFrame, offset);
                currentValue = frame.GetValue(currentFrame, offset);
                epoch?.Suspend();
                return(true);
            }
        }