예제 #1
0
        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));
        }
예제 #2
0
        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();
        }
예제 #3
0
            /// <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;
                        }
                    }
                }
            }
예제 #4
0
        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));
        }
예제 #5
0
        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);
        }