Pārlūkot izejas kodu

Fix Bug in Snapshot Status Response Timestamps (#46919)

Fixing a corner case where snapshot total time calculation was off when
getting the `SnapshotStatus` of an in-progress snapshot.

Closes #46913
Armin Braun 6 gadi atpakaļ
vecāks
revīzija
2e4ca5c382

+ 4 - 0
server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java

@@ -19,6 +19,7 @@
 
 package org.elasticsearch.action.admin.cluster.snapshots.status;
 
+import org.elasticsearch.common.Strings;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.common.io.stream.Writeable;
@@ -64,6 +65,7 @@ public class SnapshotStats implements Writeable, ToXContentObject {
                   long incrementalSize, long totalSize, long processedSize) {
         this.startTime = startTime;
         this.time = time;
+        assert time >= 0 : "Tried to initialize snapshot stats with negative total time [" + time + "]";
         this.incrementalFileCount = incrementalFileCount;
         this.totalFileCount = totalFileCount;
         this.processedFileCount = processedFileCount;
@@ -315,6 +317,8 @@ public class SnapshotStats implements Writeable, ToXContentObject {
             // Update duration
             time = endTime - startTime;
         }
+        assert time >= 0
+            : "Update with [" + Strings.toString(stats) + "][" + updateTimestamps + "] resulted in negative total time [" + time + "]";
     }
 
     @Override

+ 1 - 0
server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java

@@ -101,6 +101,7 @@ public class SnapshotStatus implements ToXContentObject, Writeable {
         this.shards = Objects.requireNonNull(shards);
         this.includeGlobalState = includeGlobalState;
         shardsStats = new SnapshotShardsStats(shards);
+        assert time >= 0 : "time must be >= 0 but received [" + time + "]";
         updateShardStats(startTime, time);
     }
 

+ 6 - 1
server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/TransportSnapshotsStatusAction.java

@@ -243,9 +243,14 @@ public class TransportSnapshotsStatusAction extends TransportMasterNodeAction<Sn
                             throw new IllegalArgumentException("Unknown snapshot state " + snapshotInfo.state());
                     }
                     final long startTime = snapshotInfo.startTime();
+                    final long endTime = snapshotInfo.endTime();
+                    assert endTime >= startTime || (endTime == 0L && snapshotInfo.state().completed() == false)
+                        : "Inconsistent timestamps found in SnapshotInfo [" + snapshotInfo + "]";
                     builder.add(new SnapshotStatus(new Snapshot(repositoryName, snapshotId), state,
                         Collections.unmodifiableList(shardStatusBuilder), snapshotInfo.includeGlobalState(),
-                        startTime, snapshotInfo.endTime() - startTime));
+                        startTime,
+                        // Use current time to calculate overall runtime for in-progress snapshots that have endTime == 0
+                        (endTime == 0 ? threadPool.absoluteTimeInMillis() : endTime) - startTime));
                 }
             }
         }

+ 3 - 2
server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java

@@ -28,8 +28,9 @@ public class SnapshotStatsTests extends AbstractXContentTestCase<SnapshotStats>
 
     @Override
     protected SnapshotStats createTestInstance() {
-        long startTime = randomNonNegativeLong();
-        long time = randomNonNegativeLong();
+        // Using less than half of Long.MAX_VALUE for random time values to avoid long overflow in tests that add the two time values
+        long startTime = randomLongBetween(0, Long.MAX_VALUE / 2 - 1);
+        long time =  randomLongBetween(0, Long.MAX_VALUE / 2 - 1);
         int incrementalFileCount = randomIntBetween(0, Integer.MAX_VALUE);
         int totalFileCount = randomIntBetween(0, Integer.MAX_VALUE);
         int processedFileCount = randomIntBetween(0, Integer.MAX_VALUE);