Add an object encapsulating the state of a PackWriter

Exposes essentially the same state machine to the programmer as is
exposed to the client via a ProgressMonitor, using a wrapper around
beginTask()/endTask().

Change-Id: Ic3622b4acea65d2b9b3551c668806981fa7293e3
This commit is contained in:
Dave Borowitz 2011-11-10 12:49:15 -08:00
parent e7ec5e1473
commit 16b8ebf2d1
3 changed files with 108 additions and 14 deletions

View File

@ -215,6 +215,7 @@ hunkDisconnectedFromFile=Hunk disconnected from file
hunkHeaderDoesNotMatchBodyLineCountOf=Hunk header {0} does not match body line count of {1}
illegalArgumentNotA=Not {0}
illegalCombinationOfArguments=The combination of arguments {0} and {1} is not allowed
illegalPackingPhase=Illegal packing phase {0}
illegalStateExists=exists {0}
improperlyPaddedBase64Input=Improperly padded Base64 input.
inMemoryBufferLimitExceeded=In-memory buffer limit exceeded

View File

@ -275,6 +275,7 @@ public static JGitText get() {
/***/ public String hunkHeaderDoesNotMatchBodyLineCountOf;
/***/ public String illegalArgumentNotA;
/***/ public String illegalCombinationOfArguments;
/***/ public String illegalPackingPhase;
/***/ public String illegalStateExists;
/***/ public String improperlyPaddedBase64Input;
/***/ public String inMemoryBufferLimitExceeded;

View File

@ -174,6 +174,8 @@ public class PackWriter {
private final Statistics stats;
private final MutableState state;
private Statistics.ObjectType typeStats;
private List<ObjectToPack> sortedByName;
@ -266,6 +268,7 @@ public PackWriter(final PackConfig config, final ObjectReader reader) {
reuseDeltas = config.isReuseDeltas();
reuseValidate = true; // be paranoid by default
stats = new Statistics();
state = new MutableState();
}
/**
@ -744,6 +747,37 @@ private List<ObjectToPack> sortByName() {
return sortedByName;
}
private void beginPhase(PackingPhase phase, ProgressMonitor monitor,
int cnt) {
state.phase = phase;
String task;
switch (phase) {
case COUNTING:
task = JGitText.get().countingObjects;
break;
case GETTING_SIZES:
task = JGitText.get().searchForSizes;
break;
case FINDING_SOURCES:
task = JGitText.get().searchForReuse;
break;
case COMPRESSING:
task = JGitText.get().compressingObjects;
break;
case WRITING:
task = JGitText.get().writingObjects;
break;
default:
throw new IllegalArgumentException(
MessageFormat.format(JGitText.get().illegalPackingPhase, phase));
}
monitor.beginTask(task, cnt);
}
private void endPhase(ProgressMonitor monitor) {
monitor.endTask();
}
/**
* Write the prepared pack to the supplied stream.
* <p>
@ -803,7 +837,7 @@ public void writePack(ProgressMonitor compressMonitor,
long objCnt = getObjectCount();
stats.totalObjects = objCnt;
writeMonitor.beginTask(JGitText.get().writingObjects, (int) objCnt);
beginPhase(PackingPhase.WRITING, writeMonitor, (int) objCnt);
long writeStart = System.currentTimeMillis();
out.writeFileHeader(PACK_VERSION_GENERATED, objCnt);
@ -843,7 +877,7 @@ public void writePack(ProgressMonitor compressMonitor,
}
reader.release();
writeMonitor.endTask();
endPhase(writeMonitor);
}
/**
@ -855,6 +889,11 @@ public Statistics getStatistics() {
return stats;
}
/** @return snapshot of the current state of this PackWriter. */
public State getState() {
return state.snapshot();
}
/** Release all resources used by this writer. */
public void release() {
reader.release();
@ -872,7 +911,7 @@ private void searchForReuse(ProgressMonitor monitor) throws IOException {
cnt += objectsLists[Constants.OBJ_TAG].size();
long start = System.currentTimeMillis();
monitor.beginTask(JGitText.get().searchForReuse, cnt);
beginPhase(PackingPhase.FINDING_SOURCES, monitor, cnt);
if (cnt <= 4096) {
// For small object counts, do everything as one list.
@ -897,7 +936,7 @@ private void searchForReuse(ProgressMonitor monitor) throws IOException {
searchForReuse(monitor, objectsLists[Constants.OBJ_TAG]);
}
monitor.endTask();
endPhase(monitor);
stats.timeSearchingForReuse = System.currentTimeMillis() - start;
}
@ -944,7 +983,7 @@ private void searchForDeltas(ProgressMonitor monitor)
// abort with an exception if we actually had to have it.
//
final long sizingStart = System.currentTimeMillis();
monitor.beginTask(JGitText.get().searchForSizes, cnt);
beginPhase(PackingPhase.GETTING_SIZES, monitor, cnt);
AsyncObjectSizeQueue<ObjectToPack> sizeQueue = reader.getObjectSize(
Arrays.<ObjectToPack> asList(list).subList(0, cnt), false);
try {
@ -989,7 +1028,7 @@ else if (sz <= DeltaIndex.BLKSZ)
} finally {
sizeQueue.release();
}
monitor.endTask();
endPhase(monitor);
stats.timeSearchingForSizes = System.currentTimeMillis() - sizingStart;
// Sort the objects by path hash so like files are near each other,
@ -1035,9 +1074,9 @@ public int compare(ObjectToPack a, ObjectToPack b) {
return;
final long searchStart = System.currentTimeMillis();
monitor.beginTask(JGitText.get().compressingObjects, nonEdgeCnt);
beginPhase(PackingPhase.COMPRESSING, monitor, nonEdgeCnt);
searchForDeltas(monitor, list, cnt);
monitor.endTask();
endPhase(monitor);
stats.deltaSearchNonEdgeObjects = nonEdgeCnt;
stats.timeCompressing = System.currentTimeMillis() - searchStart;
@ -1400,8 +1439,7 @@ private void findObjectsToPack(final ProgressMonitor countingMonitor,
throws MissingObjectException, IOException,
IncorrectObjectTypeException {
final long countingStart = System.currentTimeMillis();
countingMonitor.beginTask(JGitText.get().countingObjects,
ProgressMonitor.UNKNOWN);
beginPhase(PackingPhase.COUNTING, countingMonitor, ProgressMonitor.UNKNOWN);
if (have == null)
have = Collections.emptySet();
@ -1447,7 +1485,7 @@ private void findObjectsToPack(final ProgressMonitor countingMonitor,
cachedPacks.addAll(shortCircuit);
for (CachedPack pack : shortCircuit)
countingMonitor.update((int) pack.getObjectCount());
countingMonitor.endTask();
endPhase(countingMonitor);
stats.timeCounting = System.currentTimeMillis() - countingStart;
return;
}
@ -1537,8 +1575,8 @@ private void findObjectsToPack(final ProgressMonitor countingMonitor,
wantObjs, haveObjs, pack);
commits = new BlockList<RevCommit>();
countingMonitor.endTask();
countingMonitor.beginTask(JGitText.get().countingObjects,
endPhase(countingMonitor);
beginPhase(PackingPhase.COUNTING, countingMonitor,
ProgressMonitor.UNKNOWN);
continue;
}
@ -1625,7 +1663,7 @@ private void findObjectsToPack(final ProgressMonitor countingMonitor,
for (CachedPack pack : cachedPacks)
countingMonitor.update((int) pack.getObjectCount());
countingMonitor.endTask();
endPhase(countingMonitor);
stats.timeCounting = System.currentTimeMillis() - countingStart;
}
@ -2099,4 +2137,58 @@ public String getMessage() {
reusedObjects, reusedDeltas);
}
}
private class MutableState {
private volatile PackingPhase phase;
MutableState() {
phase = PackingPhase.COUNTING;
}
State snapshot() {
return new State(phase);
}
}
/** Possible states that a PackWriter can be in. */
public static enum PackingPhase {
/** Counting objects phase. */
COUNTING,
/** Getting sizes phase. */
GETTING_SIZES,
/** Finding sources phase. */
FINDING_SOURCES,
/** Compressing objects phase. */
COMPRESSING,
/** Writing objects phase. */
WRITING;
}
/** Summary of the current state of a PackWriter. */
public class State {
private final PackingPhase phase;
State(PackingPhase phase) {
this.phase = phase;
}
/** @return the PackConfig used to build the writer. */
public PackConfig getConfig() {
return config;
}
/** @return the current phase of the writer. */
public PackingPhase getPhase() {
return phase;
}
@Override
public String toString() {
return "PackWriter.State[" + phase + "]";
}
}
}