private static void WriteChunk(IBinaryWriter binaryWriter, HgChunk chunk) { const int chunkHeaderSize = 84; var chunkDataLength = chunk.Data.Length; binaryWriter.Write(chunkDataLength + chunkHeaderSize); binaryWriter.Write(chunk.NodeID.NodeID); binaryWriter.Write(chunk.FirstParentNodeID.NodeID); binaryWriter.Write(chunk.SecondParentNodeID.NodeID); binaryWriter.Write(chunk.ChangesetNodeID.NodeID); binaryWriter.Write(chunk.Data); }
private IEnumerable<HgChunk> ReadBundleGroup(IBinaryReader binaryReader) { const uint nullChunkMaxSize = 4; const int chunkHeaderSize = 84; uint length; while((length = binaryReader.ReadUInt32()) > nullChunkMaxSize) { var nodeID = new HgNodeID(binaryReader.ReadBytes(20)); var firstParentNodeID = new HgNodeID(binaryReader.ReadBytes(20)); var secondParentNodeID = new HgNodeID(binaryReader.ReadBytes(20)); var changesetNodeID = new HgNodeID(binaryReader.ReadBytes(20)); var dataLength = (int)length - chunkHeaderSize; var data = new byte[dataLength]; binaryReader.Read(data, 0, dataLength); var chunk = new HgChunk(nodeID, firstParentNodeID, secondParentNodeID, changesetNodeID, data); yield return chunk; } // while }
private IEnumerable<HgChunk> BuildBundleGroup(HgRepository hgRepository, HgRevlog hgRevlog, HgRevset hgRevset, Action<HgRevlogEntryData> callback = null) { var hgRevlogReader = new HgRevlogReader(hgRevlog, fileSystem); // // See http://stackoverflow.com/a/10359273/60188. Pure magic var revisionChunks = hgRevset. Select(hre => hre.Revision). OrderBy(r => r). Select((r, i) => new { r, i }). GroupBy(x => x.r - x.i). Select(x => x.Select(xx => xx.r)). Select(c => c.ToArray()). ToArray(); if(revisionChunks.Length == 0) yield break; byte[] prev = null; uint prevRev = uint.MaxValue; var prediff = false; var hgRevlogEntry = hgRevlog[revisionChunks[0][0]]; if(hgRevlogEntry.FirstParentRevisionNodeID != HgNodeID.Null) { prev = hgRevlogReader.ReadRevlogEntry(hgRevlogEntry.FirstParentRevision).Data; prediff = true; } foreach(var revisionChunk in revisionChunks) { foreach(var revision in revisionChunk) { hgRevlogEntry = hgRevlog[revision]; var hgChangeset = hgRepository.Changelog.Revlog[hgRevlogEntry.LinkRevision]; byte[] data = null; if(prev == null || hgRevlogEntry.BaseRevision == hgRevlogEntry.Revision || prediff || (prevRev != UInt32.MaxValue && prevRev + 1 != revision)) { var hgRevlogEntryData = hgRevlogReader.ReadRevlogEntry(revision); if(prev == null) { // // Trivial case var buffer = new byte[hgRevlogEntryData.Data.Length + 12]; using(var stream = new MemoryStream(buffer)) using(var binaryWriter = new BigEndianBinaryWriter(stream)) { binaryWriter.Write((uint)0); binaryWriter.Write((uint)0); binaryWriter.Write((uint)hgRevlogEntryData.Data.Length); binaryWriter.Write(hgRevlogEntryData.Data); } // using data = buffer; } // if else { data = BDiff.Diff(prev, hgRevlogEntryData.Data); if(prediff) prediff = false; } // else prev = hgRevlogEntryData.Data; } // if else { data = hgRevlogReader.ReadRevlogEntryDataRaw(revision); prev = MPatch.Patch(prev, new List<byte[]> { data }); } // else if(callback != null) callback(new HgRevlogEntryData(hgRevlogEntry, prev)); if(performIntegrityChecks) { var expectedNodeID = GetRevlogEntryDataNodeID(hgRevlogEntry.FirstParentRevisionNodeID, hgRevlogEntry.SecondParentRevisionNodeID, prev); if(expectedNodeID != hgRevlogEntry.NodeID) { // TODO: Exception class throw new ApplicationException("integrity violation for " + hgRevlogEntry.NodeID.Short); } // if } // if var hgChunk = new HgChunk(hgRevlogEntry.NodeID, hgRevlogEntry.FirstParentRevisionNodeID, hgRevlogEntry.SecondParentRevisionNodeID, hgChangeset.NodeID, data); yield return hgChunk; prevRev = revision; } // foreach } // foreach }