public Task Schedule( SubDirectoryTransfer subDirectoryTransfer, CancellationToken cancellationToken, Action persistDirTransfer, int timeOut) { if (this.semaphore.Wait(timeOut, cancellationToken)) { try { if (null != persistDirTransfer) { persistDirTransfer(); } } catch { this.semaphore.Release(); throw; } Task task = subDirectoryTransfer.ExecuteAsync(cancellationToken); task.ContinueWith((sourceTask) => { this.semaphore.Release(); return(sourceTask); }); return(task); } else { return(null); } }
private bool ScheduleSubDirectoryTransfer( SubDirectoryTransfer subDirectoryTransfer, CancellationToken cancellationToken, Action persistDirTransfer, int timeOut) { Interlocked.Increment(ref this.outstandingTasks); Task directoryListTask = null; try { directoryListTask = this.directoryListingScheduler.Schedule( subDirectoryTransfer, cancellationToken, persistDirTransfer, timeOut); } catch (OperationCanceledException) { // Ignore exception } catch (ObjectDisposedException) { // Ignore exception } this.WaitOnSubDirectoryListTask(directoryListTask, subDirectoryTransfer); return(null != directoryListTask); }
protected HierarchyDirectoryTransfer(HierarchyDirectoryTransfer other) : base(other) { other.progressUpdateLock?.EnterWriteLock(); this.ProgressTracker = other.ProgressTracker.Copy(); lock (other.continuationTokenLock) { foreach (var subDirTransfer in other.subDirectories) { this.subDirectories.Enqueue(subDirTransfer); } foreach (var subDirTransfer in other.ongoingSubDirTransfers) { var newSubDirTransfer = new SubDirectoryTransfer(subDirTransfer.Key); this.ongoingSubDirTransfers.TryAdd(newSubDirTransfer, new object()); } // copy transfers this.subTransfers = other.subTransfers.Copy(); this.enumerationStarted = other.enumerationStarted; } this.subTransfers.OverallProgressTracker.Parent = this.ProgressTracker; other.progressUpdateLock?.ExitWriteLock(); }
internal void AddOngoingSubDirTransfer(SubDirectoryTransfer directoryTransfer) { lock (this.journalLock) { long offset = this.SearchFreeOffset(); directoryTransfer.Journal = this; directoryTransfer.StreamJournalOffset = offset + 2 * sizeof(long); this.stream.Position = offset + 2 * sizeof(long); #if BINARY_SERIALIZATION this.formatter.Serialize(this.stream, directoryTransfer); #else this.WriteObject(this.subDirTransferSerializer, directoryTransfer); #endif long continuationTokenOffset = offset + 2 * sizeof(long) + 4096; this.stream.Position = continuationTokenOffset; directoryTransfer.ListContinuationToken.Journal = this; directoryTransfer.ListContinuationToken.StreamJournalOffset = continuationTokenOffset; #if BINARY_SERIALIZATION this.formatter.Serialize(this.stream, directoryTransfer.ListContinuationToken); #else this.WriteObject(this.continuationTokenSerializer, directoryTransfer.ListContinuationToken); #endif if (this.OngoingSubDirTransferChunkHead == 0) { if (this.OngoingSubDirTransferChunkTail != 0) { #if !NO_FILEFORMAT_EX throw new FileFormatException(Resources.RestartableLogCorrupted); #else throw new InvalidOperationException(Resources.RestartableLogCorrupted); #endif } this.OngoingSubDirTransferChunkHead = offset; this.OngoingSubDirTransferChunkTail = offset; this.stream.Position = this.OngoingSubDirTransferChunkHead; this.stream.Write(BitConverter.GetBytes(0L), 0, sizeof(long)); this.stream.Write(BitConverter.GetBytes(0L), 0, sizeof(long)); } else { this.stream.Position = this.OngoingSubDirTransferChunkTail + sizeof(long); this.stream.Write(BitConverter.GetBytes(offset), 0, sizeof(long)); this.stream.Position = offset; this.stream.Write(BitConverter.GetBytes(this.OngoingSubDirTransferChunkTail), 0, sizeof(long)); this.stream.Write(BitConverter.GetBytes(0L), 0, sizeof(long)); this.OngoingSubDirTransferChunkTail = offset; } this.WriteJournalHead(); this.stream.Flush(); } }
internal void RemoveSubDirTransfer(SubDirectoryTransfer directoryTransfer) { lock (this.journalLock) { long offset = directoryTransfer.StreamJournalOffset - 2 * sizeof(long); this.FreeChunk(offset, ref this.OngoingSubDirTransferChunkHead, ref this.OngoingSubDirTransferChunkTail); this.stream.Flush(); } }
public SubDirectoryTransfer(SubDirectoryTransfer other) { this.relativePath = other.relativePath; this.enumerateContinuationToken = other.enumerateContinuationToken; }
private async void WaitOnSubDirectoryListTask(Task directoryListTask, SubDirectoryTransfer subDirTransfer) { if (null == directoryListTask) { this.SignalSubDirTaskDecrement(); } else { bool shouldStopOthers = false; bool errorHappened = false; try { await directoryListTask; } catch (OperationCanceledException) { // Ingore this exception, there's other place reporting such kind of exception when cancellation is triggered. errorHappened = true; } catch (Exception ex) { if (ex is TransferException) { this.enumerateException = ex; } else if ((null != ex.InnerException) && (ex.InnerException is OperationCanceledException)) { // Ingore this exception, there's other place reporting such kind of exception when cancellation is triggered. errorHappened = true; } else { this.enumerateException = new TransferException( TransferErrorCode.FailToEnumerateDirectory, string.Format(CultureInfo.CurrentCulture, Resources.EnumerateDirectoryException, subDirTransfer.Source.Instance.ConvertToString()), ex); } shouldStopOthers = true; errorHappened = true; } finally { if (!errorHappened) { if (null != this.Journal) { this.Journal.RemoveSubDirTransfer(subDirTransfer); } else { object subDirTransferValue = null; this.ongoingSubDirTransfers.TryRemove(subDirTransfer, out subDirTransferValue); } } this.SignalSubDirTaskDecrement(); } if (shouldStopOthers) { this.cancellationTokenSource?.Cancel(); } } }
private async Task DoEnumerationAndTransferAsync(TransferScheduler scheduler, CancellationToken cancellationToken) { await Task.Yield(); this.Resume(scheduler, cancellationToken); if (0 == this.enumerationStarted) { // Got nothing from checkpoint, start directory transfer from the very beginning. var subDirTransfer = new SubDirectoryTransfer(this, ""); lock (this.continuationTokenLock) { if (null == this.Journal) { this.ongoingSubDirTransfers.TryAdd(subDirTransfer, new object()); } this.enumerationStarted = 1; } if (null != this.Journal) { this.Journal.AddOngoingSubDirTransfer(subDirTransfer); this.Journal?.UpdateJournalItem(this); } this.ScheduleSubDirectoryTransfer( subDirTransfer, this.cancellationTokenSource.Token, null, -1); } bool gotDirectory = true; while (true) { Utils.CheckCancellation(this.cancellationTokenSource.Token); if (!gotDirectory) { newAddSubDirResetEventSlim.Wait(cancellationToken); newAddSubDirResetEventSlim.Reset(); } // Check whether theres ongoing subdirectory listing thread. bool listCompleted = (1 == Interlocked.Read(ref this.outstandingTasks)); string subDirRelativePath = null; if (null != this.Journal) { subDirRelativePath = this.Journal.PeekSubDirTransfer(); } else { this.subDirectories.TryPeek(out subDirRelativePath); } if (string.IsNullOrEmpty(subDirRelativePath)) { if (listCompleted) { // There's no ongoing subdirectory listing thread, // and no subdirectory pending on listing // This means that the whole listing is completed. break; } gotDirectory = false; continue; } else { gotDirectory = true; Utils.CheckCancellation(this.cancellationTokenSource.Token); SubDirectoryTransfer subDirTransfer = new SubDirectoryTransfer(this, subDirRelativePath); this.ScheduleSubDirectoryTransfer( subDirTransfer, this.cancellationTokenSource.Token, () => { if (null != this.Journal) { this.Journal.AddOngoingSubDirTransfer(subDirTransfer); this.Journal.RemoveFirstSubDirTransfer(); } else { this.ongoingSubDirTransfers.TryAdd(subDirTransfer, new object()); this.subDirectories.TryDequeue(out subDirRelativePath); } }, -1); } } }
public IEnumerable <SubDirectoryTransfer> ListSubDirTransfers() { long currentOffset = this.OngoingSubDirTransferChunkHead; bool shouldBreak = false; while (true) { SubDirectoryTransfer transfer = null; lock (this.journalLock) { if (0 == this.OngoingSubDirTransferChunkHead) { shouldBreak = true; } else { this.stream.Position = currentOffset; long previousUsedChunk = this.ReadLong(); long nextUsedChunk = this.ReadLong(); if (0 == previousUsedChunk) { if (this.OngoingSubDirTransferChunkHead != currentOffset) { #if !NO_FILEFORMAT_EX throw new FileFormatException(Resources.RestartableLogCorrupted); #else throw new InvalidOperationException(Resources.RestartableLogCorrupted); #endif } } else { if (this.OngoingSubDirTransferChunkHead == currentOffset) { #if !NO_FILEFORMAT_EX throw new FileFormatException(Resources.RestartableLogCorrupted); #else throw new InvalidOperationException(Resources.RestartableLogCorrupted); #endif } } try { #if BINARY_SERIALIZATION transfer = this.formatter.Deserialize(this.stream) as SubDirectoryTransfer; #else transfer = this.ReadObject(this.subDirTransferSerializer) as SubDirectoryTransfer; #endif } catch { #if !NO_FILEFORMAT_EX throw new FileFormatException(Resources.RestartableLogCorrupted); #else throw new InvalidOperationException(Resources.RestartableLogCorrupted); #endif } if (null == transfer) { #if !NO_FILEFORMAT_EX throw new FileFormatException(Resources.RestartableLogCorrupted); #else throw new InvalidOperationException(Resources.RestartableLogCorrupted); #endif } transfer.StreamJournalOffset = currentOffset + 2 * sizeof(long); transfer.Journal = this; this.stream.Position = transfer.StreamJournalOffset + 4096; #if BINARY_SERIALIZATION transfer.ListContinuationToken = this.formatter.Deserialize(this.stream) as SerializableListContinuationToken; #else transfer.ListContinuationToken = this.ReadObject(this.continuationTokenSerializer) as SerializableListContinuationToken; #endif transfer.ListContinuationToken.Journal = this; transfer.ListContinuationToken.StreamJournalOffset = transfer.StreamJournalOffset + 4096; if (0 == nextUsedChunk) { if (this.OngoingSubDirTransferChunkTail != currentOffset) { #if !NO_FILEFORMAT_EX throw new FileFormatException(Resources.RestartableLogCorrupted); #else throw new InvalidOperationException(Resources.RestartableLogCorrupted); #endif } shouldBreak = true; } else { if (this.OngoingSubDirTransferChunkTail == currentOffset) { #if !NO_FILEFORMAT_EX throw new FileFormatException(Resources.RestartableLogCorrupted); #else throw new InvalidOperationException(Resources.RestartableLogCorrupted); #endif } } currentOffset = nextUsedChunk; } } if (null != transfer) { yield return(transfer); } if (shouldBreak) { yield break; } } }