Mercurial > jhg
diff src/org/tmatesoft/hg/internal/RevlogStream.java @ 263:31f67be94e71
RevlogStream - reduce number of object instances, reuse when possible
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Thu, 18 Aug 2011 18:06:44 +0200 |
parents | e5776067b3b8 |
children | 6bb5e7ed051a |
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/internal/RevlogStream.java Thu Aug 18 03:46:36 2011 +0200 +++ b/src/org/tmatesoft/hg/internal/RevlogStream.java Thu Aug 18 18:06:44 2011 +0200 @@ -23,6 +23,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.zip.Inflater; import org.tmatesoft.hg.core.HgBadStateException; import org.tmatesoft.hg.core.Nodeid; @@ -337,6 +338,9 @@ private Lifecycle.BasicCallback cb = null; private int lastRevisionRead = BAD_REVISION; private DataAccess lastUserData; + // next are to track two major bottlenecks - patch application and actual time spent in inspector +// private long applyTime, inspectorTime; + public ReaderN1(boolean needData, Inspector insp) { assert insp != null; @@ -353,6 +357,7 @@ cb = new Lifecycle.BasicCallback(); ((Lifecycle) inspector).start(totalWork, cb, cb); } +// applyTime = inspectorTime = 0; } public void finish() { @@ -367,8 +372,9 @@ if (daData != null) { daData.done(); } +// System.out.printf("applyTime:%d ms, inspectorTime: %d ms\n", applyTime, inspectorTime); } - + public boolean range(int start, int end) throws IOException { byte[] nodeidBuf = new byte[20]; int i; @@ -394,7 +400,12 @@ daIndex.seek(getIndexOffsetInt(i)); // + // reuse some instances final ArrayList<PatchRecord> patches = new ArrayList<PatchRecord>(); + final Inflater inflater = new Inflater(); + // can share buffer between instances of InflaterDataAccess as I never read any two of them in parallel + final byte[] inflaterBuffer = new byte[1024]; + // for (; i <= end; i++ ) { if (inline && needData) { @@ -432,7 +443,8 @@ } else { final byte firstByte = streamDataAccess.readByte(); if (firstByte == 0x78 /* 'x' */) { - userDataAccess = new InflaterDataAccess(streamDataAccess, streamOffset, compressedLen, patchToPrevious ? -1 : actualLen); + inflater.reset(); + userDataAccess = new InflaterDataAccess(streamDataAccess, streamOffset, compressedLen, patchToPrevious ? -1 : actualLen, inflater, inflaterBuffer); } else if (firstByte == 0x75 /* 'u' */) { userDataAccess = new FilterDataAccess(streamDataAccess, streamOffset+1, compressedLen-1); } else { @@ -444,6 +456,7 @@ // XXX if (patchToPrevious) { // this is a patch + patches.clear(); // won't hurt to ensure there are no leftovers, even if we already cleaned while (!userDataAccess.isEmpty()) { PatchRecord pr = PatchRecord.read(userDataAccess); // System.out.printf("PatchRecord:%d %d %d\n", pr.start, pr.end, pr.len); @@ -451,8 +464,14 @@ } userDataAccess.done(); // + // it shall be reset at the end of prev iteration, when it got assigned from userDataAccess + // however, actual userDataAccess and lastUserData may share Inflater object, which needs to be reset + // Alternatively, userDataAccess.done() above may be responsible to reset Inflater (if it's InflaterDataAccess) + lastUserData.reset(); +// final long startMeasuring = System.currentTimeMillis(); byte[] userData = apply(lastUserData, actualLen, patches); - patches.clear(); +// applyTime += (System.currentTimeMillis() - startMeasuring); + patches.clear(); // do not keep any reference, allow PatchRecord to be gc'd userDataAccess = new ByteArrayDataAccess(userData); } } else { @@ -461,7 +480,9 @@ } } if (!extraReadsToBaseRev || i >= start) { +// final long startMeasuring = System.currentTimeMillis(); inspector.next(i, actualLen, baseRevision, linkRevision, parent1Revision, parent2Revision, nodeidBuf, userDataAccess); +// inspectorTime += (System.currentTimeMillis() - startMeasuring); } if (cb != null) { if (cb.isStopped()) { @@ -469,12 +490,12 @@ } } if (userDataAccess != null) { - userDataAccess.reset(); - if (lastUserData != null) { - lastUserData.done(); - } - lastUserData = userDataAccess; + userDataAccess.reset(); // not sure this is necessary here, as lastUserData would get reset anyway before next use. } + if (lastUserData != null) { + lastUserData.done(); + } + lastUserData = userDataAccess; } lastRevisionRead = end; return true; @@ -497,7 +518,8 @@ int last = 0, destIndex = 0; if (outcomeLen == -1) { outcomeLen = baseRevisionContent.length(); - for (PatchRecord pr : patch) { + for (int i = 0, x = patch.size(); i < x; i++) { + PatchRecord pr = patch.get(i); outcomeLen += pr.start - last + pr.len; last = pr.end; } @@ -505,7 +527,8 @@ last = 0; } byte[] rv = new byte[outcomeLen]; - for (PatchRecord pr : patch) { + for (int i = 0, x = patch.size(); i < x; i++) { + PatchRecord pr = patch.get(i); baseRevisionContent.seek(last); baseRevisionContent.readBytes(rv, destIndex, pr.start-last); destIndex += pr.start - last;