public void TestLayerLocking() { try { const string TEST_SCENENAME = "TestSceneLocking"; const string TEST_SCENENAME2 = "TestSceneLocking_SaveAsTest"; // Create a new project and scene TestManager.Helpers.CreateTestScene(TEST_SCENENAME); EditorProject project = EditorApp.Project; IScene scene = project.Scene; Layer firstLayer = scene.Layers[0]; // First layer must be writeable Assert.IsTrue(firstLayer.OwnsLock); Assert.IsTrue(firstLayer.SaveToFile()); // close scene string layerFilePath = firstLayer.AbsoluteLayerFilename; firstLayer = null; scene.Close(); Assert.IsNull(project.Scene); // Get external lock on layer file IFileLock extFileLock = EditorManager.FileLockFactory.GetFileLock(layerFilePath); Assert.IsTrue(extFileLock.TryLock()); // Reopen scene: must fail on saving layer (locked externally) Assert.IsTrue(project.OpenScene(TEST_SCENENAME)); scene = project.Scene; firstLayer = scene.Layers[0]; Assert.IsFalse(firstLayer.OwnsLock); // Release lock: OwnsWriteLock state must get updated extFileLock.Unlock(); // Give windows time to inform the file watcher System.Threading.Thread.Sleep(1000); TestManager.Helpers.ProcessEvents(); // And then give the file watcher time to send his queued/delayed notification System.Threading.Thread.Sleep(1000); TestManager.Helpers.ProcessEvents(); Assert.IsTrue(firstLayer.LockStatus == Layer.LayerLockStatus_e.NotLocked); // Let the scene lock the layer again: saving file must be successful firstLayer.TryLock(null, false); Assert.IsTrue(firstLayer.OwnsLock); Assert.IsTrue(firstLayer.SaveToFile()); // Getting external lock must fail (since file is locked by scene) Assert.IsFalse(extFileLock.TryLock()); // Rename the scene file Assert.IsTrue(scene.SaveAs(TEST_SCENENAME2)); string renamedLayerFilePath = firstLayer.AbsoluteLayerFilename; Assert.IsTrue(renamedLayerFilePath != layerFilePath); // Getting external lock must work after scene-save-as Assert.IsTrue(firstLayer.OwnsLock); Assert.IsTrue(extFileLock.TryLock()); extFileLock.Unlock(); // Getting external lock on renamed file must fail IFileLock extFileLockRenamed = EditorManager.FileLockFactory.GetFileLock(renamedLayerFilePath); Assert.IsFalse(extFileLockRenamed.TryLock()); // Verify that a scene can't be opened without closing it at first // (important, since we otherwise still have the lock on the old scene) Assert.IsFalse(project.OpenScene(TEST_SCENENAME)); // Close scene scene.Close(); Assert.IsNull(project.Scene); // Test correct behaviour for readonly layer files { // Set the layer as readonly (as done by some version control systems // when using exclusive locking) File.SetAttributes(layerFilePath, File.GetAttributes(layerFilePath) | FileAttributes.ReadOnly); // Reopen scene Assert.IsTrue(project.OpenScene(TEST_SCENENAME)); scene = project.Scene; firstLayer = scene.Layers[0]; // Layer must not be locked due to being readonly. Assert.IsFalse(firstLayer.OwnsLock); Assert.AreEqual(Layer.LayerLockStatus_e.ReadOnly, firstLayer.LockStatus); // Close scene scene.Close(); Assert.IsNull(project.Scene); // Set the layer as readonly (as done by some version control systems // when using exclusive locking) File.SetAttributes(layerFilePath, File.GetAttributes(layerFilePath) & (~FileAttributes.ReadOnly)); } TestManager.Helpers.CloseTestProject(); } catch (Exception ex) { EditorManager.DumpException(ex); throw ex; } }
internal virtual void UnlockProject() { if (m_fileLock != null) { m_fileLock.ReleaseLock(); m_fileLock = null; } }
public AcquireLockAction ShouldAcquireLock(IFileLock fileLock) { if (lockIo.LockExists(LockFilePath)) { //Someone else owns the lock if (fileLock is OtherProcessHasExclusiveLockOnFileLock) { //we couldn't read the file as some other process has it open exlusively return(AcquireLockAction.DontAcquireLock); } if (fileLock is UnableToDeserialiseLockFile nonDeserialisedLockFile) { if ((DateTime.Now - nonDeserialisedLockFile.CreationTime).TotalSeconds > LockTimeout.TotalSeconds) { log.Warn("Lock file existed but was not readable, and has existed for longer than lock timeout. Taking lock."); return(AcquireLockAction.AcquireLock); } return(AcquireLockAction.DontAcquireLock); } //the file no longer exists if (fileLock is MissingFileLock) { return(AcquireLockAction.AcquireLock); } var concreteFileLock = fileLock as FileLock; if (concreteFileLock == null) { return(AcquireLockAction.AcquireLock); } //This lock belongs to this process - we can reacquire the lock if (concreteFileLock.BelongsToCurrentProcessAndThread()) { return(AcquireLockAction.AcquireLock); } if (!processFinder.ProcessIsRunning((int)concreteFileLock.ProcessId, concreteFileLock.ProcessName ?? "")) { log.Warn($"Process {concreteFileLock.ProcessId}, thread {concreteFileLock.ThreadId} had lock, but appears to have crashed. Taking lock."); return(AcquireLockAction.AcquireLock); } var lockWriteTime = new DateTime(concreteFileLock.Timestamp); //The lock has not timed out - we can't acquire it if (!(Math.Abs((DateTime.Now - lockWriteTime).TotalSeconds) > LockTimeout.TotalSeconds)) { return(AcquireLockAction.DontAcquireLock); } log.Warn($"Forcibly taking lock from process {concreteFileLock.ProcessId}, thread {concreteFileLock.ThreadId} as lock has timed out. If this happens regularly, please contact Octopus Support."); return(AcquireLockAction.ForciblyAcquireLock); } return(AcquireLockAction.AcquireLock); }
internal virtual void LockProject() { m_fileLock = SimpleFileLock.CreateFromFilePath(ProjectId.Path + ".lock"); if (!m_fileLock.TryAcquireLock()) throw new FdoFileLockedException(String.Format(Properties.Resources.kstidLockFileLocked, ProjectId.Name), true); m_lastWriteTime = File.GetLastWriteTimeUtc(ProjectId.Path); }