aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-server
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@gmail.com>2013-09-20 13:17:15 +0200
committerSimon Brandhof <simon.brandhof@gmail.com>2013-09-20 13:17:25 +0200
commitd46362bfbaa7a743d84290ef632ad8f21e0777c5 (patch)
tree4baf69d5d2899b057dcd1bf2448fd874035ce3bd /sonar-server
parent7fe48fc80737fb3a2511c7a517d07ca00da7ea48 (diff)
downloadsonarqube-d46362bfbaa7a743d84290ef632ad8f21e0777c5.tar.gz
sonarqube-d46362bfbaa7a743d84290ef632ad8f21e0777c5.zip
SONAR-4690 log progress status
Diffstat (limited to 'sonar-server')
-rw-r--r--sonar-server/src/main/java/org/sonar/server/db/migrations/violation/Progress.java65
-rw-r--r--sonar-server/src/main/java/org/sonar/server/db/migrations/violation/Referentials.java28
-rw-r--r--sonar-server/src/main/java/org/sonar/server/db/migrations/violation/SqlUtil.java10
-rw-r--r--sonar-server/src/main/java/org/sonar/server/db/migrations/violation/ViolationConverter.java5
-rw-r--r--sonar-server/src/main/java/org/sonar/server/db/migrations/violation/ViolationConverters.java19
-rw-r--r--sonar-server/src/main/java/org/sonar/server/db/migrations/violation/ViolationMigration.java23
-rw-r--r--sonar-server/src/test/java/org/sonar/server/db/migrations/violation/ProgressTest.java50
-rw-r--r--sonar-server/src/test/java/org/sonar/server/db/migrations/violation/ViolationMigrationTest.java11
8 files changed, 186 insertions, 25 deletions
diff --git a/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/Progress.java b/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/Progress.java
new file mode 100644
index 00000000000..fe1175a8d7b
--- /dev/null
+++ b/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/Progress.java
@@ -0,0 +1,65 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.db.migrations.violation;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.TimerTask;
+import java.util.concurrent.atomic.AtomicInteger;
+
+class Progress extends TimerTask {
+
+ static final String THREAD_NAME = "Violation Migration Progress";
+ static final long DELAY_MS = 60000L;
+
+ private final AtomicInteger counter = new AtomicInteger(0);
+ private final Logger logger;
+ private final int totalViolations;
+ private long start = System.currentTimeMillis();
+
+ Progress(int totalViolations, Logger logger) {
+ this.totalViolations = totalViolations;
+ this.logger = logger;
+ }
+
+ Progress(int totalViolations) {
+ this(totalViolations, LoggerFactory.getLogger(Progress.class));
+ }
+
+ void increment(int delta) {
+ counter.addAndGet(delta);
+ }
+
+ @Override
+ public void run() {
+ int totalIssues = counter.get();
+ long durationMinutes = (System.currentTimeMillis() - start) / 60000L;
+ int frequency = 0, remaining = 0;
+ if (durationMinutes > 0) {
+ frequency = (int) (totalIssues / durationMinutes);
+ remaining = (totalViolations - totalIssues) / frequency;
+ }
+ logger.info(String.format(
+ "%d%% [%d/%d violations, %d violations/minute, %d minutes remaining]",
+ (100 * totalIssues) / totalViolations, totalIssues, totalViolations, frequency, remaining)
+ );
+ }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/Referentials.java b/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/Referentials.java
index 43e14fa3584..d4d28258488 100644
--- a/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/Referentials.java
+++ b/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/Referentials.java
@@ -30,17 +30,20 @@ import javax.annotation.Nullable;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
+import java.sql.Statement;
import java.util.Map;
-public class Referentials {
+class Referentials {
private final Database database;
private final Map<Long, String> loginsByUserId;
private final Map<Long, String> plansById;
+ private final int totalViolations;
- public Referentials(Database database) throws SQLException {
+ Referentials(Database database) throws SQLException {
this.database = database;
loginsByUserId = selectLongString("select id,login from users");
plansById = selectLongString("select id,kee from action_plans");
+ totalViolations = selectInt("select count(id) from rule_failures");
}
@CheckForNull
@@ -53,6 +56,10 @@ public class Referentials {
return id != null ? loginsByUserId.get(id) : null;
}
+ int totalViolations() {
+ return totalViolations;
+ }
+
private Map<Long, String> selectLongString(String sql) throws SQLException {
Connection connection = database.getDataSource().getConnection();
try {
@@ -70,4 +77,21 @@ public class Referentials {
DbUtils.closeQuietly(connection);
}
}
+
+ private int selectInt(String sql) throws SQLException {
+ Connection connection = database.getDataSource().getConnection();
+ Statement stmt = null;
+ ResultSet rs = null;
+ try {
+ stmt = connection.createStatement();
+ rs = stmt.executeQuery(sql);
+ if (rs.next()) {
+ return rs.getInt(1);
+ }
+ return 0;
+ } finally {
+ DbUtils.closeQuietly(connection, stmt, rs);
+ }
+ }
+
}
diff --git a/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/SqlUtil.java b/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/SqlUtil.java
index 26e40b0ab21..e6b6ffbb3a8 100644
--- a/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/SqlUtil.java
+++ b/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/SqlUtil.java
@@ -25,13 +25,13 @@ import javax.annotation.CheckForNull;
import java.sql.ResultSet;
import java.sql.SQLException;
-public class SqlUtil {
+class SqlUtil {
private SqlUtil() {
// only static methods
}
- public static void log(Logger logger, SQLException e) {
+ static void log(Logger logger, SQLException e) {
SQLException next = e.getNextException();
while (next != null) {
logger.error("SQL error: {}. Message: {}", next.getSQLState(), next.getMessage());
@@ -40,19 +40,19 @@ public class SqlUtil {
}
@CheckForNull
- public static Long getLong(ResultSet rs, String columnName) throws SQLException {
+ static Long getLong(ResultSet rs, String columnName) throws SQLException {
long l = rs.getLong(columnName);
return rs.wasNull() ? null : l;
}
@CheckForNull
- public static Double getDouble(ResultSet rs, String columnName) throws SQLException {
+ static Double getDouble(ResultSet rs, String columnName) throws SQLException {
double d = rs.getDouble(columnName);
return rs.wasNull() ? null : d;
}
@CheckForNull
- public static Integer getInt(ResultSet rs, String columnName) throws SQLException {
+ static Integer getInt(ResultSet rs, String columnName) throws SQLException {
int i = rs.getInt(columnName);
return rs.wasNull() ? null : i;
}
diff --git a/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/ViolationConverter.java b/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/ViolationConverter.java
index 73e417faafe..1d57602224c 100644
--- a/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/ViolationConverter.java
+++ b/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/ViolationConverter.java
@@ -82,11 +82,13 @@ class ViolationConverter implements Runnable {
private final Database db;
private final Object[] violationIds;
private final Referentials referentials;
+ private final Progress progress;
- public ViolationConverter(Referentials referentials, Database db, Object[] violationIds) {
+ ViolationConverter(Referentials referentials, Database db, Object[] violationIds, Progress progress) {
this.referentials = referentials;
this.db = db;
this.violationIds = violationIds;
+ this.progress = progress;
}
@Override
@@ -182,6 +184,7 @@ class ViolationConverter implements Runnable {
writeConnection.commit();
insertComments(writeConnection, allComments);
+ progress.increment(rows.size());
} catch (SQLException e) {
//TODO
diff --git a/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/ViolationConverters.java b/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/ViolationConverters.java
index 09278de5c59..a643fa7fdc9 100644
--- a/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/ViolationConverters.java
+++ b/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/ViolationConverters.java
@@ -21,30 +21,39 @@ package org.sonar.server.db.migrations.violation;
import org.sonar.core.persistence.Database;
+import java.util.Timer;
import java.util.concurrent.*;
-public class ViolationConverters {
+class ViolationConverters {
- static final int MAX_THREADS = 4;
+ static final int MAX_THREADS = 5;
private final ExecutorService executorService;
private final Database database;
private final Referentials referentials;
+ private final Progress progress;
+ private final Timer timer;
- public ViolationConverters(Database db, Referentials referentials) {
+ ViolationConverters(Database db, Referentials referentials) {
this.database = db;
this.referentials = referentials;
+
+ this.progress = new Progress(referentials.totalViolations());
+ timer = new Timer(Progress.THREAD_NAME);
+ timer.schedule(progress, Progress.DELAY_MS, Progress.DELAY_MS);
+
BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable>(MAX_THREADS);
RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.CallerRunsPolicy();
this.executorService = new ThreadPoolExecutor(0, MAX_THREADS, 5L, TimeUnit.SECONDS, blockingQueue, rejectedExecutionHandler);
}
void convert(Object[] violationIds) {
- executorService.execute(new ViolationConverter(referentials, database, violationIds));
+ executorService.execute(new ViolationConverter(referentials, database, violationIds, progress));
}
void waitForFinished() throws InterruptedException {
executorService.shutdown();
- executorService.awaitTermination(30L, TimeUnit.SECONDS);
+ executorService.awaitTermination(10L, TimeUnit.SECONDS);
+ timer.cancel();
}
}
diff --git a/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/ViolationMigration.java b/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/ViolationMigration.java
index 249893e7a00..86a94ddef0c 100644
--- a/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/ViolationMigration.java
+++ b/sonar-server/src/main/java/org/sonar/server/db/migrations/violation/ViolationMigration.java
@@ -31,7 +31,6 @@ import org.sonar.server.db.DatabaseMigration;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
-import java.util.Arrays;
/**
* Used in the Active Record Migration 401
@@ -78,14 +77,16 @@ public class ViolationMigration implements DatabaseMigration {
public void migrate(Database db) throws Exception {
Referentials referentials = new Referentials(db);
- ViolationConverters converters = new ViolationConverters(db, referentials);
- Connection readConnection = db.getDataSource().getConnection();
- try {
- new QueryRunner().query(readConnection, "select id from rule_failures", new ViolationIdHandler(converters));
- } finally {
- DbUtils.closeQuietly(readConnection);
+ if (referentials.totalViolations() > 0) {
+ ViolationConverters converters = new ViolationConverters(db, referentials);
+ Connection readConnection = db.getDataSource().getConnection();
+ try {
+ new QueryRunner().query(readConnection, "select id from rule_failures", new ViolationIdHandler(converters));
+ } finally {
+ DbUtils.closeQuietly(readConnection);
+ }
+ converters.waitForFinished();
}
- converters.waitForFinished();
}
private static class ViolationIdHandler implements ResultSetHandler {
@@ -113,9 +114,9 @@ public class ViolationMigration implements DatabaseMigration {
total++;
}
if (cursor > 0) {
- for (int i=0 ; i<violationIds.length ; i++) {
- if (violationIds[i]==null) {
- violationIds[i]=-1;
+ for (int i = 0; i < violationIds.length; i++) {
+ if (violationIds[i] == null) {
+ violationIds[i] = -1;
}
}
converters.convert(violationIds);
diff --git a/sonar-server/src/test/java/org/sonar/server/db/migrations/violation/ProgressTest.java b/sonar-server/src/test/java/org/sonar/server/db/migrations/violation/ProgressTest.java
new file mode 100644
index 00000000000..1e437c9794d
--- /dev/null
+++ b/sonar-server/src/test/java/org/sonar/server/db/migrations/violation/ProgressTest.java
@@ -0,0 +1,50 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.db.migrations.violation;
+
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.slf4j.Logger;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+public class ProgressTest {
+ @Test
+ public void log_progress() throws Exception {
+ Logger logger = mock(Logger.class);
+ ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);
+
+ Progress progress = new Progress(5000, logger);
+ progress.run();
+ progress.increment(200);
+ progress.increment(130);
+ progress.run();
+ progress.increment(1670);
+ progress.run();
+
+ verify(logger, times(3)).info(argument.capture());
+ assertThat(argument.getAllValues().get(0)).matches("0% \\[0/5000 violations, 0 violations/minute, \\d+ minutes remaining\\]");
+ assertThat(argument.getAllValues().get(1)).matches("6% \\[330/5000 violations, \\d+ violations/minute, \\d+ minutes remaining\\]");
+ assertThat(argument.getAllValues().get(2)).matches("40% \\[2000/5000 violations, \\d+ violations/minute, \\d+ minutes remaining\\]");
+ }
+}
diff --git a/sonar-server/src/test/java/org/sonar/server/db/migrations/violation/ViolationMigrationTest.java b/sonar-server/src/test/java/org/sonar/server/db/migrations/violation/ViolationMigrationTest.java
index 67e4f8cd52c..58e96d25e8b 100644
--- a/sonar-server/src/test/java/org/sonar/server/db/migrations/violation/ViolationMigrationTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/db/migrations/violation/ViolationMigrationTest.java
@@ -23,6 +23,10 @@ import org.junit.Rule;
import org.junit.Test;
import org.sonar.core.persistence.TestDatabase;
+import java.util.Set;
+
+import static org.fest.assertions.Assertions.assertThat;
+
public class ViolationMigrationTest {
@Rule
@@ -34,7 +38,12 @@ public class ViolationMigrationTest {
new ViolationMigration().execute(db.database());
- //Thread.sleep(5000L);
db.assertDbUnit(getClass(), "migrate_violations_result.xml", "issues", "issue_changes");
+
+ // Progress thread is dead
+ Set<Thread> threads = Thread.getAllStackTraces().keySet();
+ for (Thread thread : threads) {
+ assertThat(thread.getName()).isNotEqualTo(Progress.THREAD_NAME);
+ }
}
}