/// <summary> Write a stream to a store. </summary> /// <remarks> Reads forward from the current position of the stream. </remarks> public static Task <WrittenBlob> WriteAsync( this IWriteOnlyStore store, Stream stream, CancellationToken cancel) => // Default buffer size is 4MB, because Azure Storage likes it. store.WriteAsync(stream, 4 * 1024 * 1024, cancel);
/// <summary> Write a buffer of bytes to the store. </summary> public static async Task <WrittenBlob> WriteAsync( this IWriteOnlyStore store, byte[] buffer, int offset, int count, CancellationToken cancel) { using (var writer = store.StartWriting()) return(await writer.WriteAndCommitAsync(buffer, offset, count, cancel).ConfigureAwait(false)); }
private static async Task <WrittenBlob> ImportBlobUnchecked(this IWriteOnlyStore store, IReadBlobRef srcBlob, CancellationToken cancel) { using (var writer = store.StartWriting()) { using (var reader = await srcBlob.OpenAsync(cancel).ConfigureAwait(false)) { await writer.WriteAsync(reader.ReadAsync, null, cancel).ConfigureAwait(false); } return(await writer.CommitAsync(cancel).ConfigureAwait(false)); } }
/// <summary> /// Copies blobs from <paramref name="source"/> store to <paramref name="destination"/> store. /// Also, this checks that the blobs exist, and that there is no error in the hash of those blobs. /// When these checks fail, an exception is raised, and the task fails. /// </summary> /// <param name="hashes">designates the blobs to be copied</param> /// <param name="accountId">the account of <paramref name="source"/> store. only helps with error messages</param> /// <returns></returns> public static async Task <WrittenBlob[]> ImportBlobs( this IWriteOnlyStore destination, IReadOnlyStore source, IReadOnlyCollection <Hash> hashes, long?accountId = null, CancellationToken cancel = default) { var checkExistTasks = hashes.Select( h => source[h].ExistsAsync(cancel) ).ToArray(); bool[] exist = await Task.WhenAll(checkExistTasks); int i = 0; foreach (var h in hashes) { if (!exist[i]) { throw new NoSuchBlobException(accountId?.ToString() ?? "<unknown>", h); } } var copyTasks = hashes.Select( h => destination.ImportBlobUnchecked(source[h], cancel)).ToArray(); var writtenBlobs = await Task.WhenAll(copyTasks).ConfigureAwait(false); List <(Hash orig, Hash result)> badHashes = null; i = 0; foreach (var orig in hashes) { var blob = writtenBlobs[i++]; if (!blob.Hash.Equals(orig)) { badHashes = badHashes ?? new List <(Hash orig, Hash result)>(); badHashes.Add((orig, blob.Hash)); } } if (badHashes != null) { string details = string.Join("\n", badHashes.Select(_ => $" {accountId}/{_.orig}: {_.result}")); throw new Exception("Bad hash(es) detected: " + details); } return(writtenBlobs); }
/// <summary> Write a stream to a store. </summary> /// <remarks> Reads forward from the current position of the stream. </remarks> public static async Task <WrittenBlob> WriteAsync( this IWriteOnlyStore store, Stream stream, int bufferSize, CancellationToken cancel) { // Don't allocate memory we don't need. if (stream.CanSeek && stream.Length < bufferSize) { bufferSize = (int)stream.Length; } using (var writer = store.StartWriting()) { var buffer = new byte[bufferSize]; await WriteAsync(writer, stream, buffer, null, true, cancel).ConfigureAwait(false); return(await writer.CommitAsync(cancel).ConfigureAwait(false)); } }
/// <summary> Write an entire buffer of bytes to the store. </summary> public static Task <WrittenBlob> WriteAsync( this IWriteOnlyStore store, byte[] buffer, CancellationToken cancel) => store.WriteAsync(buffer, 0, buffer.Length, cancel);