Skip to content

Commit 1296cc6

Browse files
Merge pull request #421 from appdevforall/fix/ADFA-5160-clone-eta-warmup
ADFA-5160: warm up the clone-receive ETA before showing it
2 parents 8a4c425 + 9c3927c commit 1296cc6

3 files changed

Lines changed: 19 additions & 47 deletions

File tree

‎controller/app/src/main/java/org/iiab/controller/RsyncManager.java‎

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ public void startClient(Context context, ShareConfig config, String hostIp, int
139139

140140
String lastFile = "";
141141
int lastEmittedPct = 0; // ADFA-5160: smoothed percent, never walked back
142+
long firstProgressMs = 0L; // ADFA-5160 follow-up: anchor for the ETA warmup
143+
final long etaWarmupMs = 3000L; // hold the ETA until the speed sample settles
142144

143145
while ((line = reader.readLine()) != null) {
144146
if (isCancelled) {
@@ -162,15 +164,26 @@ public void startClient(Context context, ShareConfig config, String hostIp, int
162164
lastEmittedPct = pct;
163165

164166
// ADFA-5160: rsync's ETA is computed against its per-file plan, so it jumps
165-
// the same way the old percent did. When we have a whole-set total, derive
166-
// the ETA from the bytes still to go and the current speed instead.
167-
String eta = progress.eta;
167+
// the same way the old percent did — and its first samples report a tiny
168+
// instantaneous speed, so an ETA derived then reads as thousands of hours.
169+
// Hold the ETA for a short warmup, then compute it from the AVERAGE speed
170+
// (bytes moved / elapsed), which is steadier than rsync's instantaneous
171+
// figure and smooths the mid-transfer jitter too. The bar and speed keep
172+
// moving during the warmup; only the ETA waits.
173+
if (firstProgressMs == 0L) firstProgressMs = System.currentTimeMillis();
174+
long elapsedMs = System.currentTimeMillis() - firstProgressMs;
175+
176+
String eta;
168177
if (expectedTotalBytes > 0) {
169-
double bps = RsyncProgress.parseSpeedBytesPerSec(progress.speed);
170-
if (bps > 0) {
178+
if (elapsedMs >= etaWarmupMs && progress.bytes > 0) {
179+
double avgBps = progress.bytes / (elapsedMs / 1000.0);
171180
long remaining = Math.max(0L, expectedTotalBytes - progress.bytes);
172-
eta = RsyncProgress.formatEta((long) (remaining / bps));
181+
eta = RsyncProgress.formatEta((long) (remaining / avgBps));
182+
} else {
183+
eta = "…"; // warmup: no bogus figure yet
173184
}
185+
} else {
186+
eta = progress.eta; // no whole-set total: rsync's own ETA
174187
}
175188

176189
String finalFile = lastFile;

‎controller/app/src/main/java/org/iiab/controller/sync/domain/RsyncProgress.java‎

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,6 @@ private RsyncProgress(long bytes, int percent, String speed, String eta) {
4141
private static final Pattern STATS =
4242
Pattern.compile("Total transferred file size:\\s+([\\d,\\.]+)\\s+bytes");
4343

44-
// ADFA-5160: rsync's speed column, e.g. "12.34MB/s" / "512.00B/s". Used to turn the
45-
// whole-set remaining bytes into a whole-set ETA, instead of rsync's own ETA, which is
46-
// computed against its per-file plan and jumps the same way the old percent did.
47-
private static final Pattern SPEED =
48-
Pattern.compile("([\\d\\.]+)([kMGT]?B)/s");
49-
5044
/**
5145
* Parses one rsync {@code --info=progress2} line. Returns {@code null} if the
5246
* line carries no progress token or the percentage is not a number.
@@ -79,31 +73,6 @@ public static long parseTransferredBytes(String line, long fallback) {
7973
}
8074
}
8175

82-
/**
83-
* Parses a rsync speed column ("12.34MB/s") into bytes per second (1024-based units, as
84-
* rsync prints them). Returns {@code -1} when the string does not match. ADFA-5160.
85-
*/
86-
public static double parseSpeedBytesPerSec(String speed) {
87-
if (speed == null) return -1d;
88-
Matcher m = SPEED.matcher(speed);
89-
if (!m.find()) return -1d;
90-
try {
91-
double n = Double.parseDouble(m.group(1));
92-
double mult;
93-
switch (m.group(2)) {
94-
case "B": mult = 1d; break;
95-
case "kB": mult = 1024d; break;
96-
case "MB": mult = 1024d * 1024d; break;
97-
case "GB": mult = 1024d * 1024d * 1024d; break;
98-
case "TB": mult = 1024d * 1024d * 1024d * 1024d; break;
99-
default: return -1d;
100-
}
101-
return n * mult;
102-
} catch (NumberFormatException e) {
103-
return -1d;
104-
}
105-
}
106-
10776
/** Formats a duration in seconds as rsync's {@code H:MM:SS}. Negatives clamp to zero. */
10877
public static String formatEta(long seconds) {
10978
if (seconds < 0) seconds = 0;

‎controller/app/src/test/java/org/iiab/controller/sync/domain/RsyncProgressTest.java‎

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,6 @@ public void returnsFallbackWhenStatsLineAbsent() {
5151
assertEquals(0L, RsyncProgress.parseTransferredBytes(null, 0L));
5252
}
5353

54-
// ADFA-5160: speed -> bytes/sec, for deriving a whole-set ETA.
55-
@Test
56-
public void parsesSpeedToBytesPerSecond() {
57-
assertEquals(1024.0 * 1024.0, RsyncProgress.parseSpeedBytesPerSec("1.00MB/s"), 0.001);
58-
assertEquals(1024.0, RsyncProgress.parseSpeedBytesPerSec("1.00kB/s"), 0.001);
59-
assertEquals(512.0, RsyncProgress.parseSpeedBytesPerSec("512.00B/s"), 0.001);
60-
assertEquals(-1.0, RsyncProgress.parseSpeedBytesPerSec("n/a"), 0.001);
61-
assertEquals(-1.0, RsyncProgress.parseSpeedBytesPerSec(null), 0.001);
62-
}
63-
6454
// ADFA-5160: whole-set ETA formatting, rsync's H:MM:SS.
6555
@Test
6656
public void formatsEtaAsHoursMinutesSeconds() {

0 commit comments

Comments
 (0)