Exemple #1
0
        public ObjectLockKey IssueSingleUseKey(Transaction transaction, LockIntention lockIntention)
        {
            try
            {
                lock (CriticalSections.AcquireLock)
                {
                    var key = new ObjectLockKey(core, this, transaction.ProcessId, lockIntention.Operation);
                    Keys.Add(key);

                    return(key);
                }
            }
            catch (Exception ex)
            {
                core.Log.Write("Failed to issue single use lock key.", ex);
                throw;
            }
        }
Exemple #2
0
 public ObjectLock(Core core, LockIntention intention)
 {
     this.core     = core;
     this.DiskPath = intention.DiskPath;
     this.LockType = intention.Type;
 }
Exemple #3
0
 public bool IsObjectEqual(LockIntention intention)
 {
     return(intention.Type == this.Type &&
            intention.DiskPath == this.DiskPath);
 }
Exemple #4
0
 public bool IsEqual(LockIntention intention)
 {
     return(intention.Type == this.Type &&
            intention.Operation == this.Operation &&
            intention.DiskPath == this.DiskPath);
 }
Exemple #5
0
        public void Acquire(Transaction transaction, LockIntention intention)
        {
            try
            {
                //We keep track of all transactions that are waiting on locks for a few reasons:
                // (1) When we suspect a deadlock we know what all transactions are potentially involved
                // (2) We are safe to poke around those transaction's properties because we know their threda are in this method.
                lock (lockWaits)
                {
                    lockWaits.Add(transaction, intention);
                }

                DateTime startTime = DateTime.UtcNow;

                while (true)
                {
                    lock (CriticalSections.AcquireLock)
                    {
                        if (transaction.IsDeadlocked)
                        {
                            core.Health.Increment(HealthCounterType.DeadlockCount);
                            throw new DokdexDeadlockException(String.Format("Deadlock occurred, transaction for process {0} is being terminated.", transaction.ProcessId));
                        }

                        //Find any existing locks:
                        List <ObjectLock> lockedObjects = new List <ObjectLock>();

                        if (intention.Type == LockType.File)
                        {
                            lockedObjects.AddRange((from o in objectLocks where o.LockType == LockType.File && o.DiskPath == intention.DiskPath select o).ToList());
                        }
                        else
                        {
                            lockedObjects.AddRange((from o in objectLocks where o.DiskPath.StartsWith(intention.DiskPath) select o).ToList());
                        }

                        lockedObjects.AddRange((from o in objectLocks where o.LockType == LockType.Directory && intention.DiskPath.StartsWith(o.DiskPath) select o).ToList());

                        if (lockedObjects.Count() == 0)
                        {
                            //No locks on the object exist - so add one to the local and class collections.
                            var lockedObject = new ObjectLock(core, intention);
                            this.objectLocks.Add(lockedObject);
                            lockedObjects.Add(lockedObject);
                        }

                        //We just want read access.
                        if (intention.Operation == LockOperation.Read)
                        {
                            var blockers = lockedObjects.SelectMany(o => o.Keys).Where(o => o.LockOperation == LockOperation.Write && o.ProcessId != transaction.ProcessId).ToList();
                            //If there are no existing un-owned write locks.
                            if (blockers.Count() == 0)
                            {
                                transaction.BlockedBy.Clear();

                                foreach (var lockedObject in lockedObjects)
                                {
                                    var lockKey = lockedObject.IssueSingleUseKey(transaction, intention);
                                    transaction.HeldLockKeys.Add(lockKey);
                                }

                                var lockWaitTime = (DateTime.UtcNow - startTime).TotalMilliseconds;
                                core.Health.Increment(HealthCounterType.LockWaitMs, lockWaitTime);
                                core.Health.Increment(HealthCounterType.LockWaitMs, intention.ObjectName, lockWaitTime);

                                return;
                            }
                            else
                            {
                                transaction.BlockedBy.Clear();
                                transaction.BlockedBy.AddRange(blockers.Select(o => o.ProcessId).Distinct());
                            }
                        }
                        //We want write access.
                        else if (intention.Operation == LockOperation.Write)
                        {
                            var blockers = lockedObjects.SelectMany(o => o.Keys).Where(o => o.ProcessId != transaction.ProcessId).ToList();
                            //If there are no existing un-owned locks.
                            if (blockers.Count() == 0)
                            {
                                transaction.BlockedBy.Clear();

                                foreach (var lockedObject in lockedObjects)
                                {
                                    var lockKey = lockedObject.IssueSingleUseKey(transaction, intention);
                                    transaction.HeldLockKeys.Add(lockKey);
                                }

                                var lockWaitTime = (DateTime.UtcNow - startTime).TotalMilliseconds;
                                core.Health.Increment(HealthCounterType.LockWaitMs, lockWaitTime);
                                core.Health.Increment(HealthCounterType.LockWaitMs, intention.ObjectName, lockWaitTime);

                                return;
                            }
                            else
                            {
                                transaction.BlockedBy.Clear();
                                transaction.BlockedBy.AddRange(blockers.Select(o => o.ProcessId).Distinct());
                            }
                        }
                    }

                    //Deadlock Search.
                    lock (lockWaits)
                    {
                        var actualWaiters = lockWaits.Keys.Where(o => o.IsDeadlocked == false).ToList();
                        if (actualWaiters.Count() > 1)
                        {
                            foreach (var waiter in actualWaiters)
                            {
                                var blockedByMe = (from o in actualWaiters where o != waiter && o.BlockedBy.Contains(waiter.ProcessId) select o).ToList();

                                if (blockedByMe != null && blockedByMe.Count > 0)
                                {
                                    var blockingMe = (from o in blockedByMe where waiter.BlockedBy.Contains(o.ProcessId) select o).ToList();
                                    if (blockingMe != null && blockingMe.Count > 0)
                                    {
                                        transaction.IsDeadlocked = true;
                                        break;
                                    }
                                }
                            }
                        }
                    }


                    System.Threading.Thread.Sleep(1);
                }
            }
            catch (Exception ex)
            {
                core.Log.Write(String.Format("Failed to acquire lock for process {0}.", transaction.ProcessId), ex);
                throw;
            }
            finally
            {
                lock (lockWaits)
                {
                    lockWaits.Remove(transaction);
                }
            }
        }