public static SignatureSearchResult SearchLocalFileForSignatures(string localFilePath, SizeBasedCompleteSignature sig) { var result = new SignatureSearchResult(); // length of file. var tempFile = File.Open(localFilePath, FileMode.Open); var fileLength = tempFile.Length; tempFile.Close(); var offset = 0; var windowSize = ConfigHelper.SignatureSize; var windowBuffer = new byte[windowSize]; // signatures we can reuse. var signaturesToReuse = new List <BlockSignature>(); // get sizes of signatures (block sizes) from existing sig. // then loop through all sizes looking for matches in local file. // important to search from largest to smallest. var signatureSizes = sig.Signatures.Keys.ToList(); signatureSizes.Sort(); signatureSizes.Reverse(); // byte ranges that have not been matched to existing blocks yet. var remainingByteList = new List <RemainingBytes>(); remainingByteList.Add(new RemainingBytes { BeginOffset = 0, EndOffset = fileLength - 1 }); // Create the memory-mapped file. using (var mmf = MemoryMappedFile.CreateFromFile(localFilePath, FileMode.Open)) { using (var accessor = mmf.CreateViewAccessor()) { // Any sigs smaller than 100 bytes? skip? // Valid? // Really want to avoid searching for single bytes everywhere. foreach (var sigSize in signatureSizes) { var sigs = sig.Signatures[sigSize]; var newRemainingByteList = SearchLocalFileForSignaturesBasedOnSize(sigs, accessor, remainingByteList, sigSize, fileLength, signaturesToReuse); remainingByteList = newRemainingByteList; } } } result.ByteRangesToUpload = remainingByteList; result.SignaturesToReuse = signaturesToReuse; return(result); }
// Uploads differences between existing blob and updated local file. // Have local file to reference, the search results (indicating which parts need to be uploaded) // container and blob name. private List <UploadedBlock> UploadDelta(string localFilePath, SignatureSearchResult searchResults, string containerName, string blobName, bool testMode = false) { var allUploadedBlocks = new List <UploadedBlock>(); // loop through each section of the search results. // create blob from each RemainingBytes instances. // reuse the blocks already in use. foreach (var remainingBytes in searchResults.ByteRangesToUpload) { var uploadedBlockList = UploadBytesParallel(remainingBytes, localFilePath, containerName, blobName, testMode); //var uploadedBlockList = UploadBytes(remainingBytes, localFilePath, containerName, blobName, testMode); allUploadedBlocks.AddRange(uploadedBlockList); } // once we're here we should have uploaded ALL new data to Azure Blob Storage. // We then need to send the "construct" blob message. // loop through existing blocks and get offset + blockId's. foreach (var sig in searchResults.SignaturesToReuse) { if (sig.MD5Signature != null) { var blockId = Convert.ToBase64String(sig.MD5Signature); allUploadedBlocks.Add(new UploadedBlock() { BlockId = blockId, Offset = sig.Offset, Size = sig.Size, Sig = sig, IsNew = false }); } } if (!testMode) { // needs to be sorted by offset so the final blob constructed is in correct order. var res = (from b in allUploadedBlocks orderby b.Offset ascending select b.BlockId); PutBlockList(res.ToArray(), containerName, blobName); } return(allUploadedBlocks); }