diff --git a/cs/src/core/Allocator/AllocatorBase.cs b/cs/src/core/Allocator/AllocatorBase.cs index 48f53fb39..557cddea3 100644 --- a/cs/src/core/Allocator/AllocatorBase.cs +++ b/cs/src/core/Allocator/AllocatorBase.cs @@ -870,7 +870,7 @@ public void ShiftReadOnlyToTail(out long tailAddress) tailAddress = GetTailAddress(); long localTailAddress = tailAddress; long currentReadOnlyOffset = ReadOnlyAddress; - if (MonotonicUpdate(ref ReadOnlyAddress, tailAddress, out long oldReadOnlyOffset)) + if (Utility.MonotonicUpdate(ref ReadOnlyAddress, tailAddress, out long oldReadOnlyOffset)) { epoch.BumpCurrentEpoch(() => OnPagesMarkedReadOnly(localTailAddress, false)); } @@ -882,7 +882,7 @@ public void ShiftReadOnlyToTail(out long tailAddress) /// public bool ShiftReadOnlyAddress(long newReadOnlyAddress) { - if (MonotonicUpdate(ref ReadOnlyAddress, newReadOnlyAddress, out long oldReadOnlyOffset)) + if (Utility.MonotonicUpdate(ref ReadOnlyAddress, newReadOnlyAddress, out long oldReadOnlyOffset)) { epoch.BumpCurrentEpoch(() => OnPagesMarkedReadOnly(newReadOnlyAddress, false)); return true; @@ -897,19 +897,19 @@ public bool ShiftReadOnlyAddress(long newReadOnlyAddress) public void ShiftBeginAddress(long newBeginAddress) { // First update the begin address - MonotonicUpdate(ref BeginAddress, newBeginAddress, out long oldBeginAddress); + Utility.MonotonicUpdate(ref BeginAddress, newBeginAddress, out long oldBeginAddress); // Then the head address - var h = MonotonicUpdate(ref HeadAddress, newBeginAddress, out long old); + var h = Utility.MonotonicUpdate(ref HeadAddress, newBeginAddress, out long old); // Finally the read-only address - var r = MonotonicUpdate(ref ReadOnlyAddress, newBeginAddress, out old); + var r = Utility.MonotonicUpdate(ref ReadOnlyAddress, newBeginAddress, out old); // Clean up until begin address epoch.BumpCurrentEpoch(() => { if (r) { - MonotonicUpdate(ref SafeReadOnlyAddress, newBeginAddress, out long _old); - MonotonicUpdate(ref FlushedUntilAddress, newBeginAddress, out _old); + Utility.MonotonicUpdate(ref SafeReadOnlyAddress, newBeginAddress, out long _old); + Utility.MonotonicUpdate(ref FlushedUntilAddress, newBeginAddress, out _old); } if (h) OnPagesClosed(newBeginAddress); @@ -935,7 +935,7 @@ protected virtual void DeleteAddressRange(long fromAddress, long toAddress) /// public void OnPagesMarkedReadOnly(long newSafeReadOnlyAddress, bool waitForPendingFlushComplete = false) { - if (MonotonicUpdate(ref SafeReadOnlyAddress, newSafeReadOnlyAddress, out long oldSafeReadOnlyAddress)) + if (Utility.MonotonicUpdate(ref SafeReadOnlyAddress, newSafeReadOnlyAddress, out long oldSafeReadOnlyAddress)) { Debug.WriteLine("SafeReadOnly shifted from {0:X} to {1:X}", oldSafeReadOnlyAddress, newSafeReadOnlyAddress); long startPage = oldSafeReadOnlyAddress >> LogPageSizeBits; @@ -964,7 +964,7 @@ public void OnPagesMarkedReadOnly(long newSafeReadOnlyAddress, bool waitForPendi /// public void OnPagesClosed(long newSafeHeadAddress) { - if (MonotonicUpdate(ref SafeHeadAddress, newSafeHeadAddress, out long oldSafeHeadAddress)) + if (Utility.MonotonicUpdate(ref SafeHeadAddress, newSafeHeadAddress, out long oldSafeHeadAddress)) { Debug.WriteLine("SafeHeadOffset shifted from {0:X} to {1:X}", oldSafeHeadAddress, newSafeHeadAddress); @@ -1020,7 +1020,7 @@ private void PageAlignedShiftReadOnlyAddress(long currentTailAddress) long currentReadOnlyAddress = ReadOnlyAddress; long pageAlignedTailAddress = currentTailAddress & ~PageSizeMask; long desiredReadOnlyAddress = (pageAlignedTailAddress - ReadOnlyLagAddress); - if (MonotonicUpdate(ref ReadOnlyAddress, desiredReadOnlyAddress, out long oldReadOnlyAddress)) + if (Utility.MonotonicUpdate(ref ReadOnlyAddress, desiredReadOnlyAddress, out long oldReadOnlyAddress)) { Debug.WriteLine("Allocate: Moving read-only offset from {0:X} to {1:X}", oldReadOnlyAddress, desiredReadOnlyAddress); epoch.BumpCurrentEpoch(() => OnPagesMarkedReadOnly(desiredReadOnlyAddress)); @@ -1050,7 +1050,7 @@ private void PageAlignedShiftHeadAddress(long currentTailAddress) if (ReadCache && (newHeadAddress > HeadAddress)) EvictCallback(HeadAddress, newHeadAddress); - if (MonotonicUpdate(ref HeadAddress, newHeadAddress, out long oldHeadAddress)) + if (Utility.MonotonicUpdate(ref HeadAddress, newHeadAddress, out long oldHeadAddress)) { Debug.WriteLine("Allocate: Moving head offset from {0:X} to {1:X}", oldHeadAddress, newHeadAddress); epoch.BumpCurrentEpoch(() => OnPagesClosed(newHeadAddress)); @@ -1075,7 +1075,7 @@ public long ShiftHeadAddress(long desiredHeadAddress) if (ReadCache && (newHeadAddress > HeadAddress)) EvictCallback(HeadAddress, newHeadAddress); - if (MonotonicUpdate(ref HeadAddress, newHeadAddress, out long oldHeadAddress)) + if (Utility.MonotonicUpdate(ref HeadAddress, newHeadAddress, out long oldHeadAddress)) { Debug.WriteLine("Allocate: Moving head offset from {0:X} to {1:X}", oldHeadAddress, newHeadAddress); epoch.BumpCurrentEpoch(() => OnPagesClosed(newHeadAddress)); @@ -1104,35 +1104,10 @@ protected void ShiftFlushedUntilAddress() if (update) { - MonotonicUpdate(ref FlushedUntilAddress, currentFlushedUntilAddress, out long oldFlushedUntilAddress); + Utility.MonotonicUpdate(ref FlushedUntilAddress, currentFlushedUntilAddress, out long oldFlushedUntilAddress); } } - - - /// - /// Used by several functions to update the variable to newValue. Ignores if newValue is smaller or - /// than the current value. - /// - /// - /// - /// - /// - private bool MonotonicUpdate(ref long variable, long newValue, out long oldValue) - { - oldValue = variable; - while (oldValue < newValue) - { - var foundValue = Interlocked.CompareExchange(ref variable, newValue, oldValue); - if (foundValue == oldValue) - { - return true; - } - oldValue = foundValue; - } - return false; - } - /// /// Reset for recovery /// diff --git a/cs/src/core/Utilities/Utility.cs b/cs/src/core/Utilities/Utility.cs index 57ab7168f..375b20cfc 100644 --- a/cs/src/core/Utilities/Utility.cs +++ b/cs/src/core/Utilities/Utility.cs @@ -223,5 +223,39 @@ internal static int Murmur3(int h) a ^= a >> 16; return (int)a; } + + /// + /// Updates the variable to newValue only if the current value is smaller than the new value. + /// + /// The variable to possibly replace + /// The value that replaces the variable if successful + /// The orignal value in the variable + /// if oldValue less than newValue + public static bool MonotonicUpdate(ref long variable, long newValue, out long oldValue) + { + do + { + oldValue = variable; + if (oldValue > newValue) return false; + } while (Interlocked.CompareExchange(ref variable, newValue, oldValue) != oldValue); + return true; + } + /// + /// Updates the variable to newValue only if the current value is smaller than the new value. + /// + /// The variable to possibly replace + /// The value that replaces the variable if successful + /// The orignal value in the variable + /// if oldValue less than newValue + public static bool MonotonicUpdate(ref int variable, int newValue, out int oldValue) + { + do + { + oldValue = variable; + if (oldValue > newValue) return false; + } while (Interlocked.CompareExchange(ref variable, newValue, oldValue) != oldValue); + return true; + } + } }