public WaitHandle WriteAsync(Block block, long offset, Action <IAsyncResult <Block> > callback, CancellationToken cancellationToken) { ThrowIf.Argument.IsNull(block, nameof(block)); ThrowIf.Argument.LessThanZero(offset, nameof(offset)); ThrowIf.Argument.IsNull(callback, nameof(callback)); if (block.Index == -1) { var wh = new ManualResetEvent(initialState: true); callback(new ValueResult <Block>(block, wh)); return(wh); } var waitHandle = new ManualResetEvent(initialState: false); Action <States, CancellationToken> writerStateMachine = null; Exception exception = null; writerStateMachine = (state, token) => { if (token.IsCancellationRequested) { waitHandle.Set(); return; } switch (state) { case States.Start: try { WriteBlock(block.Payload, offset, block.Size); _scheduler.ScheduleWorkItem(() => writerStateMachine(States.Success, token)); } catch (Exception ex) { exception = ex; _scheduler.ScheduleWorkItem(() => writerStateMachine(States.Error, token)); } break; case States.Success: callback(new ValueResult <Block>(block, waitHandle)); _scheduler.ScheduleWorkItem(() => writerStateMachine(States.Finalize, CancellationToken.None)); break; case States.Error: callback(new ExceptionResult <Block>(exception, waitHandle)); _scheduler.ScheduleWorkItem(() => writerStateMachine(States.Finalize, CancellationToken.None)); break; case States.Finalize: RemoveAwaiter(waitHandle); waitHandle.Set(); break; default: throw new ArgumentOutOfRangeException($"Unknown state: {state}"); } }; _scheduler.ScheduleWorkItem(() => writerStateMachine(States.Start, cancellationToken)); StoreAwaiter(waitHandle); return(waitHandle); }
public WaitHandle ReadAsync(Action <IAsyncResult <Block> > callback, CancellationToken cancellationToken = default) { ThrowIf.Argument.IsNull(callback, nameof(callback)); var waitHandle = new ManualResetEvent(initialState: false); Action <int, CancellationToken> readStateMachine = null; Exception exception = null; Block block = null; readStateMachine = (state, token) => { switch (state) { case 0: if (_isFaulted) { exception = new AggregateException(GetExceptions()); _scheduler.ScheduleWorkItem(() => readStateMachine(4, CancellationToken.None)); return; } // try to get block if (TryDequeue(out Block _block)) { block = _block; _scheduler.ScheduleWorkItem(() => readStateMachine(1, token)); return; } if (_endOfStream) { _scheduler.ScheduleWorkItem(() => readStateMachine(3, token)); } else { _scheduler.ScheduleWorkItem(() => readStateMachine(2, token)); } break; case 1: // success callback(new ValueResult <Block>(block, waitHandle)); _scheduler.ScheduleWorkItem( workItem: () => readStateMachine(5, CancellationToken.None)); break; case 2: // retry _scheduler.ScheduleWorkItem(() => readStateMachine(0, token)); break; case 3: // end of steam callback(new ValueResult <Block>(Block.NullBlock(), waitHandle)); _scheduler.ScheduleWorkItem( workItem: () => readStateMachine(5, CancellationToken.None)); break; case 4: // exception callback(new ExceptionResult <Block>(exception, waitHandle)); _scheduler.ScheduleWorkItem( workItem: () => readStateMachine(5, CancellationToken.None)); break; case 5: // finalizing waitHandle.Set(); break; } }; _scheduler.ScheduleWorkItem(() => readStateMachine(0, cancellationToken)); return(waitHandle); }
public void Start(CancellationToken cancellationToken) { Action <States, CancellationToken> archStateMachine = null; archStateMachine = (state, token) => { if (token.IsCancellationRequested) { //TODO: try to delete target file. IsCancelled = true; _waitHandle.Set(); return; } switch (state) { case States.Start: Interlocked.Increment(ref _readRequestCount); _reader.ReadAsync(asyncBlockResult => { try { var block = asyncBlockResult.Result; if (block.Index >= 0) { AddToBuffer(block); _scheduler.ScheduleWorkItem(() => archStateMachine(States.Write, token)); _scheduler.ScheduleWorkItem(() => archStateMachine(States.NextItem, token)); } else { _scheduler.ScheduleWorkItem(() => archStateMachine(States.EndOfSteam, token)); } } catch (Exception ex) { SetException(ex); _scheduler.ScheduleWorkItem(() => archStateMachine(States.Error, token)); } finally { Interlocked.Decrement(ref _readRequestCount); } }, token); break; case States.Write: if (TryGetNextBlock(out Block block, out long offset)) { Interlocked.Increment(ref _writeRequestCount); _writer.WriteAsync(block, offset, asyncBlockResult => { try { var block = asyncBlockResult.Result; }catch (Exception ex) { SetException(ex); _scheduler.ScheduleWorkItem(() => archStateMachine(States.Error, token)); } finally { Interlocked.Decrement(ref _writeRequestCount); } }, token); } break; case States.NextItem: archStateMachine(States.Start, cancellationToken); break; case States.EndOfSteam: _endOfStream = true; if (_readRequestCount != 0 || _writeRequestCount != 0 || _buffer.Count > 0) { _scheduler.ScheduleWorkItem(() => archStateMachine(States.EndOfSteam, token)); // wait spinner } else { _scheduler.ScheduleWorkItem(() => archStateMachine(States.Finalize, CancellationToken.None)); } break; case States.Error: //SetException(exception); _scheduler.ScheduleWorkItem(() => archStateMachine(States.Finalize, CancellationToken.None)); break; case States.Finalize: _waitHandle.Set(); break; default: throw new ArgumentOutOfRangeException($"Unknown state: {state}"); } }; _scheduler.ScheduleWorkItem(() => archStateMachine(States.Start, cancellationToken)); }
public WaitHandle ReadAsync(Action <IAsyncResult <Block> > callback, CancellationToken cancellationToken) { var waitHandle = new ManualResetEvent(initialState: false); Action <int, CancellationToken> readStateMachine = null; Block block = null; Exception exception = null; readStateMachine = (state, token) => { if (token.IsCancellationRequested) { RemoveAwaiter(waitHandle); waitHandle.Set(); callback(new OperationCancelledResult <Block>(waitHandle)); return; } switch (state) { case 0: var blockIdx = GetNextBlockIndex(); var offset = (long)blockIdx * _blockSizeInBytes; _scheduler.ScheduleWorkItem( workItem: () => { try { block = ReadBlock(blockIdx, offset); } catch (Exception ex) { exception = ex; } }, callback: () => { if (block != null) { readStateMachine(1, token); } else { readStateMachine(2, token); } }); break; case 1: // success _scheduler.ScheduleWorkItem( workItem: () => callback(new ValueResult <Block>(block, waitHandle)), callback: () => readStateMachine(3, token)); break; case 2: // exception _scheduler.ScheduleWorkItem( workItem: () => callback(new ExceptionResult <Block>(exception, waitHandle)), callback: () => readStateMachine(3, token)); break; case 3: // finalizing RemoveAwaiter(waitHandle); waitHandle.Set(); break; } }; StoreAwaiter(waitHandle); _scheduler.ScheduleWorkItem(() => readStateMachine(0, cancellationToken), callback: null); return(waitHandle); }
public WaitHandle ReadAsync(Action <IAsyncResult <Block> > callback, CancellationToken cancellationToken) { var waitHandle = new ManualResetEvent(initialState: false); Action <States, CancellationToken> readerStateMachine = null; Block block = null; Block compressedBlock = null; Exception exception = null; readerStateMachine = (state, token) => { switch (state) { case States.Start: _reader.ReadAsync(blockAsyncResult => { try { block = blockAsyncResult.Result; if (block.Index >= 0) { _scheduler.ScheduleWorkItem(() => readerStateMachine(States.Compress, token)); } else { _scheduler.ScheduleWorkItem(() => readerStateMachine(States.EndOfStream, token)); } } catch (Exception ex) { exception = ex; _scheduler.ScheduleWorkItem(() => readerStateMachine(States.Error, token)); } }, token); break; case States.EndOfStream: callback(new ValueResult <Block>(block, waitHandle)); _scheduler.ScheduleWorkItem(() => readerStateMachine(States.Finalize, CancellationToken.None)); break; case States.Compress: // compress try { int size; byte[] data; (size, data) = CompressBlock(block.Payload, block.Size, _compressionLevel); compressedBlock = new Block(block.Index, block.Capacity, data, size); _scheduler.ScheduleWorkItem(() => readerStateMachine(States.Success, token)); } catch (Exception ex) { exception = ex; _scheduler.ScheduleWorkItem(() => readerStateMachine(States.Error, token)); } break; case States.Success: // success callback(new ValueResult <Block>(compressedBlock, waitHandle)); _scheduler.ScheduleWorkItem(() => readerStateMachine(States.Finalize, CancellationToken.None)); break; case States.Error: // error callback(new ExceptionResult <Block>(exception, waitHandle)); _scheduler.ScheduleWorkItem(() => readerStateMachine(States.Finalize, CancellationToken.None)); break; case States.Finalize: // finalize waitHandle.Set(); break; } }; _scheduler.ScheduleWorkItem(() => readerStateMachine(0, cancellationToken)); return(waitHandle); }