comparison src/org/tmatesoft/hg/internal/RevlogStreamWriter.java @ 618:7c0d2ce340b8

Refactor approach how content finds it way down to a commit revision
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Thu, 16 May 2013 19:46:13 +0200
parents 65c01508f002
children 6526d8adbc0f
comparison
equal deleted inserted replaced
617:65c01508f002 618:7c0d2ce340b8
17 package org.tmatesoft.hg.internal; 17 package org.tmatesoft.hg.internal;
18 18
19 import static org.tmatesoft.hg.internal.Internals.REVLOGV1_RECORD_SIZE; 19 import static org.tmatesoft.hg.internal.Internals.REVLOGV1_RECORD_SIZE;
20 import static org.tmatesoft.hg.repo.HgRepository.NO_REVISION; 20 import static org.tmatesoft.hg.repo.HgRepository.NO_REVISION;
21 21
22 import java.io.File;
23 import java.io.IOException; 22 import java.io.IOException;
24 import java.nio.ByteBuffer; 23 import java.nio.ByteBuffer;
25 24
26 import org.tmatesoft.hg.core.HgIOException; 25 import org.tmatesoft.hg.core.HgIOException;
27 import org.tmatesoft.hg.core.Nodeid; 26 import org.tmatesoft.hg.core.Nodeid;
28 import org.tmatesoft.hg.core.SessionContext; 27 import org.tmatesoft.hg.core.SessionContext;
28 import org.tmatesoft.hg.internal.DataSerializer.ByteArrayDataSerializer;
29 import org.tmatesoft.hg.internal.DataSerializer.ByteArrayDataSource;
30 import org.tmatesoft.hg.internal.DataSerializer.DataSource;
29 import org.tmatesoft.hg.repo.HgInvalidControlFileException; 31 import org.tmatesoft.hg.repo.HgInvalidControlFileException;
30 import org.tmatesoft.hg.repo.HgInvalidStateException; 32 import org.tmatesoft.hg.repo.HgInvalidStateException;
31 33
32 /** 34 /**
33 * 35 *
58 } 60 }
59 61
60 /** 62 /**
61 * @return nodeid of added revision 63 * @return nodeid of added revision
62 */ 64 */
63 public Nodeid addRevision(byte[] content, int linkRevision, int p1, int p2) throws HgIOException { 65 public Nodeid addRevision(DataSource content, int linkRevision, int p1, int p2) throws HgIOException {
64 lastEntryRevision = Nodeid.NULL; 66 lastEntryRevision = Nodeid.NULL;
65 int revCount = revlogStream.revisionCount(); 67 int revCount = revlogStream.revisionCount();
66 lastEntryIndex = revCount == 0 ? NO_REVISION : revCount - 1; 68 lastEntryIndex = revCount == 0 ? NO_REVISION : revCount - 1;
67 populateLastEntry(); 69 populateLastEntry();
68 // 70 //
69 Patch patch = GeneratePatchInspector.delta(lastEntryContent, content); 71 byte[] contentByteArray = toByteArray(content);
72 Patch patch = GeneratePatchInspector.delta(lastEntryContent, contentByteArray);
70 int patchSerializedLength = patch.serializedLength(); 73 int patchSerializedLength = patch.serializedLength();
71 74
72 final boolean writeComplete = preferCompleteOverPatch(patchSerializedLength, content.length); 75 final boolean writeComplete = preferCompleteOverPatch(patchSerializedLength, contentByteArray.length);
73 DataSerializer.DataSource dataSource = writeComplete ? new DataSerializer.ByteArrayDataSource(content) : patch.new PatchDataSource(); 76 DataSerializer.DataSource dataSource = writeComplete ? new ByteArrayDataSource(contentByteArray) : patch.new PatchDataSource();
74 revlogDataZip.reset(dataSource); 77 revlogDataZip.reset(dataSource);
75 final int compressedLen; 78 final int compressedLen;
76 final boolean useCompressedData = preferCompressedOverComplete(revlogDataZip.getCompressedLength(), dataSource.serializeLength()); 79 final boolean useCompressedData = preferCompressedOverComplete(revlogDataZip.getCompressedLength(), dataSource.serializeLength());
77 if (useCompressedData) { 80 if (useCompressedData) {
78 compressedLen= revlogDataZip.getCompressedLength(); 81 compressedLen= revlogDataZip.getCompressedLength();
81 compressedLen = dataSource.serializeLength() + 1 /*1 byte for 'u' - uncompressed prefix byte*/; 84 compressedLen = dataSource.serializeLength() + 1 /*1 byte for 'u' - uncompressed prefix byte*/;
82 } 85 }
83 // 86 //
84 Nodeid p1Rev = revision(p1); 87 Nodeid p1Rev = revision(p1);
85 Nodeid p2Rev = revision(p2); 88 Nodeid p2Rev = revision(p2);
86 byte[] revisionNodeidBytes = dh.sha1(p1Rev, p2Rev, content).asBinary(); 89 byte[] revisionNodeidBytes = dh.sha1(p1Rev, p2Rev, contentByteArray).asBinary();
87 // 90 //
88 91
89 DataSerializer indexFile, dataFile, activeFile; 92 DataSerializer indexFile, dataFile;
90 indexFile = dataFile = activeFile = null; 93 indexFile = dataFile = null;
91 try { 94 try {
92 // 95 //
93 activeFile = indexFile = revlogStream.getIndexStreamWriter(transaction); 96 indexFile = revlogStream.getIndexStreamWriter(transaction);
94 final boolean isInlineData = revlogStream.isInlineData(); 97 final boolean isInlineData = revlogStream.isInlineData();
95 HeaderWriter revlogHeader = new HeaderWriter(isInlineData); 98 HeaderWriter revlogHeader = new HeaderWriter(isInlineData);
96 revlogHeader.length(content.length, compressedLen); 99 revlogHeader.length(contentByteArray.length, compressedLen);
97 revlogHeader.nodeid(revisionNodeidBytes); 100 revlogHeader.nodeid(revisionNodeidBytes);
98 revlogHeader.linkRevision(linkRevision); 101 revlogHeader.linkRevision(linkRevision);
99 revlogHeader.parents(p1, p2); 102 revlogHeader.parents(p1, p2);
100 revlogHeader.baseRevision(writeComplete ? lastEntryIndex+1 : lastEntryBase); 103 revlogHeader.baseRevision(writeComplete ? lastEntryIndex+1 : lastEntryBase);
101 long lastEntryOffset = revlogStream.newEntryOffset(); 104 long lastEntryOffset = revlogStream.newEntryOffset();
106 if (isInlineData) { 109 if (isInlineData) {
107 dataFile = indexFile; 110 dataFile = indexFile;
108 } else { 111 } else {
109 dataFile = revlogStream.getDataStreamWriter(transaction); 112 dataFile = revlogStream.getDataStreamWriter(transaction);
110 } 113 }
111 activeFile = dataFile;
112 if (useCompressedData) { 114 if (useCompressedData) {
113 int actualCompressedLenWritten = revlogDataZip.writeCompressedData(dataFile); 115 int actualCompressedLenWritten = revlogDataZip.writeCompressedData(dataFile);
114 if (actualCompressedLenWritten != compressedLen) { 116 if (actualCompressedLenWritten != compressedLen) {
115 throw new HgInvalidStateException(String.format("Expected %d bytes of compressed data, but actually wrote %d in %s", compressedLen, actualCompressedLenWritten, revlogStream.getDataFileName())); 117 throw new HgInvalidStateException(String.format("Expected %d bytes of compressed data, but actually wrote %d in %s", compressedLen, actualCompressedLenWritten, revlogStream.getDataFileName()));
116 } 118 }
118 dataFile.writeByte((byte) 'u'); 120 dataFile.writeByte((byte) 'u');
119 dataSource.serialize(dataFile); 121 dataSource.serialize(dataFile);
120 } 122 }
121 123
122 124
123 lastEntryContent = content; 125 lastEntryContent = contentByteArray;
124 lastEntryBase = revlogHeader.baseRevision(); 126 lastEntryBase = revlogHeader.baseRevision();
125 lastEntryIndex++; 127 lastEntryIndex++;
126 lastEntryRevision = Nodeid.fromBinary(revisionNodeidBytes, 0); 128 lastEntryRevision = Nodeid.fromBinary(revisionNodeidBytes, 0);
127 revisionCache.put(lastEntryIndex, lastEntryRevision); 129 revisionCache.put(lastEntryIndex, lastEntryRevision);
128 130
129 revlogStream.revisionAdded(lastEntryIndex, lastEntryRevision, lastEntryBase, lastEntryOffset); 131 revlogStream.revisionAdded(lastEntryIndex, lastEntryRevision, lastEntryBase, lastEntryOffset);
130 } catch (IOException ex) {
131 String m = String.format("Failed to write revision %d", lastEntryIndex+1, null);
132 // FIXME proper file in the exception based on activeFile == dataFile || indexFile
133 throw new HgIOException(m, ex, new File(revlogStream.getDataFileName()));
134 } finally { 132 } finally {
135 indexFile.done(); 133 indexFile.done();
136 if (dataFile != null && dataFile != indexFile) { 134 if (dataFile != null && dataFile != indexFile) {
137 dataFile.done(); 135 dataFile.done();
138 } 136 }
139 } 137 }
140 return lastEntryRevision; 138 return lastEntryRevision;
141 } 139 }
142 140
141 private byte[] toByteArray(DataSource content) throws HgIOException {
142 ByteArrayDataSerializer ba = new ByteArrayDataSerializer();
143 content.serialize(ba);
144 return ba.toByteArray();
145 }
146
143 private Nodeid revision(int revisionIndex) { 147 private Nodeid revision(int revisionIndex) {
144 if (revisionIndex == NO_REVISION) { 148 if (revisionIndex == NO_REVISION) {
145 return Nodeid.NULL; 149 return Nodeid.NULL;
146 } 150 }
147 Nodeid n = revisionCache.get(revisionIndex); 151 Nodeid n = revisionCache.get(revisionIndex);
249 public HeaderWriter nodeid(byte[] nodeidBytes) { 253 public HeaderWriter nodeid(byte[] nodeidBytes) {
250 nodeid = nodeidBytes; 254 nodeid = nodeidBytes;
251 return this; 255 return this;
252 } 256 }
253 257
254 public void serialize(DataSerializer out) throws IOException { 258 public void serialize(DataSerializer out) throws HgIOException {
255 header.clear(); 259 header.clear();
256 if (offset == 0) { 260 if (offset == 0) {
257 int version = 1 /* RevlogNG */; 261 int version = 1 /* RevlogNG */;
258 if (isInline) { 262 if (isInline) {
259 version |= RevlogStream.INLINEDATA; 263 version |= RevlogStream.INLINEDATA;