mirror of
https://github.com/abraunegg/onedrive
synced 2026-03-14 14:35:46 +01:00
Update how the ETA values are calculated to avoid negative values (#3386)
* Update calculation of ETA values to guard against incorrect Unix Epoch / time skew impacting calculation outcome. * Use common function for ETA string calculation for upload|download operations to avoid negative values
This commit is contained in:
parent
6248f27b87
commit
3fff182812
3 changed files with 82 additions and 55 deletions
|
|
@ -1383,7 +1383,10 @@ class OneDriveApi {
|
|||
if (fileSize >= thresholdFileSize){
|
||||
// Download Progress variables
|
||||
size_t expected_total_segments = 20;
|
||||
ulong start_unix_time = Clock.currTime.toUnixTime();
|
||||
|
||||
// Time sensitive and ETA string items
|
||||
SysTime currentTime = Clock.currTime();
|
||||
long start_unix_time = currentTime.toUnixTime();
|
||||
int h, m, s;
|
||||
string etaString;
|
||||
bool barInit = false;
|
||||
|
|
@ -1425,10 +1428,10 @@ class OneDriveApi {
|
|||
if (appConfig.getValueLong("rate_limit") > 0) {
|
||||
// User configured rate limit
|
||||
// How much data should be in each segment to qualify for 5%
|
||||
ulong dataPerSegment = to!ulong(floor(double(dltotal)/expected_total_segments));
|
||||
size_t dataPerSegment = cast(size_t)(floor(double(dltotal)/expected_total_segments));
|
||||
// How much data received do we need to validate against
|
||||
ulong thisSegmentData = dataPerSegment * segmentCount;
|
||||
ulong nextSegmentData = dataPerSegment * (segmentCount + 1);
|
||||
size_t thisSegmentData = dataPerSegment * segmentCount;
|
||||
size_t nextSegmentData = dataPerSegment * (segmentCount + 1);
|
||||
|
||||
// Has the data that has been received in a 5% window that we need to increment the progress bar at
|
||||
if ((dlnow > thisSegmentData) && (dlnow < nextSegmentData) && (previousProgressPercent != currentDLPercent) || (dlnow == dltotal)) {
|
||||
|
|
@ -1440,15 +1443,16 @@ class OneDriveApi {
|
|||
// Not 100% yet
|
||||
// Calculate the output
|
||||
segmentCount++;
|
||||
auto eta = calc_eta(segmentCount, expected_total_segments, start_unix_time);
|
||||
dur!"seconds"(eta).split!("hours", "minutes", "seconds")(h, m, s);
|
||||
etaString = format!"| ETA %02d:%02d:%02d"( h, m, s);
|
||||
// Generate ETA time output
|
||||
etaString = formatETA(calc_eta(segmentCount, expected_total_segments, start_unix_time));
|
||||
// Calculate percentage
|
||||
string percentage = leftJustify(to!string(currentDLPercent) ~ "%", 5, ' ');
|
||||
addLogEntry(downloadLogEntry ~ percentage ~ etaString, ["consoleOnly"]);
|
||||
} else {
|
||||
// 100% done
|
||||
ulong end_unix_time = Clock.currTime.toUnixTime();
|
||||
auto upload_duration = cast(int)(end_unix_time - start_unix_time);
|
||||
SysTime endTime = Clock.currTime();
|
||||
long end_unix_time = endTime.toUnixTime();
|
||||
int upload_duration = cast(int)(end_unix_time - start_unix_time);
|
||||
dur!"seconds"(upload_duration).split!("hours", "minutes", "seconds")(h, m, s);
|
||||
etaString = format!"| DONE in %02d:%02d:%02d"( h, m, s);
|
||||
string percentage = leftJustify(to!string(currentDLPercent) ~ "%", 5, ' ');
|
||||
|
|
@ -1472,15 +1476,16 @@ class OneDriveApi {
|
|||
// Not 100% yet
|
||||
// Calculate the output
|
||||
segmentCount++;
|
||||
auto eta = calc_eta(segmentCount, expected_total_segments, start_unix_time);
|
||||
dur!"seconds"(eta).split!("hours", "minutes", "seconds")(h, m, s);
|
||||
etaString = format!"| ETA %02d:%02d:%02d"( h, m, s);
|
||||
// Generate ETA time output
|
||||
etaString = formatETA(calc_eta(segmentCount, expected_total_segments, start_unix_time));
|
||||
// Calculate percentage
|
||||
string percentage = leftJustify(to!string(currentDLPercent) ~ "%", 5, ' ');
|
||||
addLogEntry(downloadLogEntry ~ percentage ~ etaString, ["consoleOnly"]);
|
||||
} else {
|
||||
// 100% done
|
||||
ulong end_unix_time = Clock.currTime.toUnixTime();
|
||||
auto upload_duration = cast(int)(end_unix_time - start_unix_time);
|
||||
SysTime endTime = Clock.currTime();
|
||||
long end_unix_time = endTime.toUnixTime();
|
||||
int upload_duration = cast(int)(end_unix_time - start_unix_time);
|
||||
dur!"seconds"(upload_duration).split!("hours", "minutes", "seconds")(h, m, s);
|
||||
etaString = format!"| DONE in %02d:%02d:%02d"( h, m, s);
|
||||
string percentage = leftJustify(to!string(currentDLPercent) ~ "%", 5, ' ');
|
||||
|
|
|
|||
27
src/sync.d
27
src/sync.d
|
|
@ -9371,6 +9371,15 @@ class SyncEngine {
|
|||
enum CHUNK_SIZE = 327_680L; // 320 KiB
|
||||
enum MAX_FRAGMENT_BYTES = 60L * 1_048_576L; // 60 MiB = 62,914,560 bytes
|
||||
|
||||
// Time sensitive and ETA string items
|
||||
SysTime currentTime = Clock.currTime();
|
||||
long start_unix_time = currentTime.toUnixTime();
|
||||
int h, m, s;
|
||||
string etaString;
|
||||
|
||||
// Upload string template
|
||||
string uploadLogEntry = "Uploading: " ~ uploadSessionData["localPath"].str ~ " ... ";
|
||||
|
||||
// Calculate base size using configured fragment size
|
||||
baseSize = appConfig.getValueLong("file_fragment_size") * 2^^20;
|
||||
|
||||
|
|
@ -9391,10 +9400,6 @@ class SyncEngine {
|
|||
|
||||
// Estimate total number of expected fragments
|
||||
size_t expected_total_fragments = cast(size_t) ceil(double(thisFileSize) / double(fragmentSize));
|
||||
long start_unix_time = Clock.currTime.toUnixTime();
|
||||
int h, m, s;
|
||||
string etaString;
|
||||
string uploadLogEntry = "Uploading: " ~ uploadSessionData["localPath"].str ~ " ... ";
|
||||
|
||||
// If we get a 404, create a new upload session and store it here
|
||||
JSONValue newUploadSession;
|
||||
|
|
@ -9405,17 +9410,9 @@ class SyncEngine {
|
|||
fragmentCount++;
|
||||
if (debugLogging) {addLogEntry("Fragment: " ~ to!string(fragmentCount) ~ " of " ~ to!string(expected_total_fragments), ["debug"]);}
|
||||
|
||||
// What ETA string do we use?
|
||||
auto eta = calc_eta((fragmentCount -1), expected_total_fragments, start_unix_time);
|
||||
if (eta == 0) {
|
||||
// Initial calculation ...
|
||||
etaString = format!"| ETA --:--:--";
|
||||
} else {
|
||||
// we have at least an ETA provided
|
||||
dur!"seconds"(eta).split!("hours", "minutes", "seconds")(h, m, s);
|
||||
etaString = format!"| ETA %02d:%02d:%02d"(h, m, s);
|
||||
}
|
||||
|
||||
// Generate ETA time output
|
||||
etaString = formatETA(calc_eta((fragmentCount -1), expected_total_fragments, start_unix_time));
|
||||
|
||||
// Calculate this progress output
|
||||
auto ratio = cast(double)(fragmentCount - 1) / expected_total_fragments;
|
||||
// Convert the ratio to a percentage and format it to two decimal places
|
||||
|
|
|
|||
77
src/util.d
77
src/util.d
|
|
@ -1509,49 +1509,74 @@ string getUserName() {
|
|||
}
|
||||
|
||||
// Calculate the ETA for when a 'large file' will be completed (upload & download operations)
|
||||
int calc_eta(size_t counter, size_t iterations, ulong start_time) {
|
||||
if (counter == 0) {
|
||||
return 0; // Avoid division by zero
|
||||
}
|
||||
int calc_eta(size_t counter, size_t iterations, long start_time) {
|
||||
if (counter == 0) {
|
||||
return 0; // Avoid division by zero
|
||||
}
|
||||
|
||||
// Get the current time as a Unix timestamp (seconds since the epoch, January 1, 1970, 00:00:00 UTC)
|
||||
SysTime currentTime = Clock.currTime();
|
||||
long current_time = currentTime.toUnixTime();
|
||||
|
||||
double ratio = cast(double) counter / iterations;
|
||||
auto current_time = Clock.currTime.toUnixTime();
|
||||
ulong duration = (current_time - start_time);
|
||||
// 'start_time' must be less than 'current_time' otherwise ETA will have negative values
|
||||
if (start_time > current_time) {
|
||||
if (debugLogging) {
|
||||
addLogEntry("Warning: start_time is in the future. Cannot calculate ETA.", ["debug"]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate duration
|
||||
long duration = (current_time - start_time);
|
||||
|
||||
// Segments left to download
|
||||
auto segments_remaining = (iterations > counter) ? (iterations - counter) : 0;
|
||||
|
||||
// Calculate the average time per iteration so far
|
||||
double avg_time_per_iteration = cast(double) duration / counter;
|
||||
// Calculate the ratio we are at
|
||||
double ratio = cast(double) counter / iterations;
|
||||
|
||||
// Debug output for the ETA calculation
|
||||
// Calculate segments left to download
|
||||
auto segments_remaining = (iterations > counter) ? (iterations - counter) : 0;
|
||||
|
||||
// Calculate the average time per iteration so far
|
||||
double avg_time_per_iteration = cast(double) duration / counter;
|
||||
|
||||
// Debug output for the ETA calculation
|
||||
if (debugLogging) {
|
||||
addLogEntry("counter: " ~ to!string(counter), ["debug"]);
|
||||
addLogEntry("iterations: " ~ to!string(iterations), ["debug"]);
|
||||
addLogEntry("segments_remaining: " ~ to!string(segments_remaining), ["debug"]);
|
||||
addLogEntry("ratio: " ~ format("%.2f", ratio), ["debug"]);
|
||||
addLogEntry("start_time: " ~ to!string(start_time), ["debug"]);
|
||||
addLogEntry("current_time: " ~ to!string(current_time), ["debug"]);
|
||||
addLogEntry("duration: " ~ to!string(duration), ["debug"]);
|
||||
addLogEntry("counter: " ~ to!string(counter), ["debug"]);
|
||||
addLogEntry("iterations: " ~ to!string(iterations), ["debug"]);
|
||||
addLogEntry("segments_remaining: " ~ to!string(segments_remaining), ["debug"]);
|
||||
addLogEntry("ratio: " ~ format("%.2f", ratio), ["debug"]);
|
||||
addLogEntry("start_time: " ~ to!string(start_time), ["debug"]);
|
||||
addLogEntry("current_time: " ~ to!string(current_time), ["debug"]);
|
||||
addLogEntry("duration: " ~ to!string(duration), ["debug"]);
|
||||
addLogEntry("avg_time_per_iteration: " ~ format("%.2f", avg_time_per_iteration), ["debug"]);
|
||||
}
|
||||
|
||||
// Return the ETA or duration
|
||||
if (counter != iterations) {
|
||||
auto eta_sec = avg_time_per_iteration * segments_remaining;
|
||||
auto eta_sec = avg_time_per_iteration * segments_remaining;
|
||||
// ETA Debug
|
||||
if (debugLogging) {
|
||||
addLogEntry("eta_sec: " ~ to!string(eta_sec), ["debug"]);
|
||||
addLogEntry("estimated_total_time: " ~ to!string(avg_time_per_iteration * iterations), ["debug"]);
|
||||
addLogEntry("eta_sec: " ~ to!string(eta_sec), ["debug"]);
|
||||
addLogEntry("estimated_total_time: " ~ to!string(avg_time_per_iteration * iterations), ["debug"]);
|
||||
}
|
||||
// Return ETA
|
||||
return eta_sec > 0 ? cast(int) ceil(eta_sec) : 0;
|
||||
} else {
|
||||
return eta_sec > 0 ? cast(int) ceil(eta_sec) : 0;
|
||||
} else {
|
||||
// Return the average time per iteration for the last iteration
|
||||
return cast(int) ceil(avg_time_per_iteration);
|
||||
return cast(int) ceil(avg_time_per_iteration);
|
||||
}
|
||||
}
|
||||
|
||||
// Use the ETA value and return a formatted string in a consistent manner
|
||||
string formatETA(int eta) {
|
||||
// How do we format the ETA string. Guard against zero and negative values
|
||||
if (eta <= 0) {
|
||||
return "| ETA --:--:--";
|
||||
}
|
||||
int h, m, s;
|
||||
dur!"seconds"(eta).split!("hours", "minutes", "seconds")(h, m, s);
|
||||
return format!"| ETA %02d:%02d:%02d"(h, m, s);
|
||||
}
|
||||
|
||||
// Force Exit due to failure
|
||||
void forceExit() {
|
||||
// Allow any logging complete before we force exit
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue