MetaProgressObserver -> ProgressAggregator.

This changes the way progress is aggregated so that we can do the various
progress accumulating steps in parallel if we like.
This commit is contained in:
Michael Bayne
2016-05-15 12:52:08 -07:00
parent 949eb8d718
commit 0a217cada6
4 changed files with 85 additions and 63 deletions
@@ -1237,6 +1237,9 @@ public class Application
* that do not exist or fail the verification process will be returned. If all resources are * that do not exist or fail the verification process will be returned. If all resources are
* ready to go, null will be returned and the application is considered ready to run. * ready to go, null will be returned and the application is considered ready to run.
* *
* @param obs a progress observer that will be notified of verification progress. NOTE: this
* observer may be called from arbitrary threads, so if you update a UI based on calls to it,
* you have to take care to get back to your UI thread.
* @param alreadyValid if non-null a 1 element array that will have the number of "already * @param alreadyValid if non-null a 1 element array that will have the number of "already
* validated" resources filled in. * validated" resources filled in.
* @param unpacked a set to populate with unpacked resources. * @param unpacked a set to populate with unpacked resources.
@@ -1247,30 +1250,31 @@ public class Application
List<Resource> rsrcs = getAllActiveResources(); List<Resource> rsrcs = getAllActiveResources();
List<Resource> failures = new ArrayList<Resource>(); List<Resource> failures = new ArrayList<Resource>();
// total up the file size of the resources to validate // obtain the sizes of the resources to validate
long totalSize = 0L; long[] sizes = new long[rsrcs.size()];
for (Resource rsrc : rsrcs) { for (int ii = 0; ii < sizes.length; ii++) {
totalSize += rsrc.getLocal().length(); sizes[ii] = rsrcs.get(ii).getLocal().length();
} }
MetaProgressObserver mpobs = new MetaProgressObserver(obs, totalSize); ProgressAggregator pagg = new ProgressAggregator(obs, sizes);
boolean noUnpack = SysProps.noUnpack(); boolean noUnpack = SysProps.noUnpack();
for (Resource rsrc : rsrcs) { for (int ii = 0; ii < sizes.length; ii++) {
Resource rsrc = rsrcs.get(ii);
if (Thread.interrupted()) { if (Thread.interrupted()) {
throw new InterruptedException("m.applet_stopped"); throw new InterruptedException("m.applet_stopped");
} }
mpobs.startElement(rsrc.getLocal().length());
ProgressObserver robs = pagg.startElement(ii);
if (rsrc.isMarkedValid()) { if (rsrc.isMarkedValid()) {
if (alreadyValid != null) { if (alreadyValid != null) {
alreadyValid[0]++; alreadyValid[0]++;
} }
mpobs.progress(100); robs.progress(100);
continue; continue;
} }
try { try {
if (_digest.validateResource(rsrc, mpobs)) { if (_digest.validateResource(rsrc, robs)) {
// unpack this resource if appropriate // unpack this resource if appropriate
if (noUnpack || !rsrc.shouldUnpack()) { if (noUnpack || !rsrc.shouldUnpack()) {
// finally note that this resource is kosher // finally note that this resource is kosher
@@ -1290,7 +1294,7 @@ public class Application
"rsrc", rsrc, "error", e); "rsrc", rsrc, "error", e);
} finally { } finally {
mpobs.progress(100); robs.progress(100);
} }
failures.add(rsrc); failures.add(rsrc);
} }
@@ -1308,27 +1312,31 @@ public class Application
{ {
List<Resource> rsrcs = getActiveResources(); List<Resource> rsrcs = getActiveResources();
// total up the file size of the resources to unpack // remove resources that we don't want to unpack
long totalSize = 0L;
for (Iterator<Resource> it = rsrcs.iterator(); it.hasNext(); ) { for (Iterator<Resource> it = rsrcs.iterator(); it.hasNext(); ) {
Resource rsrc = it.next(); Resource rsrc = it.next();
if (rsrc.shouldUnpack() && !unpacked.contains(rsrc)) { if (!rsrc.shouldUnpack() || unpacked.contains(rsrc)) {
totalSize += rsrc.getLocal().length();
} else {
it.remove(); it.remove();
} }
} }
MetaProgressObserver mpobs = new MetaProgressObserver(obs, totalSize); // obtain the sizes of the resources to unpack
for (Resource rsrc : rsrcs) { long[] sizes = new long[rsrcs.size()];
for (int ii = 0; ii < sizes.length; ii++) {
sizes[ii] = rsrcs.get(ii).getLocal().length();
}
ProgressAggregator pagg = new ProgressAggregator(obs, sizes);
for (int ii = 0; ii < sizes.length; ii++) {
if (Thread.interrupted()) { if (Thread.interrupted()) {
throw new InterruptedException("m.applet_stopped"); throw new InterruptedException("m.applet_stopped");
} }
mpobs.startElement(rsrc.getLocal().length()); Resource rsrc = rsrcs.get(ii);
ProgressObserver pobs = pagg.startElement(ii);
if (!rsrc.unpack()) { if (!rsrc.unpack()) {
log.info("Failure unpacking resource", "rsrc", rsrc); log.info("Failure unpacking resource", "rsrc", rsrc);
} }
mpobs.progress(100); pobs.progress(100);
} }
} }
@@ -39,6 +39,7 @@ import java.net.URLConnection;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@@ -68,7 +69,7 @@ import com.threerings.getdown.tools.Patcher;
import com.threerings.getdown.util.ConfigUtil; import com.threerings.getdown.util.ConfigUtil;
import com.threerings.getdown.util.ConnectionUtil; import com.threerings.getdown.util.ConnectionUtil;
import com.threerings.getdown.util.LaunchUtil; import com.threerings.getdown.util.LaunchUtil;
import com.threerings.getdown.util.MetaProgressObserver; import com.threerings.getdown.util.ProgressAggregator;
import com.threerings.getdown.util.ProgressObserver; import com.threerings.getdown.util.ProgressObserver;
import com.threerings.getdown.util.VersionUtil; import com.threerings.getdown.util.VersionUtil;
@@ -665,13 +666,14 @@ public abstract class Getdown extends Thread
setStep(Step.PATCH); setStep(Step.PATCH);
updateStatus("m.patching"); updateStatus("m.patching");
// create a new ProgressObserver that divides the different patching phases long[] sizes = new long[list.size()];
MetaProgressObserver mprog = new MetaProgressObserver(_progobs, list.size()); Arrays.fill(sizes, 1L);
for (Resource prsrc : list) { ProgressAggregator pragg = new ProgressAggregator(_progobs, sizes);
mprog.startElement(1); int ii = 0; for (Resource prsrc : list) {
ProgressObserver pobs = pragg.startElement(ii++);
try { try {
Patcher patcher = new Patcher(); Patcher patcher = new Patcher();
patcher.patch(prsrc.getLocal().getParentFile(), prsrc.getLocal(), mprog); patcher.patch(prsrc.getLocal().getParentFile(), prsrc.getLocal(), pobs);
} catch (Exception e) { } catch (Exception e) {
log.warning("Failed to apply patch", "prsrc", prsrc, e); log.warning("Failed to apply patch", "prsrc", prsrc, e);
} }
@@ -1,38 +0,0 @@
//
// Getdown - application installer, patcher and launcher
// Copyright (C) 2004-2014 Three Rings Design, Inc.
// https://raw.github.com/threerings/getdown/master/LICENSE
package com.threerings.getdown.util;
/**
* Accumulates the progress from a number of elements into a single
* smoothly progressing progress.
*/
public class MetaProgressObserver implements ProgressObserver
{
public MetaProgressObserver (ProgressObserver target, long totalSize)
{
_target = target;
_totalSize = totalSize;
}
public void startElement (long elementSize)
{
// add the previous size
_accum += (_elementSize * 100);
// then set the new one
_elementSize = elementSize;
}
// documentation inherited from interface
public void progress (int percent)
{
if (_totalSize > 0) {
_target.progress((int)((_accum + (percent * _elementSize)) / _totalSize));
}
}
protected ProgressObserver _target;
protected long _totalSize, _accum, _elementSize;
}
@@ -0,0 +1,50 @@
//
// Getdown - application installer, patcher and launcher
// Copyright (C) 2004-2014 Three Rings Design, Inc.
// https://raw.github.com/threerings/getdown/master/LICENSE
package com.threerings.getdown.util;
/**
* Accumulates the progress from a number of (potentially parallel) elements into a single smoothly
* progressing progress.
*/
public class ProgressAggregator
{
public ProgressAggregator (ProgressObserver target, long[] sizes) {
_target = target;
_sizes = sizes;
_progress = new int[sizes.length];
}
public ProgressObserver startElement (final int index) {
return new ProgressObserver() {
public void progress (int percent) {
_sizes[index] = percent;
updateAggProgress();
}
};
}
protected void updateAggProgress () {
long totalSize = 0L, currentSize = 0L;
synchronized (this) {
for (int ii = 0, ll = _sizes.length; ii < ll; ii++) {
long size = _sizes[ii];
totalSize += size;
currentSize += (int)((size * _progress[ii])/100.0);
}
}
_target.progress((int)(100.0*currentSize / totalSize));
}
protected static long sum (long[] sizes) {
long totalSize = 0L;
for (long size : sizes) totalSize += size;
return totalSize;
}
protected ProgressObserver _target;
protected long[] _sizes;
protected int[] _progress;
}