/// <summary> /// Tries to acquire an exclusive write /// for the resource, and specifies a timeout for the lock. If this operation /// succeeds, the lock must be released as soon /// as possible through the <see cref="ReleaseWriteLock"/> /// method. /// </summary> /// <param name="timeout">The timeout of the lock. /// A value of null requests a lock that doesn't time out.</param> /// <returns>A lock that corresponds to the request. If the lock was denied, the /// returned item's <see cref="LockItem.LockType"/> /// is <see cref="ResourceLockType.Denied"/>.</returns> /// <exception cref="ArgumentOutOfRangeException">In case of a negative /// timeout.</exception> public LockItem TryGetWriteLock(TimeSpan?timeout) { lock (this) { if (HasWriteLock || HasReadLocks) { return(LockItem.CreateDenied(ResourceId)); } activeWriteLock = LockItem.CreateWrite(ResourceId, timeout); return(activeWriteLock); } }
/// <summary> /// Tries to acquire a shared read lock /// for the resource, and specifies a timeout for the lock. If this operation /// succeeds, the lock must be released as soon /// as possible through the <see cref="ReleaseReadLock"/> /// method. /// </summary> /// <returns>A lock that corresponds to the request. If the lock was denied, the /// returned item's <see cref="LockItem.LockType"/> /// is <see cref="ResourceLockType.Denied"/>.</returns> /// <param name="timeout">The timeout of the lock. /// A null value requests a lock that doesn't time out.</param> /// <returns>True if the lock was granted.</returns> /// <exception cref="ArgumentOutOfRangeException">In case of a negative /// timeout.</exception> public LockItem TryGetReadLock(TimeSpan?timeout) { lock (this) { if (HasWriteLock) { return(LockItem.CreateDenied(ResourceId)); } //clean up inactive locks from time to time Cleanup(); var item = LockItem.CreateRead(ResourceId, timeout); readLocks.Add(item); return(item); } }
/// <summary> /// Gets a read lock on all parent folders of a given resource, and rolls back the resources /// if the locking fails. /// </summary> /// <param name="repository">The repository that manages locked resources.</param> /// <param name="resourceId">The resource to be locked.</param> /// <param name="isWriteLock">Whether to acquire a read or write lock for the resource itself.</param> /// <param name="parentFolderIds">Ids of the resource's parent folders, which are being locked one /// by one. The list should be ordered, with the first item being the immediate parent of the locked /// resource, and the last one the topmost folder to be locked.</param> /// <returns>A guard which releases the resource and all folders once it is being disposed.</returns> public static ResourceLockGuard GetResourceChainLock(this IResourceLockRepository repository, string resourceId, bool isWriteLock, List <string> parentFolderIds) { LockItem lockItem = isWriteLock ? repository.TryGetWriteLock(resourceId) : repository.TryGetReadLock(resourceId); //we couldn't get a lock on the resource itself if (!lockItem.IsEnabled) { return(new ResourceLockGuard(lockItem, repository)); } //get read locks for all parent folders List <LockItem> folderLocks = new List <LockItem>(); LockItem folderLock = null; foreach (string folderId in parentFolderIds) { //lock parent folders, one by one for read access (prevents deletion) folderLock = repository.TryGetReadLock(folderId); if (!folderLock.IsEnabled) { break; } folderLocks.Add(folderLock); } if (folderLock != null && !folderLock.IsEnabled) { //roll back all locks... repository.ReleaseLock(lockItem); folderLocks.ForEach(li => repository.ReleaseLock(li)); //...and return a dummy lock return(new ResourceLockGuard(LockItem.CreateDenied(resourceId), repository)); } return(new ResourceLockGuard(lockItem, repository) { SecondaryLocks = folderLocks }); }