aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-db-migration
diff options
context:
space:
mode:
authorSteve Marion <steve.marion@sonarsource.com>2024-05-06 18:03:36 +0200
committersonartech <sonartech@sonarsource.com>2024-05-08 20:02:44 +0000
commitcb1f5878464822e4e0caf660c9689c255f8cdb66 (patch)
treef4ebcb430c79e218bcc29e5aafbc3ecb03d80ca3 /server/sonar-db-migration
parentaedbebebed4b2048458a8a7b104f74de23cd2f22 (diff)
downloadsonarqube-cb1f5878464822e4e0caf660c9689c255f8cdb66.tar.gz
sonarqube-cb1f5878464822e4e0caf660c9689c255f8cdb66.zip
SONAR-22141 implement simple linear ETA algorithm for db-migration.
Diffstat (limited to 'server/sonar-db-migration')
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/DatabaseMigrationState.java19
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/DatabaseMigrationStateImpl.java38
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/MutableDatabaseMigrationState.java7
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/DatabaseMigrationStateImplTest.java55
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));
}
-
}