From 0a217cada6773f099928ad8788e4472b7c8d5071 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Sun, 15 May 2016 12:52:08 -0700 Subject: [PATCH] MetaProgressObserver -> ProgressAggregator. This changes the way progress is aggregated so that we can do the various progress accumulating steps in parallel if we like. --- .../threerings/getdown/data/Application.java | 46 ++++++++++------- .../threerings/getdown/launcher/Getdown.java | 14 +++--- .../getdown/util/MetaProgressObserver.java | 38 -------------- .../getdown/util/ProgressAggregator.java | 50 +++++++++++++++++++ 4 files changed, 85 insertions(+), 63 deletions(-) delete mode 100644 src/main/java/com/threerings/getdown/util/MetaProgressObserver.java create mode 100644 src/main/java/com/threerings/getdown/util/ProgressAggregator.java diff --git a/src/main/java/com/threerings/getdown/data/Application.java b/src/main/java/com/threerings/getdown/data/Application.java index e800561..0027070 100644 --- a/src/main/java/com/threerings/getdown/data/Application.java +++ b/src/main/java/com/threerings/getdown/data/Application.java @@ -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 rsrcs = getAllActiveResources(); List failures = new ArrayList(); - // 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 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 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); } } diff --git a/src/main/java/com/threerings/getdown/launcher/Getdown.java b/src/main/java/com/threerings/getdown/launcher/Getdown.java index 80b9667..bc6b873 100644 --- a/src/main/java/com/threerings/getdown/launcher/Getdown.java +++ b/src/main/java/com/threerings/getdown/launcher/Getdown.java @@ -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); } diff --git a/src/main/java/com/threerings/getdown/util/MetaProgressObserver.java b/src/main/java/com/threerings/getdown/util/MetaProgressObserver.java deleted file mode 100644 index 887fd9f..0000000 --- a/src/main/java/com/threerings/getdown/util/MetaProgressObserver.java +++ /dev/null @@ -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; -} diff --git a/src/main/java/com/threerings/getdown/util/ProgressAggregator.java b/src/main/java/com/threerings/getdown/util/ProgressAggregator.java new file mode 100644 index 0000000..d65caf1 --- /dev/null +++ b/src/main/java/com/threerings/getdown/util/ProgressAggregator.java @@ -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; +}