// regenerate blob locally. // we need to either download byte ranges from Azure. // OR // need to copy from local file. private void RegenerateBlob(string containerName, string blobName, List <RemainingBytes> byteRangesToDownload, string localFilePath, List <BlockSignature> reusableBlockSignatures, SizeBasedCompleteSignature blobSig, int parallelFactor = 2) { // removing size from the equation. var allBlobSigs = blobSig.Signatures.Values.SelectMany(x => x.SignatureList).OrderBy(a => a.Offset).ToList(); // LUT to see if block is to be reused or not. var reusableBlockDict = CommonOps.GenerateBlockDict(reusableBlockSignatures.ToArray()); var offset = 0L; using (var localStream = new FileStream(localFilePath, FileMode.Open)) using (var newStream = new FileStream(localFilePath + ".new", FileMode.Create)) { // go through all sigs in offset order.... determine if can reuse or need to download. foreach (var sig in allBlobSigs) { var haveMatch = false; if (reusableBlockDict.ContainsKey(sig.RollingSig)) { // have a match... so will reuse local file. var localSig = reusableBlockDict[sig.RollingSig]; var matchingLocalSigs = localSig.Where(s => s.MD5Signature.SequenceEqual(sig.MD5Signature)) .Select(n => n) .ToList(); if (matchingLocalSigs.Any()) { // have a match. var matchingLocalSig = matchingLocalSigs[0]; // huge amount of wasted allocations... maybe move this. var buffer = new byte[matchingLocalSig.Size]; localStream.Seek(matchingLocalSig.Offset, SeekOrigin.Begin); localStream.Read(buffer, 0, (int)matchingLocalSig.Size); newStream.Seek(sig.Offset, SeekOrigin.Begin); newStream.Write(buffer, 0, (int)matchingLocalSig.Size); haveMatch = true; offset += matchingLocalSig.Size; } } if (!haveMatch) { // check if we have byte ranges starting at offset. var byteRange = (from b in byteRangesToDownload where b.BeginOffset == offset select b).FirstOrDefault(); if (byteRange != null) { // download bytes. var blobBytes = DownloadBytes(containerName, blobName, byteRange.BeginOffset, byteRange.EndOffset, parallelFactor); newStream.Seek(sig.Offset, SeekOrigin.Begin); newStream.Write(blobBytes, 0, (int)(byteRange.EndOffset - byteRange.BeginOffset + 1)); offset += (byteRange.EndOffset - byteRange.BeginOffset + 1); } } } } // rename .new file to original File.Replace(localFilePath + ".new", localFilePath, null); }