*/
package org.sonar.server.db.migrations;
-import org.slf4j.LoggerFactory;
import org.sonar.core.persistence.Database;
-import org.sonar.server.util.ProgressTask;
+import org.sonar.server.util.ProgressLogger;
import java.sql.Connection;
import java.sql.SQLException;
-import java.util.Timer;
import java.util.concurrent.atomic.AtomicLong;
public class MassUpdate {
private final Database db;
private final Connection readConnection, writeConnection;
private final AtomicLong counter = new AtomicLong(0L);
- private final ProgressTask progressTask = new ProgressTask(counter, LoggerFactory.getLogger("DbMigration"));
+ private final ProgressLogger progress = ProgressLogger.create(getClass(), counter);
private Select select;
private Upsert update;
}
public MassUpdate rowPluralName(String s) {
- this.progressTask.setRowPluralName(s);
+ this.progress.setPluralLabel(s);
return this;
}
throw new IllegalStateException("SELECT or UPDATE requests are not defined");
}
- Timer timer = new Timer("Db Migration Progress");
- timer.schedule(progressTask, ProgressTask.PERIOD_MS, ProgressTask.PERIOD_MS);
+ progress.start();
try {
select.scroll(new Select.RowHandler() {
@Override
}
update.close();
- // log the total number of process rows
- progressTask.log();
+ // log the total number of processed rows
+ progress.log();
} finally {
- timer.cancel();
- timer.purge();
+ progress.stop();
}
}
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
-
-import org.slf4j.LoggerFactory;
import org.sonar.api.utils.System2;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.migration.v45.Migration45Mapper;
import org.sonar.core.persistence.migration.v45.RuleParameter;
import org.sonar.server.db.DbClient;
import org.sonar.server.db.migrations.DatabaseMigration;
-import org.sonar.server.util.ProgressTask;
+import org.sonar.server.util.ProgressLogger;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Date;
import java.util.List;
-import java.util.Timer;
import java.util.concurrent.atomic.AtomicLong;
/**
private final System2 system;
private final AtomicLong counter = new AtomicLong(0L);
- private final ProgressTask progressTask = new ProgressTask(counter, LoggerFactory.getLogger("DbMigration"));
+ private final ProgressLogger progress = ProgressLogger.create(getClass(), counter);
public AddMissingCustomRuleParametersMigration(DbClient db, System2 system) {
this.db = db;
@Override
public void execute() {
- Timer timer = new Timer("Db Migration Progress");
- timer.schedule(progressTask, ProgressTask.PERIOD_MS, ProgressTask.PERIOD_MS);
+ progress.start();
DbSession session = db.openSession(false);
try {
session.commit();
// log the total number of process rows
- progressTask.log();
+ progress.log();
} finally {
session.close();
-
- timer.cancel();
- timer.purge();
+ progress.stop();
}
}
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
-
import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
-import org.slf4j.LoggerFactory;
import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.internal.Uuids;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.migration.v50.Migration50Mapper;
import org.sonar.server.db.DbClient;
import org.sonar.server.db.migrations.DatabaseMigration;
-import org.sonar.server.util.ProgressTask;
+import org.sonar.server.util.ProgressLogger;
import java.util.List;
import java.util.Map;
-import java.util.Timer;
import java.util.concurrent.atomic.AtomicLong;
import static com.google.common.collect.Lists.newArrayList;
private final DbClient db;
private final AtomicLong counter = new AtomicLong(0L);
- private final ProgressTask progressTask = new ProgressTask(counter, LoggerFactory.getLogger("DbMigration"));
+ private final ProgressLogger progress = ProgressLogger.create(getClass(), counter);
public PopulateProjectsUuidColumnsMigration(DbClient db) {
this.db = db;
@Override
public void execute() {
- Timer timer = new Timer("Db Migration Progress");
- timer.schedule(progressTask, ProgressTask.PERIOD_MS, ProgressTask.PERIOD_MS);
+ progress.start();
final DbSession readSession = db.openSession(false);
final DbSession writeSession = db.openSession(true);
writeSession.commit();
// log the total number of process rows
- progressTask.log();
+ progress.log();
} finally {
readSession.close();
writeSession.close();
- timer.cancel();
- timer.purge();
+ progress.stop();
}
}
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
-
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse;
import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequestBuilder;
import org.elasticsearch.common.unit.ByteSizeUnit;
import org.elasticsearch.common.unit.ByteSizeValue;
import org.picocontainer.Startable;
-import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.sonar.server.util.ProgressTask;
+import org.sonar.server.util.ProgressLogger;
import java.util.Map;
-import java.util.Timer;
import java.util.concurrent.atomic.AtomicLong;
/**
private Map<String, Object> largeInitialSettings = null;
private final AtomicLong counter = new AtomicLong(0L);
- private final ProgressTask progressTask = new ProgressTask(counter, LoggerFactory.getLogger("BulkIndex")).setRowPluralName("requests");
- private final Timer timer = new Timer("Bulk index progress");
+ private final ProgressLogger progress;
public BulkIndexer(EsClient client, String indexName) {
this.client = client;
this.indexName = indexName;
+ this.progress = new ProgressLogger(String.format("Progress[BulkIndexer[%s]]", indexName), counter,
+ LoggerFactory.getLogger(BulkIndexer.class))
+ .setPluralLabel("requests");
}
/**
updateSettings(bulkSettings);
}
bulkRequest = client.prepareBulk();
- timer.schedule(progressTask, ProgressTask.PERIOD_MS, ProgressTask.PERIOD_MS);
+ counter.set(0L);
+ progress.start();
}
public void add(ActionRequest request) {
executeBulk(bulkRequest);
}
- // Log final advancement and reset counter
- progressTask.log();
- counter.set(0L);
- timer.cancel();
- timer.purge();
+ progress.stop();
if (refresh) {
client.prepareRefresh(indexName).get();
import java.util.Date;
-/**
- * @since 4.4
- */
public class IndexSynchronizer {
private static final Logger LOG = LoggerFactory.getLogger(IndexSynchronizer.class);
}
public void execute() {
- /* synchronize all activeRules until we have mng tables in INDEX */
- DbSession session = db.openSession(true);
+ DbSession session = db.openSession(false);
try {
synchronize(session, db.ruleDao(), index.get(RuleIndex.class));
synchronize(session, db.activeRuleDao(), index.get(ActiveRuleIndex.class));
synchronize(session, db.activityDao(), index.get(ActivityIndex.class));
-
- LOG.info("Indexing issues");
- issueAuthorizationIndexer.index();
- issueIndexer.indexAll();
-
- LOG.info("Indexing source files");
- sourceLineIndexer.index();
-
session.commit();
} finally {
session.close();
}
+
+ LOG.info("Index issues");
+ issueAuthorizationIndexer.index();
+ issueIndexer.index();
+
+ LOG.info("Index source files");
+ sourceLineIndexer.index();
}
void synchronize(DbSession session, Dao dao, Index index) {
long count = index.getIndexStat().getDocumentCount();
Date lastSynch = index.getLastSynchronization();
if (count <= 0) {
- LOG.info("Initial indexing of {} records", index.getIndexType());
+ LOG.info("Index {}s", index.getIndexType());
dao.synchronizeAfter(session);
} else {
- LOG.info("Synchronizing {} records for updates after {}", index.getIndexType(), lastSynch);
+ LOG.info("Index {}s for updates after {}", index.getIndexType(), lastSynch);
dao.synchronizeAfter(session, lastSynch);
}
}
public void deleteByFile(String fileUuid) {
esClient.prepareDeleteByQuery(SourceLineIndexDefinition.INDEX)
.setTypes(SourceLineIndexDefinition.TYPE)
- .setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), FilterBuilders.termFilter(FIELD_FILE_UUID, fileUuid).cache(false)))
+ .setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(),
+ FilterBuilders.termFilter(FIELD_FILE_UUID, fileUuid).cache(false)))
.get();
}
public void deleteByProject(String projectUuid) {
esClient.prepareDeleteByQuery(SourceLineIndexDefinition.INDEX)
.setTypes(SourceLineIndexDefinition.TYPE)
- .setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), FilterBuilders.termFilter(FIELD_PROJECT_UUID, projectUuid).cache(false)))
+ .setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(),
+ FilterBuilders.termFilter(FIELD_PROJECT_UUID, projectUuid).cache(false)))
.get();
}
}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Background thread that logs the state of a counter at fixed intervals.
+ */
+public class ProgressLogger {
+
+ public static final long DEFAULT_PERIOD_MS = 60000L;
+
+ private final Timer timer;
+ private final LoggerTimerTask task;
+ private long periodMs = DEFAULT_PERIOD_MS;
+
+ public ProgressLogger(String threadName, AtomicLong counter, Logger logger) {
+ this.timer = new Timer(threadName);
+ this.task = new LoggerTimerTask(counter, logger);
+ }
+
+ public static ProgressLogger create(Class clazz, AtomicLong counter) {
+ String threadName = String.format("ProgressLogger[%s]", clazz.getSimpleName());
+ Logger logger = LoggerFactory.getLogger(clazz);
+ return new ProgressLogger(threadName, counter, logger);
+ }
+
+ /**
+ * Warning, does not check if already started.
+ */
+ public void start() {
+ // first log after {periodMs} milliseconds
+ timer.schedule(task, periodMs, periodMs);
+ }
+
+ public void stop() {
+ timer.cancel();
+ timer.purge();
+ }
+
+ /**
+ * Default is 1 minute
+ */
+ public ProgressLogger setPeriodMs(long l) {
+ this.periodMs = l;
+ return this;
+ }
+
+ public long getPeriodMs() {
+ return periodMs;
+ }
+
+ /**
+ * For example "issues", "measures", ... Default is "rows".
+ */
+ public ProgressLogger setPluralLabel(String s) {
+ task.pluralLabel = s;
+ return this;
+ }
+
+ public String getPluralLabel() {
+ return task.pluralLabel;
+ }
+
+ public void log() {
+ task.run();
+ }
+
+ private static class LoggerTimerTask extends TimerTask {
+ private final AtomicLong counter;
+ private final Logger logger;
+ private String pluralLabel = "rows";
+
+ private LoggerTimerTask(AtomicLong counter, Logger logger) {
+ this.counter = counter;
+ this.logger = logger;
+ }
+
+ @Override
+ public void run() {
+ logger.info(String.format("%d %s processed", counter.get(), pluralLabel));
+ }
+ }
+}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 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.util;
-
-import java.util.TimerTask;
-import java.util.concurrent.atomic.AtomicLong;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ProgressTask extends TimerTask {
- private final Logger logger;
- public static final long PERIOD_MS = 60000L;
- private final AtomicLong counter;
- private String rowName = "rows";
-
- public ProgressTask(AtomicLong counter, Logger logger) {
- this.counter = counter;
- this.logger = logger;
- }
-
- public ProgressTask setRowPluralName(String s) {
- this.rowName = s;
- return this;
- }
-
- @Override
- public void run() {
- log();
- }
-
- public void log() {
- logger.info(String.format("%d %s processed", counter.get(), rowName));
- }
-}
--- /dev/null
+package org.sonar.server.util;
+
+import org.junit.Test;
+import org.slf4j.Logger;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class ProgressLoggerTest {
+
+ @Test(timeout = 1000L)
+ public void log_at_fixed_intervals() throws Exception {
+ Logger logger = mock(Logger.class);
+ AtomicLong counter = new AtomicLong(42L);
+ ProgressLogger progress = new ProgressLogger("ProgressLoggerTest", counter, logger);
+ progress.setPeriodMs(1L);
+ progress.start();
+ Thread.sleep(20L);
+ progress.stop();
+ verify(logger, atLeast(1)).info("42 rows processed");
+
+ // ability to manual log, generally final status
+ counter.incrementAndGet();
+ progress.log();
+ verify(logger).info("43 rows processed");
+ }
+
+ @Test
+ public void create() throws Exception {
+ ProgressLogger progress = ProgressLogger.create(getClass(), new AtomicLong());
+
+ // default values
+ assertThat(progress.getPeriodMs()).isEqualTo(60000L);
+ assertThat(progress.getPluralLabel()).isEqualTo("rows");
+
+ // override values
+ progress.setPeriodMs(10L);
+ progress.setPluralLabel("issues");
+ assertThat(progress.getPeriodMs()).isEqualTo(10L);
+ assertThat(progress.getPluralLabel()).isEqualTo("issues");
+
+ }
+}