Mercurial > hg4j
comparison src/com/tmate/hgkit/ll/RevlogStream.java @ 5:fc265ddeab26
File content and non-effective, although working, patch application
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Tue, 21 Dec 2010 05:11:06 +0100 |
parents | aa1912c70b36 |
children | 5abe5af181bd |
comparison
equal
deleted
inserted
replaced
4:aa1912c70b36 | 5:fc265ddeab26 |
---|---|
1 /** | 1 /** |
2 * Copyright (c) 2010 Artem Tikhomirov | 2 * Copyright (c) 2010 Artem Tikhomirov |
3 */ | 3 */ |
4 package com.tmate.hgkit.ll; | 4 package com.tmate.hgkit.ll; |
5 | |
6 import static com.tmate.hgkit.ll.HgRepository.TIP; | |
5 | 7 |
6 import java.io.BufferedInputStream; | 8 import java.io.BufferedInputStream; |
7 import java.io.DataInput; | 9 import java.io.DataInput; |
8 import java.io.DataInputStream; | 10 import java.io.DataInputStream; |
9 import java.io.EOFException; | 11 import java.io.EOFException; |
72 initOutline(); | 74 initOutline(); |
73 final int indexSize = index.size(); | 75 final int indexSize = index.size(); |
74 if (indexSize == 0) { | 76 if (indexSize == 0) { |
75 return; | 77 return; |
76 } | 78 } |
77 if (end == -1 /*FIXME TIP*/) { | 79 if (end == TIP) { |
78 end = indexSize - 1; | 80 end = indexSize - 1; |
81 } | |
82 if (start == TIP) { | |
83 start = indexSize - 1; | |
79 } | 84 } |
80 if (start < 0 || start >= indexSize) { | 85 if (start < 0 || start >= indexSize) { |
81 throw new IllegalArgumentException("Bad left range boundary " + start); | 86 throw new IllegalArgumentException("Bad left range boundary " + start); |
82 } | 87 } |
83 if (end < start || end >= indexSize) { | 88 if (end < start || end >= indexSize) { |
89 diIndex = getIndexStream(); | 94 diIndex = getIndexStream(); |
90 if (needData && !inline) { | 95 if (needData && !inline) { |
91 diData = getDataStream(); | 96 diData = getDataStream(); |
92 } | 97 } |
93 try { | 98 try { |
94 int skipped = diIndex.skipBytes(inline ? (int) index.get(start).offset : start * 64); | |
95 byte[] lastData = null; | 99 byte[] lastData = null; |
96 for (int i = start; i <= end; i++ ) { | 100 int i; |
97 IndexEntry ie = index.get(i); | 101 boolean extraReadsToBaseRev = false; |
102 if (needData && index.get(start).baseRevision < start) { | |
103 i = index.get(start).baseRevision; | |
104 extraReadsToBaseRev = true; | |
105 } else { | |
106 i = start; | |
107 } | |
108 diIndex.skipBytes(inline ? (int) index.get(i).offset : start * 64); | |
109 for (; i <= end; i++ ) { | |
98 long l = diIndex.readLong(); | 110 long l = diIndex.readLong(); |
99 long offset = l >>> 16; | 111 long offset = l >>> 16; |
100 int flags = (int) (l & 0X0FFFF); | 112 int flags = (int) (l & 0X0FFFF); |
101 int compressedLen = diIndex.readInt(); | 113 int compressedLen = diIndex.readInt(); |
102 int actualLen = diIndex.readInt(); | 114 int actualLen = diIndex.readInt(); |
112 if (needData) { | 124 if (needData) { |
113 byte[] dataBuf = new byte[compressedLen]; | 125 byte[] dataBuf = new byte[compressedLen]; |
114 if (inline) { | 126 if (inline) { |
115 diIndex.readFully(dataBuf); | 127 diIndex.readFully(dataBuf); |
116 } else { | 128 } else { |
117 diData.skipBytes((int) ie.offset); // FIXME not skip but seek!!! (skip would work only for the first time) | 129 diData.skipBytes((int) index.get(i).offset); // FIXME not skip but seek!!! (skip would work only for the first time) |
118 diData.readFully(dataBuf); | 130 diData.readFully(dataBuf); |
119 } | 131 } |
120 if (dataBuf[0] == 0x78 /* 'x' */) { | 132 if (dataBuf[0] == 0x78 /* 'x' */) { |
121 try { | 133 try { |
122 Inflater zlib = new Inflater(); | 134 Inflater zlib = new Inflater(); |
143 // this is a patch | 155 // this is a patch |
144 LinkedList<PatchRecord> patches = new LinkedList<PatchRecord>(); | 156 LinkedList<PatchRecord> patches = new LinkedList<PatchRecord>(); |
145 int patchElementIndex = 0; | 157 int patchElementIndex = 0; |
146 do { | 158 do { |
147 final int x = patchElementIndex; // shorthand | 159 final int x = patchElementIndex; // shorthand |
148 int p1 = (data[x] << 24) | (data[x+1] << 16) | (data[x+2] << 8) | data[x+3]; | 160 int p1 = ((data[x] & 0xFF)<< 24) | ((data[x+1] & 0xFF) << 16) | ((data[x+2] & 0xFF) << 8) | (data[x+3] & 0xFF); |
149 int p2 = (data[x+4] << 24) | (data[x+5] << 16) | (data[x+6] << 8) | data[x+7]; | 161 int p2 = ((data[x+4] & 0xFF) << 24) | ((data[x+5] & 0xFF) << 16) | ((data[x+6] & 0xFF) << 8) | (data[x+7] & 0xFF); |
150 int len = (data[x+8] << 24) | (data[x+9] << 16) | (data[x+10] << 8) | data[x+11]; | 162 int len = ((data[x+8] & 0xFF) << 24) | ((data[x+9] & 0xFF) << 16) | ((data[x+10] & 0xFF) << 8) | (data[x+11] & 0xFF); |
151 patchElementIndex += 12 + len; | 163 patchElementIndex += 12 + len; |
152 patches.add(new PatchRecord(p1, p2, len, data, x+12)); | 164 patches.add(new PatchRecord(p1, p2, len, data, x+12)); |
153 } while (patchElementIndex < data.length); | 165 } while (patchElementIndex < data.length); |
154 // | 166 // |
155 byte[] baseRevContent; | 167 byte[] baseRevContent = lastData; |
156 if (baseRevision == i - 1) { | |
157 baseRevContent = lastData; | |
158 } else { | |
159 // FIXME implement delta collection from few revisions | |
160 // read baseRevision plus all deltas between this revision and base. Need to do this effectively. | |
161 throw HgRepository.notImplemented(); | |
162 } | |
163 | |
164 // FIXME need to collect all patches between baseRevision and current version | |
165 data = apply(baseRevContent, patches); | 168 data = apply(baseRevContent, patches); |
166 } | 169 } |
167 } else { | 170 } else { |
168 if (inline) { | 171 if (inline) { |
169 diIndex.skipBytes(compressedLen); | 172 diIndex.skipBytes(compressedLen); |
170 } | 173 } |
171 } | 174 } |
172 inspector.next(i, actualLen, baseRevision, linkRevision, parent1Revision, parent2Revision, buf, data); | 175 if (!extraReadsToBaseRev || i >= start) { |
176 inspector.next(i, actualLen, baseRevision, linkRevision, parent1Revision, parent2Revision, buf, data); | |
177 } | |
173 lastData = data; | 178 lastData = data; |
174 } | 179 } |
175 } catch (EOFException ex) { | 180 } catch (EOFException ex) { |
176 // should not happen as long as we read inside known boundaries | 181 // should not happen as long as we read inside known boundaries |
177 throw new IllegalStateException(ex); | 182 throw new IllegalStateException(ex); |
194 final int INLINEDATA = 1 << 16; | 199 final int INLINEDATA = 1 << 16; |
195 inline = (versionField & INLINEDATA) != 0; | 200 inline = (versionField & INLINEDATA) != 0; |
196 long offset = 0; // first offset is always 0, thus Hg uses it for other purposes | 201 long offset = 0; // first offset is always 0, thus Hg uses it for other purposes |
197 while(true) { // EOFExcepiton should get us outta here. FIXME Our inputstream should has explicit no-more-data indicator | 202 while(true) { // EOFExcepiton should get us outta here. FIXME Our inputstream should has explicit no-more-data indicator |
198 int compressedLen = di.readInt(); | 203 int compressedLen = di.readInt(); |
199 // 8+4 = 12 bytes total read | 204 // 8+4 = 12 bytes total read here |
200 // int actualLen = di.readInt(); | 205 int actualLen = di.readInt(); |
201 // int baseRevision = di.readInt(); | 206 int baseRevision = di.readInt(); |
207 // 12 + 8 = 20 bytes read here | |
202 // int linkRevision = di.readInt(); | 208 // int linkRevision = di.readInt(); |
203 // int parent1Revision = di.readInt(); | 209 // int parent1Revision = di.readInt(); |
204 // int parent2Revision = di.readInt(); | 210 // int parent2Revision = di.readInt(); |
205 // byte[] nodeid = new byte[32]; | 211 // byte[] nodeid = new byte[32]; |
206 if (inline) { | 212 if (inline) { |
207 res.add(new IndexEntry(offset + 64*res.size(), compressedLen)); | 213 res.add(new IndexEntry(offset + 64*res.size(), baseRevision)); |
208 di.skipBytes(5*4 + 32 + compressedLen); // Check: 52 (skip) + 12 (read) = 64 (total RevlogNG record size) | 214 di.skipBytes(3*4 + 32 + compressedLen); // Check: 44 (skip) + 20 (read) = 64 (total RevlogNG record size) |
209 } else { | 215 } else { |
210 res.add(new IndexEntry(offset, compressedLen)); | 216 res.add(new IndexEntry(offset, baseRevision)); |
211 di.skipBytes(5*4 + 32); | 217 di.skipBytes(3*4 + 32); |
212 } | 218 } |
213 long l = di.readLong(); | 219 long l = di.readLong(); |
214 offset = l >>> 16; | 220 offset = l >>> 16; |
215 } | 221 } |
216 } catch (EOFException ex) { | 222 } catch (EOFException ex) { |
239 } | 245 } |
240 } | 246 } |
241 | 247 |
242 | 248 |
243 // perhaps, package-local or protected, if anyone else from low-level needs them | 249 // perhaps, package-local or protected, if anyone else from low-level needs them |
250 // XXX think over if we should keep offset in case of separate data file - we read the field anyway. Perhaps, distinct entry classes for Inline and non-inline indexes? | |
244 private static class IndexEntry { | 251 private static class IndexEntry { |
245 public final long offset; // for separate .i and .d - copy of index record entry, for inline index - actual offset of the record in the .i file (record entry + revision * record size)) | 252 public final long offset; // for separate .i and .d - copy of index record entry, for inline index - actual offset of the record in the .i file (record entry + revision * record size)) |
246 public final int length; // data past fixed record (need to decide whether including header size or not), and whether length is of compressed data or not | 253 //public final int length; // data past fixed record (need to decide whether including header size or not), and whether length is of compressed data or not |
247 | 254 public final int baseRevision; |
248 public IndexEntry(long o, int l) { | 255 |
256 public IndexEntry(long o, int baseRev) { | |
249 offset = o; | 257 offset = o; |
250 length = l; | 258 baseRevision = baseRev; |
251 } | 259 } |
252 } | 260 } |
253 | 261 |
254 // mpatch.c : apply() | 262 // mpatch.c : apply() |
255 // FIXME need to implement patch merge (fold, combine, gather and discard from aforementioned mpatch.[c|py]), also see Revlog and Mercurial PDF | 263 // FIXME need to implement patch merge (fold, combine, gather and discard from aforementioned mpatch.[c|py]), also see Revlog and Mercurial PDF |