/// <summary> Write the contents of a stream to a writer. </summary> /// <param name="writer"> To be written to. </param> /// <param name="stream"> To be read from. </param> /// <param name="buffer"> Temporary buffer for copying data. </param> /// <param name="buffer2"> /// Optional secondary buffer. If null, the function may allocate a /// secondary buffer itself. In both cases, the secondary buffer will /// be returned by the function (if null, and none was created, then /// null will be returned). /// </param> /// <param name="thenCommit"> /// If true, commit the writer after writing the last buffer. /// </param> /// <param name="cancel"></param> private static async Task <byte[]> WriteAsync( StoreWriter writer, Stream stream, byte[] buffer, byte[] buffer2, bool thenCommit, CancellationToken cancel) { var bufferSize = buffer.Length; // The task that writes data in the background. Returns the buffer it // was using when it ends and doesn't need to buffer anymore, so that // it can be reused in a double-buffering scheme. var writing = Task.FromResult(buffer2); while (true) // Read all pages and write them { var offset = 0; // Current offset within 'buffer' int read; // Bytes returned by last 'ReadAsync', zero if EoS do // Read a page of size 'bufferSize' { offset += read = await stream .ReadAsync(buffer, offset, bufferSize - offset, cancel) .ConfigureAwait(false); } while (offset < bufferSize && read > 0); if (offset == 0) { break; } var isLast = read == 0; // Swap buffers and start writing. var next = await writing.ConfigureAwait(false); writing = InternalWrite(writer, buffer, offset, isLast && thenCommit, cancel); if (isLast) { break; } // Allocate a second buffer, but only if we need one buffer = next ?? (buffer2 = new byte[bufferSize]); } await writing.ConfigureAwait(false); return(buffer2); }
/// <see cref="WriteAsync(IWriteOnlyStore,Stream,int,CancellationToken)"/> private static async Task <byte[]> InternalWrite(StoreWriter writer, byte[] buffer, int count, bool thenCommit, CancellationToken cancel) { // This method returns the byte array to facilitate the control flow. // This way, the byte array is reserved until the write task completes. if (thenCommit) { await writer.WriteAndCommitAsync(buffer, 0, count, cancel); } else { await writer.WriteAsync(buffer, 0, count, cancel); } return(buffer); }
public BufferedCASStream(StoreWriter w, bool commit = true) { _w = w; _commit = commit; }