Mercurial > hg4j
comparison src/org/tmatesoft/hg/internal/RevlogStream.java @ 606:5daa42067e7c
Avoid mmap files when only few bytes are to be read
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Tue, 07 May 2013 14:16:35 +0200 |
| parents | cc7b0c4dc993 |
| children | 66f1cc23b906 |
comparison
equal
deleted
inserted
replaced
| 605:c56edf42be64 | 606:5daa42067e7c |
|---|---|
| 75 public RevlogStream(DataAccessProvider dap, File indexFile) { | 75 public RevlogStream(DataAccessProvider dap, File indexFile) { |
| 76 this.dataAccess = dap; | 76 this.dataAccess = dap; |
| 77 this.indexFile = indexFile; | 77 this.indexFile = indexFile; |
| 78 } | 78 } |
| 79 | 79 |
| 80 /*package*/ DataAccess getIndexStream() { | 80 /** |
| 81 // FIXME [1.1] must supply a hint that I'll need really few bytes of data (perhaps, at some offset) | 81 * @param shortRead pass <code>true</code> to indicate intention to read few revisions only (as opposed to reading most of/complete revlog) |
| 82 // to avoid mmap files when only few bytes are to be read (i.e. #dataLength()) | 82 * @return never <code>null</code>, empty {@link DataAccess} if no stream is available |
| 83 return dataAccess.createReader(indexFile); | 83 */ |
| 84 /*package*/ DataAccess getIndexStream(boolean shortRead) { | |
| 85 // shortRead hint helps to avoid mmap files when only | |
| 86 // few bytes are to be read (i.e. #dataLength()) | |
| 87 return dataAccess.createReader(indexFile, shortRead); | |
| 84 } | 88 } |
| 85 | 89 |
| 86 /*package*/ DataAccess getDataStream() { | 90 /*package*/ DataAccess getDataStream() { |
| 87 return dataAccess.createReader(getDataFile()); | 91 return dataAccess.createReader(getDataFile(), false); |
| 88 } | 92 } |
| 89 | 93 |
| 90 /*package*/ DataSerializer getIndexStreamWriter() { | 94 /*package*/ DataSerializer getIndexStreamWriter() { |
| 91 return dataAccess.createWriter(indexFile, true); | 95 return dataAccess.createWriter(indexFile, true); |
| 92 } | 96 } |
| 145 */ | 149 */ |
| 146 public int dataLength(int revisionIndex) throws HgInvalidControlFileException, HgInvalidRevisionException { | 150 public int dataLength(int revisionIndex) throws HgInvalidControlFileException, HgInvalidRevisionException { |
| 147 // XXX in fact, use of iterate() instead of this implementation may be quite reasonable. | 151 // XXX in fact, use of iterate() instead of this implementation may be quite reasonable. |
| 148 // | 152 // |
| 149 revisionIndex = checkRevisionIndex(revisionIndex); | 153 revisionIndex = checkRevisionIndex(revisionIndex); |
| 150 DataAccess daIndex = getIndexStream(); | 154 DataAccess daIndex = getIndexStream(true); |
| 151 try { | 155 try { |
| 152 int recordOffset = getIndexOffsetInt(revisionIndex); | 156 int recordOffset = getIndexOffsetInt(revisionIndex); |
| 153 daIndex.seek(recordOffset + 12); // 6+2+4 | 157 daIndex.seek(recordOffset + 12); // 6+2+4 |
| 154 int actualLen = daIndex.readInt(); | 158 int actualLen = daIndex.readInt(); |
| 155 return actualLen; | 159 return actualLen; |
| 166 * @throws HgInvalidControlFileException if attempt to read index file failed | 170 * @throws HgInvalidControlFileException if attempt to read index file failed |
| 167 * @throws HgInvalidRevisionException if revisionIndex argument doesn't represent a valid record in the revlog | 171 * @throws HgInvalidRevisionException if revisionIndex argument doesn't represent a valid record in the revlog |
| 168 */ | 172 */ |
| 169 public byte[] nodeid(int revisionIndex) throws HgInvalidControlFileException, HgInvalidRevisionException { | 173 public byte[] nodeid(int revisionIndex) throws HgInvalidControlFileException, HgInvalidRevisionException { |
| 170 revisionIndex = checkRevisionIndex(revisionIndex); | 174 revisionIndex = checkRevisionIndex(revisionIndex); |
| 171 DataAccess daIndex = getIndexStream(); | 175 DataAccess daIndex = getIndexStream(true); |
| 172 try { | 176 try { |
| 173 int recordOffset = getIndexOffsetInt(revisionIndex); | 177 int recordOffset = getIndexOffsetInt(revisionIndex); |
| 174 daIndex.seek(recordOffset + 32); | 178 daIndex.seek(recordOffset + 32); |
| 175 byte[] rv = new byte[20]; | 179 byte[] rv = new byte[20]; |
| 176 daIndex.readBytes(rv, 0, 20); | 180 daIndex.readBytes(rv, 0, 20); |
| 188 * @throws HgInvalidControlFileException if attempt to read index file failed | 192 * @throws HgInvalidControlFileException if attempt to read index file failed |
| 189 * @throws HgInvalidRevisionException if revisionIndex argument doesn't represent a valid record in the revlog | 193 * @throws HgInvalidRevisionException if revisionIndex argument doesn't represent a valid record in the revlog |
| 190 */ | 194 */ |
| 191 public int linkRevision(int revisionIndex) throws HgInvalidControlFileException, HgInvalidRevisionException { | 195 public int linkRevision(int revisionIndex) throws HgInvalidControlFileException, HgInvalidRevisionException { |
| 192 revisionIndex = checkRevisionIndex(revisionIndex); | 196 revisionIndex = checkRevisionIndex(revisionIndex); |
| 193 DataAccess daIndex = getIndexStream(); | 197 DataAccess daIndex = getIndexStream(true); |
| 194 try { | 198 try { |
| 195 int recordOffset = getIndexOffsetInt(revisionIndex); | 199 int recordOffset = getIndexOffsetInt(revisionIndex); |
| 196 daIndex.seek(recordOffset + 20); | 200 daIndex.seek(recordOffset + 20); |
| 197 int linkRev = daIndex.readInt(); | 201 int linkRev = daIndex.readInt(); |
| 198 return linkRev; | 202 return linkRev; |
| 224 * @throws HgInvalidControlFileException if attempt to read index file failed | 228 * @throws HgInvalidControlFileException if attempt to read index file failed |
| 225 */ | 229 */ |
| 226 public int findRevisionIndex(Nodeid nodeid) throws HgInvalidControlFileException { | 230 public int findRevisionIndex(Nodeid nodeid) throws HgInvalidControlFileException { |
| 227 // XXX this one may be implemented with iterate() once there's mechanism to stop iterations | 231 // XXX this one may be implemented with iterate() once there's mechanism to stop iterations |
| 228 final int indexSize = revisionCount(); | 232 final int indexSize = revisionCount(); |
| 229 DataAccess daIndex = getIndexStream(); | 233 DataAccess daIndex = getIndexStream(false); |
| 230 try { | 234 try { |
| 231 byte[] nodeidBuf = new byte[20]; | 235 byte[] nodeidBuf = new byte[20]; |
| 232 for (int i = 0; i < indexSize; i++) { | 236 for (int i = 0; i < indexSize; i++) { |
| 233 daIndex.skip(8); | 237 daIndex.skip(8); |
| 234 int compressedLen = daIndex.readInt(); | 238 int compressedLen = daIndex.readInt(); |
| 253 */ | 257 */ |
| 254 public long newEntryOffset() { | 258 public long newEntryOffset() { |
| 255 if (revisionCount() == 0) { | 259 if (revisionCount() == 0) { |
| 256 return 0; | 260 return 0; |
| 257 } | 261 } |
| 258 DataAccess daIndex = getIndexStream(); | 262 DataAccess daIndex = getIndexStream(true); |
| 259 int lastRev = revisionCount() - 1; | 263 int lastRev = revisionCount() - 1; |
| 260 try { | 264 try { |
| 261 int recordOffset = getIndexOffsetInt(lastRev); | 265 int recordOffset = getIndexOffsetInt(lastRev); |
| 262 daIndex.seek(recordOffset); | 266 daIndex.seek(recordOffset); |
| 263 long value = daIndex.readLong(); | 267 long value = daIndex.readLong(); |
| 419 | 423 |
| 420 private void initOutline() throws HgInvalidControlFileException { | 424 private void initOutline() throws HgInvalidControlFileException { |
| 421 if (outlineCached()) { | 425 if (outlineCached()) { |
| 422 return; | 426 return; |
| 423 } | 427 } |
| 424 DataAccess da = getIndexStream(); | 428 DataAccess da = getIndexStream(false); |
| 425 try { | 429 try { |
| 426 if (da.isEmpty()) { | 430 if (da.isEmpty()) { |
| 427 // do not fail with exception if stream is empty, it's likely intentional | 431 // do not fail with exception if stream is empty, it's likely intentional |
| 428 baseRevisions = new int[0]; | 432 baseRevisions = new int[0]; |
| 429 // empty revlog, likely to be populated, indicate we start with a single file | 433 // empty revlog, likely to be populated, indicate we start with a single file |
| 549 inspector = insp; | 553 inspector = insp; |
| 550 mergePatches = usePatchMerge; | 554 mergePatches = usePatchMerge; |
| 551 } | 555 } |
| 552 | 556 |
| 553 public void start(int totalWork, CachedRevision cachedRevision) { | 557 public void start(int totalWork, CachedRevision cachedRevision) { |
| 554 daIndex = getIndexStream(); | 558 daIndex = getIndexStream(totalWork <= 10); |
| 555 if (needData && !inline) { | 559 if (needData && !inline) { |
| 556 daData = getDataStream(); | 560 daData = getDataStream(); |
| 557 } | 561 } |
| 558 lifecycleListener = Adaptable.Factory.getAdapter(inspector, Lifecycle.class, null); | 562 lifecycleListener = Adaptable.Factory.getAdapter(inspector, Lifecycle.class, null); |
| 559 if (lifecycleListener != null) { | 563 if (lifecycleListener != null) { |
