/// <summary> /// Constructor /// </summary> /// <param name="beginAddress"></param> /// <param name="endAddress"></param> /// <param name="scanBufferingMode"></param> /// <param name="epoch"></param> /// <param name="logPageSizeBits"></param> /// <param name="initForReads"></param> public unsafe ScanIteratorBase(long beginAddress, long endAddress, ScanBufferingMode scanBufferingMode, LightEpoch epoch, int logPageSizeBits, bool initForReads = true) { // If we are protected when creating the iterator, we do not need per-GetNext protection if (epoch != null && !epoch.ThisInstanceProtected()) { this.epoch = epoch; } this.beginAddress = beginAddress; this.endAddress = endAddress; this.logPageSizeBits = logPageSizeBits; currentAddress = -1; nextAddress = beginAddress; if (scanBufferingMode == ScanBufferingMode.SinglePageBuffering) { frameSize = 1; } else if (scanBufferingMode == ScanBufferingMode.DoublePageBuffering) { frameSize = 2; } else if (scanBufferingMode == ScanBufferingMode.NoBuffering) { frameSize = 0; return; } if (initForReads) { InitializeForReads(); } }
/// <summary> /// Attempts to advance the version to the target version, executing the given action in a critical section /// where no batches are being processed before entering the next version. Each version will be advanced to /// exactly once. This method may fail and return false if given target version is not larger than the /// current version (possibly due to concurrent invocations to advance to the same version). /// After the method returns, subsequent calls to Version() and Enter() will return at least the value of /// targetVersion. /// </summary> /// <param name="criticalSection"> The logic to execute in a critical section </param> /// <param name="targetVersion"> The version to advance to, or -1 for the immediate next version</param> /// <returns> Whether the advance was successful </returns> public bool TryAdvanceVersion(Action <long, long> criticalSection, long targetVersion = -1) { var ev = new ManualResetEventSlim(); // Compare and exchange to install our advance while (Interlocked.CompareExchange(ref versionChanged, ev, null) != null) { } if (targetVersion != -1 && targetVersion <= version) { versionChanged.Set(); versionChanged = null; return(false); } // Any thread that sees ev will be in v + 1, because the bump happens only after ev is set. var original = Interlocked.Read(ref version); epoch.BumpCurrentEpoch(() => { version = targetVersion == -1 ? original + 1 : targetVersion; criticalSection(original, version); versionChanged.Set(); versionChanged = null; }); // Make sure that even if we are the only thread, we are able to make progress if (!epoch.ThisInstanceProtected()) { epoch.Resume(); epoch.Suspend(); } return(true); }
/// <summary> /// Constructor /// </summary> /// <param name="hlog"></param> /// <param name="beginAddress"></param> /// <param name="endAddress"></param> /// <param name="scanBufferingMode"></param> /// <param name="epoch"></param> public unsafe GenericScanIterator(GenericAllocator <Key, Value> hlog, long beginAddress, long endAddress, ScanBufferingMode scanBufferingMode, LightEpoch epoch) { this.hlog = hlog; // If we are protected when creating the iterator, we do not need per-GetNext protection if (!epoch.ThisInstanceProtected()) { this.epoch = epoch; } if (beginAddress == 0) { beginAddress = hlog.GetFirstValidLogicalAddress(0); } this.endAddress = endAddress; recordSize = hlog.GetRecordSize(0).Item2; currentAddress = -1; nextAddress = beginAddress; if (scanBufferingMode == ScanBufferingMode.SinglePageBuffering) { frameSize = 1; } else if (scanBufferingMode == ScanBufferingMode.DoublePageBuffering) { frameSize = 2; } else if (scanBufferingMode == ScanBufferingMode.NoBuffering) { frameSize = 0; return; } frame = new GenericFrame <Key, Value>(frameSize, hlog.PageSize); loaded = new CountdownEvent[frameSize]; // Only load addresses flushed to disk if (nextAddress < hlog.HeadAddress) { var frameNumber = (nextAddress >> hlog.LogPageSizeBits) % frameSize; hlog.AsyncReadPagesFromDeviceToFrame (nextAddress >> hlog.LogPageSizeBits, 1, endAddress, AsyncReadPagesCallback, Empty.Default, frame, out loaded[frameNumber]); } }
/// <summary> /// Constructor /// </summary> /// <param name="beginAddress"></param> /// <param name="endAddress"></param> /// <param name="scanBufferingMode"></param> /// <param name="epoch"></param> /// <param name="logPageSizeBits"></param> public unsafe ScanIteratorBase(long beginAddress, long endAddress, ScanBufferingMode scanBufferingMode, LightEpoch epoch, int logPageSizeBits) { // If we are protected when creating the iterator, we do not need per-GetNext protection if (!epoch.ThisInstanceProtected()) { this.epoch = epoch; } this.beginAddress = beginAddress; this.endAddress = endAddress; this.logPageSizeBits = logPageSizeBits; currentAddress = -1; nextAddress = beginAddress; if (scanBufferingMode == ScanBufferingMode.SinglePageBuffering) { frameSize = 1; } else if (scanBufferingMode == ScanBufferingMode.DoublePageBuffering) { frameSize = 2; } else if (scanBufferingMode == ScanBufferingMode.NoBuffering) { frameSize = 0; return; } loaded = new CountdownEvent[frameSize]; loadedCancel = new CancellationTokenSource[frameSize]; loadedPage = new long[frameSize]; nextLoadedPage = new long[frameSize]; for (int i = 0; i < frameSize; i++) { loadedPage[i] = -1; nextLoadedPage[i] = -1; loadedCancel[i] = new CancellationTokenSource(); } }