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
* 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
* validated" resources filled in.
* @param unpacked a set to populate with unpacked resources.
@@ -1247,30 +1250,31 @@ public class Application
List<Resource> rsrcs = getAllActiveResources();
List<Resource> failures = new ArrayList<Resource>();
// total up the file size of the resources to validate
long totalSize = 0L;
for (Resource rsrc : rsrcs) {
totalSize += rsrc.getLocal().length();
// obtain the sizes of the resources to validate
long[] sizes = new long[rsrcs.size()];
for (int ii = 0; ii < sizes.length; ii++) {
sizes[ii] = rsrcs.get(ii).getLocal().length();
}
MetaProgressObserver mpobs = new MetaProgressObserver(obs, totalSize);
ProgressAggregator pagg = new ProgressAggregator(obs, sizes);
boolean noUnpack = SysProps.noUnpack();
for (Resource rsrc : rsrcs) {
for (int ii = 0; ii < sizes.length; ii++) {
Resource rsrc = rsrcs.get(ii);
if (Thread.interrupted()) {
throw new InterruptedException("m.applet_stopped");
}
mpobs.startElement(rsrc.getLocal().length());
ProgressObserver robs = pagg.startElement(ii);
if (rsrc.isMarkedValid()) {
if (alreadyValid != null) {
alreadyValid[0]++;
}
mpobs.progress(100);
robs.progress(100);
continue;
}
try {
if (_digest.validateResource(rsrc, mpobs)) {
if (_digest.validateResource(rsrc, robs)) {
// unpack this resource if appropriate
if (noUnpack || !rsrc.shouldUnpack()) {
// finally note that this resource is kosher
@@ -1290,7 +1294,7 @@ public class Application
"rsrc", rsrc, "error", e);
} finally {
mpobs.progress(100);
robs.progress(100);
}
failures.add(rsrc);
}
@@ -1308,27 +1312,31 @@ public class Application
{
List<Resource> rsrcs = getActiveResources();
// total up the file size of the resources to unpack
long totalSize = 0L;
// remove resources that we don't want to unpack
for (Iterator<Resource> it = rsrcs.iterator(); it.hasNext(); ) {
Resource rsrc = it.next();
if (rsrc.shouldUnpack() && !unpacked.contains(rsrc)) {
totalSize += rsrc.getLocal().length();
} else {
if (!rsrc.shouldUnpack() || unpacked.contains(rsrc)) {
it.remove();
}
}
MetaProgressObserver mpobs = new MetaProgressObserver(obs, totalSize);
for (Resource rsrc : rsrcs) {
// obtain the sizes of the resources to unpack
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()) {
throw new InterruptedException("m.applet_stopped");
}
mpobs.startElement(rsrc.getLocal().length());
Resource rsrc = rsrcs.get(ii);
ProgressObserver pobs = pagg.startElement(ii);
if (!rsrc.unpack()) {
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.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
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.ConnectionUtil;
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.VersionUtil;
@@ -665,13 +666,14 @@ public abstract class Getdown extends Thread
setStep(Step.PATCH);
updateStatus("m.patching");
// create a new ProgressObserver that divides the different patching phases
MetaProgressObserver mprog = new MetaProgressObserver(_progobs, list.size());
for (Resource prsrc : list) {
mprog.startElement(1);
long[] sizes = new long[list.size()];
Arrays.fill(sizes, 1L);
ProgressAggregator pragg = new ProgressAggregator(_progobs, sizes);
int ii = 0; for (Resource prsrc : list) {
ProgressObserver pobs = pragg.startElement(ii++);
try {
Patcher patcher = new Patcher();
patcher.patch(prsrc.getLocal().getParentFile(), prsrc.getLocal(), mprog);
patcher.patch(prsrc.getLocal().getParentFile(), prsrc.getLocal(), pobs);
} catch (Exception 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;
}