public unsafe void CouldAcquireReleaseExclusiveLock() { var ptr = (long *)Marshal.AllocHGlobal(8); * ptr = 0; var wpid = Wpid.Create(); var wpid2 = Wpid.Create(); var sl = new SharedSpinLock(ptr); Assert.AreEqual(Wpid.Empty, sl.TryAcquireExclusiveLock(wpid, out _, spinLimit: 0)); // fast path Assert.AreEqual(Wpid.Empty, sl.TryReleaseLock(wpid)); Assert.AreEqual(Wpid.Empty, sl.TryAcquireExclusiveLock(wpid, out _)); var sw = new Stopwatch(); sw.Start(); Assert.AreEqual(wpid, sl.TryAcquireExclusiveLock(wpid2, out _, spinLimit: 1000)); sw.Stop(); Console.WriteLine($"Elapsed: {sw.ElapsedMilliseconds}"); Assert.AreEqual(Wpid.Empty, sl.TryReleaseLock(wpid)); }
public unsafe void UncontentedBench() { var ptr = (long *)Marshal.AllocHGlobal(8); * ptr = 0; var wpid = Wpid.Create(); var sl = new SharedSpinLock(ptr); var count = 10_000_000; for (int _ = 0; _ < 10; _++) { using (Benchmark.Run("Uncontented", count)) { for (int i = 0; i < count; i++) { sl.TryAcquireLock(wpid); sl.TryReleaseLock(wpid); } } } Benchmark.Dump(); }
/// <summary> /// Increment shared instance id and return a process buffer with new Wpid /// </summary> /// <returns></returns> public ProcessConfigRecord CreateNew() { using (var txn = Environment.BeginTransaction()) { while (true) { // ReSharper disable once ImpureMethodCallOnReadonlyValueField var newInsatnceId = unchecked ((uint)SharedRecord._processBuffer.InterlockedIncrementInt32(ProcessConfigRecord.SharedInstanceIdCounterOffset)); try { // We try to increment instance id instead of reuse existing // At some point after running for very very long time it might overflow // and start from zero again - this is fine. if (_processDb.TryGet(txn, ref newInsatnceId, out BufferRef bufferRef)) { continue; } bufferRef = Allocate(txn, 0, out var fromFreeList, null); _processDb.Put(txn, newInsatnceId, bufferRef, TransactionPutOptions.NoOverwrite); txn.Commit(); if (!fromFreeList) { Environment.Sync(true); } var result = _buckets[bufferRef]; if (fromFreeList) { // in Delete we clear the buffer after commit, there is small chance a process died after commit but before cleaning result.Clear(0, result.Length); } else { Debug.Assert(result.IsFilledWithValue(0), "a new ProcessConfig buffer must be clean."); } result.WriteInt64(ProcessConfigRecord.WpidOffset, Wpid.Create(newInsatnceId)); var record = new ProcessConfigRecord(result); return(record); } catch (Exception ex) { txn.Abort(); Trace.TraceError(ex.ToString()); throw; } } } }
public unsafe void CouldAcquireEnterExitReleaseExclusiveLock() { var ptr = (long *)Marshal.AllocHGlobal(8); * ptr = 0; var wpid = Wpid.Create(); var wpid2 = Wpid.Create(); var sl = new SharedSpinLock(ptr); Assert.AreEqual(Wpid.Empty, sl.TryAcquireExclusiveLock(wpid, out var tt, spinLimit: 0)); Assert.AreEqual(Wpid.Empty, sl.TryReEnterExclusiveLock(wpid, tt, spinLimit: 0)); Assert.Throws <InvalidOperationException>(() => { sl.TryReleaseLock(wpid); }); Assert.AreEqual(Wpid.Empty, sl.TryExitExclusiveLock(wpid, tt)); Assert.AreEqual(Wpid.Empty, sl.TryReleaseLock(wpid)); }
public unsafe void ReleasingOthersLockReturnsOthersWpid() { var ptr = (long *)Marshal.AllocHGlobal(8); * ptr = 0; var wpid = Wpid.Create(); var wpid2 = Wpid.Create(); var sl = new SharedSpinLock(ptr); Assert.AreEqual(Wpid.Empty, sl.TryAcquireLock(wpid, spinLimit: 0)); // fast path Assert.AreEqual(Wpid.Empty, sl.TryReleaseLock(wpid)); Assert.AreEqual(Wpid.Empty, sl.TryAcquireLock(wpid)); // wpid holding the lock var holder = sl.TryReleaseLock(wpid2); Assert.AreEqual(wpid, holder); }