using System; using System.Collections.Generic; using System.Linq; using System.Text; using DTS.Common.Classes.Locking; using DTS.Common.Import.Interfaces; using DTS.Common.SharedResource.Strings; using DTS.Common.Storage; using DTS.Common.Utilities.Logging; using DTS.Slice.Users; namespace DTS.Common.Import.DatabaseLocks { //FB 36740 public class LockImportTestSetups : ILockImport { private readonly User _currentUser; private readonly double _strandedLockTimeoutMinutes; /// /// this is a list of all tests locked by user /// private readonly List _lockedTests = new List(); /// /// this is a list of tests locking was attempted but another user has the lock /// private readonly List _contendedTests = new List(); public LockImportTestSetups(User currentUser, double strandedLockTimeoutMinutes) { _currentUser = currentUser; _strandedLockTimeoutMinutes = strandedLockTimeoutMinutes; } public bool Contended { get => _contendedTests.Any(); } public void FreeLock(ref ImportObject importObject) { if (!_lockedTests.Any()) { return; } foreach (var record in _lockedTests) { LockManager.FreeLock(record.ItemId, _currentUser.UserName, _currentUser.Id, out var lockError, record.ItemCategory); } } public void SetLock(ref ImportObject importObject, ref StringBuilder message) { _lockedTests.Clear(); _contendedTests.Clear(); foreach (var test in importObject.TestSetups()) { try { var gotLock = LockManager.LockItem(test.Name, test.Id, LockManager.ItemCategories.TestSetup, _currentUser.UserName, _currentUser.Id, out var existingLock, out var lockError); if (!gotLock) { if (lockError.ErrorCode == LockError.ITEM_NOT_FOUND) { continue; //lock not needed, doesn't exist in db } var lockOutOfDate = existingLock.LastUpdated.AddMinutes(_strandedLockTimeoutMinutes) < DateTime.Now; var IHaveTheLock = existingLock.LockingUserName == _currentUser.UserName && existingLock.LockingMachineName == Environment.MachineName; if (lockOutOfDate || IHaveTheLock) { //lock is expired (or already belongs to us), either way we can claim it _ = LockManager.FreeLock(existingLock.ItemId, _currentUser.UserName, _currentUser.Id, out lockError, existingLock.ItemCategory); _ = LockManager.LockItem(existingLock.ItemKey, existingLock.ItemId, LockManager.ItemCategories.TestSetup, _currentUser.UserName, _currentUser.Id, out existingLock, out lockError); _lockedTests.Add(existingLock); } else { //couldn't be locked, we need Admin + confirmation to steal lock _contendedTests.Add(existingLock); } } else { //successfully locked _lockedTests.Add(existingLock); } } catch (Exception ex) { APILogger.Log(ex); } } if (!_contendedTests.Any()) { return; } message.AppendLine(StringResources.ImportTestSetup_TestsLocked); foreach (var contended in _contendedTests) { message.AppendLine($"{contended.ItemKey} by {contended.LockingUserName} on {contended.LockingMachineName}"); } } public bool StealLock(bool proceed) { if (!_contendedTests.Any()) { return true; } if (!_currentUser.IsAdmin) { return false; } //steal locks if user oks it if (!proceed) { return false; } foreach (var contendedTest in _contendedTests) { LockManager.FreeLock(contendedTest.ItemId, _currentUser.UserName, _currentUser.Id, out var lockError, contendedTest.ItemCategory); LockManager.LockItem(contendedTest.ItemKey, contendedTest.ItemId, LockManager.ItemCategories.Sensor, _currentUser.UserName, _currentUser.Id, out var newLockRecord, out lockError); _lockedTests.Add(newLockRecord); } return true; } } }