diff options
author | Steve Marion <steve.marion@sonarsource.com> | 2024-05-06 18:03:36 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-05-08 20:02:44 +0000 |
commit | cb1f5878464822e4e0caf660c9689c255f8cdb66 (patch) | |
tree | f4ebcb430c79e218bcc29e5aafbc3ecb03d80ca3 /server/sonar-db-migration | |
parent | aedbebebed4b2048458a8a7b104f74de23cd2f22 (diff) | |
download | sonarqube-cb1f5878464822e4e0caf660c9689c255f8cdb66.tar.gz sonarqube-cb1f5878464822e4e0caf660c9689c255f8cdb66.zip |
SONAR-22141 implement simple linear ETA algorithm for db-migration.
Diffstat (limited to 'server/sonar-db-migration')
4 files changed, 69 insertions, 50 deletions
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/DatabaseMigrationState.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/DatabaseMigrationState.java index ff2f310e6b5..fc7bb265c9f 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/DatabaseMigrationState.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/DatabaseMigrationState.java @@ -19,8 +19,9 @@ */ package org.sonar.server.platform.db.migration; +import java.time.Instant; import java.util.Date; -import javax.annotation.CheckForNull; +import java.util.Optional; public interface DatabaseMigrationState { @@ -62,21 +63,19 @@ public interface DatabaseMigrationState { /** * The time and day the last migration was started. * <p> - * If no migration was ever started, the returned date is {@code null}. + * If no migration was ever started, the returned date is empty. * </p> * - * @return a {@link Date} or {@code null} + * @return a {@link Date} if present */ - @CheckForNull - Date getStartedAt(); + Optional<Instant> getStartedAt(); /** * The error of the last migration if it failed. * - * @return a {@link Throwable} or {@code null} + * @return a {@link Throwable} if present. */ - @CheckForNull - Throwable getError(); + Optional<Throwable> getError(); /** * The amount of migrations already completed. @@ -89,8 +88,8 @@ public interface DatabaseMigrationState { int getTotalMigrations(); /** - * The expected finish timestamp of the migration. + * The expected finish timestamp of the migration if known. */ - Date getExpectedFinishDate(); + Optional<Instant> getExpectedFinishDate(Instant now); } diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/DatabaseMigrationStateImpl.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/DatabaseMigrationStateImpl.java index 5951e58871b..0cd28f0c813 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/DatabaseMigrationStateImpl.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/DatabaseMigrationStateImpl.java @@ -19,8 +19,9 @@ */ package org.sonar.server.platform.db.migration; -import java.util.Date; -import javax.annotation.CheckForNull; +import java.time.Duration; +import java.time.Instant; +import java.util.Optional; import javax.annotation.Nullable; /** @@ -29,13 +30,11 @@ import javax.annotation.Nullable; public class DatabaseMigrationStateImpl implements MutableDatabaseMigrationState { private Status status = Status.NONE; @Nullable - private Date startedAt = null; + private Instant startedAt = null; @Nullable private Throwable error = null; private int completedMigrations = 0; private int totalMigrations = 0; - @Nullable - private Date completionExpectedAt = null; @Override public Status getStatus() { @@ -48,26 +47,23 @@ public class DatabaseMigrationStateImpl implements MutableDatabaseMigrationState } @Override - @CheckForNull - public Date getStartedAt() { - return startedAt; + public Optional<Instant> getStartedAt() { + return Optional.ofNullable(startedAt); } @Override - public void setStartedAt(@Nullable Date startedAt) { + public void setStartedAt(Instant startedAt) { this.startedAt = startedAt; } @Override - @CheckForNull - public Throwable getError() { - return error; + public Optional<Throwable> getError() { + return Optional.ofNullable(error); } @Override public void incrementCompletedMigrations() { completedMigrations++; - updateExpectedFinishDate(); } @Override @@ -91,14 +87,12 @@ public class DatabaseMigrationStateImpl implements MutableDatabaseMigrationState } @Override - public Date getExpectedFinishDate() { - return completionExpectedAt; - } - - private void updateExpectedFinishDate() { - // Here the logic is to calculate the expected finish date based on the current time and the number of migrations completed and total - // migrations - this.completionExpectedAt = new Date(); + public Optional<Instant> getExpectedFinishDate(Instant now) { + if (startedAt == null || totalMigrations == 0 || completedMigrations == 0) { + return Optional.empty(); + } + Duration elapsed = Duration.between(startedAt, now); + double progress = (double) completedMigrations / totalMigrations; + return Optional.of(startedAt.plusMillis((long) (elapsed.toMillis() / progress))); } - } diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/MutableDatabaseMigrationState.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/MutableDatabaseMigrationState.java index fb1d64ce71f..2185f168284 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/MutableDatabaseMigrationState.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/MutableDatabaseMigrationState.java @@ -19,15 +19,14 @@ */ package org.sonar.server.platform.db.migration; -import java.util.Date; -import javax.annotation.Nullable; +import java.time.Instant; public interface MutableDatabaseMigrationState extends DatabaseMigrationState { void setStatus(Status status); - void setStartedAt(@Nullable Date startedAt); + void setStartedAt(Instant startedAt); - void setError(@Nullable Throwable error); + void setError(Throwable error); void incrementCompletedMigrations(); diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/DatabaseMigrationStateImplTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/DatabaseMigrationStateImplTest.java index 1c2813b4c3a..3abaab81772 100644 --- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/DatabaseMigrationStateImplTest.java +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/DatabaseMigrationStateImplTest.java @@ -19,13 +19,16 @@ */ package org.sonar.server.platform.db.migration; -import java.util.Date; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.within; class DatabaseMigrationStateImplTest { - private DatabaseMigrationStateImpl underTest = new DatabaseMigrationStateImpl(); + private final DatabaseMigrationStateImpl underTest = new DatabaseMigrationStateImpl(); @Test void getStatus_whenComponentIsCreated_shouldReturnNONE() { @@ -42,21 +45,21 @@ class DatabaseMigrationStateImplTest { } @Test - void getStartedAt_whenComponentIsCreated_shouldReturnNull() { - assertThat(underTest.getStartedAt()).isNull(); + void getStartedAt_whenComponentIsCreated_shouldNotBePresent() { + assertThat(underTest.getStartedAt()).isEmpty(); } @Test void getStartedAt_shouldReturnArgumentOfSetStartedAt() { - Date expected = new Date(); + Instant expected = Instant.now(); underTest.setStartedAt(expected); - assertThat(underTest.getStartedAt()).isSameAs(expected); + assertThat(underTest.getStartedAt()).get().isSameAs(expected); } @Test - void getError_whenComponentIsCreated_shouldReturnNull() { - assertThat(underTest.getError()).isNull(); + void getError_whenComponentIsCreated_shouldNotBePresent() { + assertThat(underTest.getError()).isEmpty(); } @Test @@ -64,7 +67,7 @@ class DatabaseMigrationStateImplTest { RuntimeException expected = new RuntimeException(); underTest.setError(expected); - assertThat(underTest.getError()).isSameAs(expected); + assertThat(underTest.getError()).get().isSameAs(expected); } @Test @@ -84,13 +87,37 @@ class DatabaseMigrationStateImplTest { } @Test - void incrementCompletedMigrations_shouldUpdateExpectedFinishDate() { - Date startDate = new Date(); + void when_noStartedMigration_expectedFinishDateShouldBeAbsent() { + Instant startDate = Instant.now(); + Instant later = startDate.plus(1, ChronoUnit.MINUTES); + underTest.setTotalMigrations(2); + + assertThat(underTest.getExpectedFinishDate(later)).isEmpty(); + } + + @Test + void when_noStepCompleted_expectedFinishDateShouldBeAbsent() { + Instant startDate = Instant.now(); + Instant later = startDate.plus(1, ChronoUnit.MINUTES); + + underTest.setStartedAt(startDate); + underTest.setTotalMigrations(2); + + assertThat(underTest.getExpectedFinishDate(later)).isEmpty(); + } + + @Test + void when_StepCompleted_expectedFinishDateShouldBePresent() { + Instant startDate = Instant.now(); + Instant later = startDate.plus(1, ChronoUnit.MINUTES); + Instant expectedEnd = startDate.plus(2, ChronoUnit.MINUTES); + + underTest.setStartedAt(startDate); + underTest.setTotalMigrations(2); underTest.incrementCompletedMigrations(); - // At the moment the expected finish date gets update with the timestamp of the last migration completed - assertThat(underTest.getExpectedFinishDate()).isAfterOrEqualTo(startDate); + assertThat(underTest.getExpectedFinishDate(later)).get(InstanceOfAssertFactories.INSTANT) + .isCloseTo(expectedEnd, within(1, ChronoUnit.SECONDS)); } - } |