// 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);
}