From 1a8a6d5c91ddc8807c0f113ca4c470d8078bf721 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Mon, 5 Oct 2015 10:31:49 +0200 Subject: [PATCH] SONAR-6397 Use a cache when reading SCM info to reduce db calls --- .../scm/ScmInfoRepositoryImpl.java | 21 ++++++++++++++++-- .../scm/ScmInfoRepositoryImplTest.java | 22 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/scm/ScmInfoRepositoryImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/scm/ScmInfoRepositoryImpl.java index 7ac532af8aa..20a7e1d88b9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/scm/ScmInfoRepositoryImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/scm/ScmInfoRepositoryImpl.java @@ -20,6 +20,8 @@ package org.sonar.server.computation.scm; import com.google.common.base.Optional; +import java.util.HashMap; +import java.util.Map; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.batch.protocol.output.BatchReport; @@ -40,6 +42,8 @@ public class ScmInfoRepositoryImpl implements ScmInfoRepository { private final DbClient dbClient; private final SourceService sourceService; + private final Map scmInfoCache = new HashMap<>(); + public ScmInfoRepositoryImpl(BatchReportReader batchReportReader, DbClient dbClient, SourceService sourceService) { this.batchReportReader = batchReportReader; this.dbClient = dbClient; @@ -49,17 +53,30 @@ public class ScmInfoRepositoryImpl implements ScmInfoRepository { @Override public Optional getScmInfo(Component component) { checkNotNull(component, "Component cannot be bull"); + initializeScmInfoForComponent(component); + return Optional.fromNullable(scmInfoCache.get(component)); + } + + private void initializeScmInfoForComponent(Component component) { + if (scmInfoCache.containsKey(component)) { + return; + } + Optional scmInfoOptional = getScmInfoForComponent(component); + scmInfoCache.put(component, scmInfoOptional.isPresent() ? scmInfoOptional.get() : null); + } + + private Optional getScmInfoForComponent(Component component) { BatchReport.Changesets changesets = batchReportReader.readChangesets(component.getReportAttributes().getRef()); if (changesets == null) { LOGGER.trace("Reading SCM info from db for file '{}'", component); - return getFromDb(component); + return getScmInfoFromDb(component); } else { LOGGER.trace("Reading SCM info from report for file '{}'", component); return Optional.of(new ReportScmInfo(changesets)); } } - private Optional getFromDb(Component component){ + private Optional getScmInfoFromDb(Component component) { DbSession dbSession = dbClient.openSession(false); try { Optional> linesOpt = sourceService.getLines(dbSession, component.getUuid(), 1, Integer.MAX_VALUE); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/scm/ScmInfoRepositoryImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/scm/ScmInfoRepositoryImplTest.java index 04c0166a372..6108f9f640d 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/scm/ScmInfoRepositoryImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/scm/ScmInfoRepositoryImplTest.java @@ -24,6 +24,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.utils.System2; +import org.sonar.api.utils.log.LogTester; import org.sonar.batch.protocol.output.BatchReport; import org.sonar.db.DbClient; import org.sonar.db.DbTester; @@ -35,10 +36,14 @@ import org.sonar.server.source.SourceService; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.guava.api.Assertions.assertThat; +import static org.sonar.api.utils.log.LoggerLevel.TRACE; import static org.sonar.server.computation.component.ReportComponent.builder; public class ScmInfoRepositoryImplTest { + @Rule + public LogTester logTester = new LogTester(); + @Rule public ExpectedException thrown = ExpectedException.none(); @@ -61,6 +66,8 @@ public class ScmInfoRepositoryImplTest { ScmInfo scmInfo = underTest.getScmInfo(FILE).get(); assertThat(scmInfo.getAllChangesets()).hasSize(1); + + assertThat(logTester.logs(TRACE)).containsOnly("Reading SCM info from report for file 'ReportComponent{ref=1, key='FILE_KEY', type=FILE}'"); } @Test @@ -69,6 +76,8 @@ public class ScmInfoRepositoryImplTest { ScmInfo scmInfo = underTest.getScmInfo(FILE).get(); assertThat(scmInfo.getAllChangesets()).hasSize(1); + + assertThat(logTester.logs(TRACE)).containsOnly("Reading SCM info from db for file 'ReportComponent{ref=1, key='FILE_KEY', type=FILE}'"); } @Test @@ -111,6 +120,19 @@ public class ScmInfoRepositoryImplTest { underTest.getScmInfo(null); } + @Test + public void load_scm_info_from_cache_when_already_read() throws Exception { + addChangesetInReport("john", 123456789L, "rev-1"); + ScmInfo scmInfo = underTest.getScmInfo(FILE).get(); + assertThat(scmInfo.getAllChangesets()).hasSize(1); + + assertThat(logTester.logs(TRACE)).hasSize(1); + logTester.clear(); + + underTest.getScmInfo(FILE); + assertThat(logTester.logs(TRACE)).isEmpty(); + } + private void addChangesetInDb(String author, Long date, String revision) { DbFileSources.Data.Builder fileDataBuilder = DbFileSources.Data.newBuilder(); fileDataBuilder.addLinesBuilder() -- 2.39.5