aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorAleksandra Bozhinoska <aleksandra.bozhinoska@sonarsource.com>2025-02-25 13:53:27 +0100
committerLukasz Jarocki <lukasz.jarocki@sonarsource.com>2025-02-28 09:57:48 +0100
commit28fe0fe355dd799b52c8741282a355d584d23253 (patch)
treea023a65b8fbd906fc69e8cf37f3f8ffeb547dfb5 /server
parent86670bc803d6bedaa7703da7f7e0aa072cf6977d (diff)
downloadsonarqube-28fe0fe355dd799b52c8741282a355d584d23253.tar.gz
sonarqube-28fe0fe355dd799b52c8741282a355d584d23253.zip
SONAR-24358 Make measures migration reentrant
Diffstat (limited to 'server')
-rw-r--r--server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/MigrateBranchesLiveMeasuresToMeasuresIT.java47
-rw-r--r--server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/MigratePortfoliosLiveMeasuresToMeasuresIT.java47
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v108/AbstractMigrateLiveMeasuresToMeasures.java21
3 files changed, 113 insertions, 2 deletions
diff --git a/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/MigrateBranchesLiveMeasuresToMeasuresIT.java b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/MigrateBranchesLiveMeasuresToMeasuresIT.java
index 6418fdeddc4..308aa8495e2 100644
--- a/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/MigrateBranchesLiveMeasuresToMeasuresIT.java
+++ b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/MigrateBranchesLiveMeasuresToMeasuresIT.java
@@ -167,6 +167,43 @@ class MigrateBranchesLiveMeasuresToMeasuresIT {
}
@Test
+ void should_duplicate_measures_on_reentry_when_index_does_not_exist() throws SQLException {
+ String nclocMetricUuid = insertMetric("ncloc", "INT");
+
+ String branch1 = "branch_1";
+ insertNotMigratedBranch(branch1);
+ String component1 = uuidFactory.create();
+ insertMeasure(branch1, component1, nclocMetricUuid, Map.of("value", 120));
+
+ insertMigratedMeasure(branch1, component1);
+ assertThat(db.countRowsOfTable("measures")).isEqualTo(1);
+
+ underTest.execute();
+
+ assertThat(db.countRowsOfTable("measures")).isEqualTo(2);
+ }
+
+ @Test
+ void should_remove_migrated_measures_on_reentry_when_index_exists() throws SQLException {
+ String nclocMetricUuid = insertMetric("ncloc", "INT");
+
+ String branch1 = "branch_1";
+ insertNotMigratedBranch(branch1);
+ String component1 = uuidFactory.create();
+ insertMeasure(branch1, component1, nclocMetricUuid, Map.of("value", 120));
+
+ insertMigratedMeasure(branch1, component1);
+ assertThat(db.countRowsOfTable("measures")).isEqualTo(1);
+
+ var createIndexMigration = new CreateIndexOnMeasuresTable(db.database());
+ createIndexMigration.execute();
+
+ underTest.execute();
+
+ assertThat(db.countRowsOfTable("measures")).isEqualTo(1);
+ }
+
+ @Test
void should_not_migrate_measures_planned_for_deletion() throws SQLException {
String nclocMetricUuid = insertMetric("ncloc", "INT");
Set<String> deletedMetricUuid = DeleteSoftwareQualityRatingFromProjectMeasures.SOFTWARE_QUALITY_METRICS_TO_DELETE.stream().map(e -> insertMetric(e, "INT"))
@@ -381,4 +418,14 @@ class MigrateBranchesLiveMeasuresToMeasuresIT {
"updated_at", 12L);
}
+ private void insertMigratedMeasure(String branch, String componentUuid) {
+ db.executeInsert("measures",
+ "component_uuid", componentUuid,
+ "branch_uuid", branch,
+ "json_value", "{\"any\":\"thing\"}",
+ "json_value_hash", "1234",
+ "created_at", 12,
+ "updated_at", 12);
+ }
+
}
diff --git a/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/MigratePortfoliosLiveMeasuresToMeasuresIT.java b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/MigratePortfoliosLiveMeasuresToMeasuresIT.java
index f0a197af534..79dd5abe808 100644
--- a/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/MigratePortfoliosLiveMeasuresToMeasuresIT.java
+++ b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/MigratePortfoliosLiveMeasuresToMeasuresIT.java
@@ -186,6 +186,43 @@ class MigratePortfoliosLiveMeasuresToMeasuresIT {
.containsOnly(tuple(component1, portfolio1, "{\"ncloc\":120.0}", -1557106439558598045L));
}
+ @Test
+ void should_duplicate_measures_on_reentry_when_index_does_not_exist() throws SQLException {
+ String nclocMetricUuid = insertMetric("ncloc", "INT");
+
+ String portfolio1 = "portfolio_1";
+ insertNotMigratedPortfolio(portfolio1);
+ String component1 = uuidFactory.create();
+ insertMeasure(portfolio1, component1, nclocMetricUuid, Map.of("value", 120));
+
+ insertMigratedMeasure(portfolio1, component1);
+ assertThat(db.countRowsOfTable("measures")).isEqualTo(1);
+
+ underTest.execute();
+
+ assertThat(db.countRowsOfTable("measures")).isEqualTo(2);
+ }
+
+ @Test
+ void should_remove_migrated_measures_on_reentry_when_index_exists() throws SQLException {
+ String nclocMetricUuid = insertMetric("ncloc", "INT");
+
+ String portfolio1 = "portfolio_1";
+ insertNotMigratedPortfolio(portfolio1);
+ String component1 = uuidFactory.create();
+ insertMeasure(portfolio1, component1, nclocMetricUuid, Map.of("value", 120));
+
+ insertMigratedMeasure(portfolio1, component1);
+ assertThat(db.countRowsOfTable("measures")).isEqualTo(1);
+
+ var createIndexMigration = new CreateIndexOnMeasuresTable(db.database());
+ createIndexMigration.execute();
+
+ underTest.execute();
+
+ assertThat(db.countRowsOfTable("measures")).isEqualTo(1);
+ }
+
private void assertPortfolioMigrated(String portfolio) {
List<Map<String, Object>> result = db.select(format("select %s as \"MIGRATED\" from portfolios where uuid = '%s'", MEASURES_MIGRATED_COLUMN, portfolio));
assertThat(result)
@@ -239,4 +276,14 @@ class MigratePortfoliosLiveMeasuresToMeasuresIT {
"created_at", 12L,
"updated_at", 12L);
}
+
+ private void insertMigratedMeasure(String branch, String componentUuid) {
+ db.executeInsert("measures",
+ "component_uuid", componentUuid,
+ "branch_uuid", branch,
+ "json_value", "{\"any\":\"thing\"}",
+ "json_value_hash", "1234",
+ "created_at", 12,
+ "updated_at", 12);
+ }
}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v108/AbstractMigrateLiveMeasuresToMeasures.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v108/AbstractMigrateLiveMeasuresToMeasures.java
index e1cac143632..71d0e173080 100644
--- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v108/AbstractMigrateLiveMeasuresToMeasures.java
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v108/AbstractMigrateLiveMeasuresToMeasures.java
@@ -45,6 +45,8 @@ import org.sonar.server.platform.db.migration.step.Upsert;
import static java.lang.String.format;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.sonar.server.platform.db.migration.version.v108.CreateIndexOnMeasuresTable.INDEX_NAME;
+import static org.sonar.server.platform.db.migration.version.v108.CreateMeasuresTable.MEASURES_TABLE_NAME;
public abstract class AbstractMigrateLiveMeasuresToMeasures extends DataChange {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractMigrateLiveMeasuresToMeasures.class);
@@ -52,6 +54,11 @@ public abstract class AbstractMigrateLiveMeasuresToMeasures extends DataChange {
private static final Set<String> TEXT_VALUE_TYPES = Set.of("STRING", "LEVEL", "DATA", "DISTRIB");
private static final Gson GSON = new Gson();
+ private static final String CLEANUP_QUERY = """
+ DELETE FROM measures
+ WHERE branch_uuid = ?
+ """;
+
private static final String SELECT_QUERY = """
SELECT lm.component_uuid,
m.name,
@@ -108,11 +115,14 @@ public abstract class AbstractMigrateLiveMeasuresToMeasures extends DataChange {
@Override
protected void execute(Context context) throws SQLException {
+ boolean measuresIndexExists;
try (Connection c = getDatabase().getDataSource().getConnection()) {
// the table is later deleted, this check ensures the migration re-entrance
if (!DatabaseUtils.tableExists("live_measures", c)) {
return;
}
+
+ measuresIndexExists = DatabaseUtils.indexExistsIgnoreCase(MEASURES_TABLE_NAME, INDEX_NAME, c);
}
List<String> uuids = context.prepareSelect(getSelectUuidQuery())
@@ -129,7 +139,7 @@ public abstract class AbstractMigrateLiveMeasuresToMeasures extends DataChange {
for (String uuid : uuids) {
try {
- migrateItem(uuid, context, selectQuery);
+ migrateItem(uuid, context, selectQuery, measuresIndexExists);
} catch (Exception e) {
LOGGER.error(format("Migration of %s %s failed", item, uuid));
throw e;
@@ -152,9 +162,16 @@ public abstract class AbstractMigrateLiveMeasuresToMeasures extends DataChange {
};
}
- private void migrateItem(String uuid, Context context, String selectQuery) throws SQLException {
+ private void migrateItem(String uuid, Context context, String selectQuery, boolean measuresIndexExists) throws SQLException {
LOGGER.debug("Migrating {} {}...", item, uuid);
+ if (measuresIndexExists) {
+ context.prepareUpsert(CLEANUP_QUERY)
+ .setString(1, uuid)
+ .execute()
+ .commit();
+ }
+
Map<String, Object> measureValues = new HashMap<>();
AtomicReference<String> componentUuid = new AtomicReference<>(null);