mirror of
https://github.com/SonarSource/sonarqube.git
synced 2024-08-07 15:05:55 +02:00
Try to improve performance of MeasurePersister
This commit is contained in:
parent
383f667695
commit
f3ce69889f
2
pom.xml
2
pom.xml
@ -813,7 +813,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis</artifactId>
|
||||
<version>3.2.2</version>
|
||||
<version>3.2.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.picocontainer</groupId>
|
||||
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* 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.batch.api;
|
||||
|
||||
/**
|
||||
* Dependency Injection : all the classes implementing this interface are available in the batch IoC container.
|
||||
* Just add a parameter to the constructor of your component.
|
||||
*
|
||||
* @since 4.4
|
||||
*/
|
||||
public interface BatchComponent {
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
/*
|
||||
* 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.batch.api;
|
||||
|
||||
|
||||
/**
|
||||
* Batch extension point.
|
||||
*
|
||||
* @since 4.4
|
||||
*/
|
||||
public interface BatchExtension extends BatchComponent {
|
||||
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* 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.batch.api;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Define instantiation strategy of batch extensions. If an extension is not annotated, then default value
|
||||
* is {@link #PER_PROJECT}.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface InstantiationStrategy {
|
||||
|
||||
/**
|
||||
* Shared extension. Lifecycle is the full analysis.
|
||||
*/
|
||||
String PER_BATCH = "PER_BATCH";
|
||||
|
||||
/**
|
||||
* Created and initialized for each project and sub-project (a project is a module in Maven terminology).
|
||||
*/
|
||||
String PER_PROJECT = "PER_PROJECT";
|
||||
|
||||
String value();
|
||||
}
|
@ -25,6 +25,8 @@ import com.persistit.Exchange;
|
||||
import com.persistit.Persistit;
|
||||
import com.persistit.Value;
|
||||
import com.persistit.Volume;
|
||||
import com.persistit.encoding.CoderManager;
|
||||
import com.persistit.encoding.ValueCoder;
|
||||
import com.persistit.exception.PersistitException;
|
||||
import com.persistit.logging.Slf4jAdapter;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
@ -78,6 +80,11 @@ public class Caches implements BatchComponent, Startable {
|
||||
}
|
||||
}
|
||||
|
||||
public void registerValueCoder(Class<?> clazz, ValueCoder coder) {
|
||||
CoderManager cm = persistit.getCoderManager();
|
||||
cm.registerValueCoder(clazz, coder);
|
||||
}
|
||||
|
||||
public <V extends Serializable> Cache<V> createCache(String cacheName) {
|
||||
Preconditions.checkState(volume != null && volume.isOpened(), "Caches are not initialized");
|
||||
Preconditions.checkState(!cacheNames.contains(cacheName), "Cache is already created: " + cacheName);
|
||||
|
@ -22,8 +22,10 @@ package org.sonar.batch.scan.measure;
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.sonar.api.BatchComponent;
|
||||
import org.sonar.api.measures.Measure;
|
||||
import org.sonar.api.measures.MetricFinder;
|
||||
import org.sonar.api.measures.RuleMeasure;
|
||||
import org.sonar.api.resources.Resource;
|
||||
import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
|
||||
import org.sonar.batch.index.Cache;
|
||||
import org.sonar.batch.index.Cache.Entry;
|
||||
import org.sonar.batch.index.Caches;
|
||||
@ -35,7 +37,8 @@ public class MeasureCache implements BatchComponent {
|
||||
|
||||
private final Cache<Measure> cache;
|
||||
|
||||
public MeasureCache(Caches caches) {
|
||||
public MeasureCache(Caches caches, MetricFinder metricFinder, TechnicalDebtModel techDebtModel) {
|
||||
caches.registerValueCoder(Measure.class, new MeasureValueCoder(metricFinder, techDebtModel));
|
||||
cache = caches.createCache("measures");
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.batch.scan.measure;
|
||||
|
||||
import com.persistit.Value;
|
||||
import com.persistit.encoding.CoderContext;
|
||||
import com.persistit.encoding.ValueCoder;
|
||||
import org.sonar.api.measures.Measure;
|
||||
import org.sonar.api.measures.Metric;
|
||||
import org.sonar.api.measures.MetricFinder;
|
||||
import org.sonar.api.measures.PersistenceMode;
|
||||
import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
|
||||
|
||||
class MeasureValueCoder implements ValueCoder {
|
||||
|
||||
private final MetricFinder metricFinder;
|
||||
private final TechnicalDebtModel techDebtModel;
|
||||
|
||||
public MeasureValueCoder(MetricFinder metricFinder, TechnicalDebtModel techDebtModel) {
|
||||
this.metricFinder = metricFinder;
|
||||
this.techDebtModel = techDebtModel;
|
||||
}
|
||||
|
||||
public void put(Value value, Object object, CoderContext context) {
|
||||
Measure<?> m = (Measure) object;
|
||||
value.putString(m.getMetricKey());
|
||||
value.put(m.getValue());
|
||||
value.putString(m.getData());
|
||||
value.putString(m.getDescription());
|
||||
value.putString(m.getAlertStatus() != null ? m.getAlertStatus().name() : null);
|
||||
value.putString(m.getAlertText());
|
||||
value.put(m.getTendency());
|
||||
value.putDate(m.getDate());
|
||||
value.put(m.getVariation1());
|
||||
value.put(m.getVariation2());
|
||||
value.put(m.getVariation3());
|
||||
value.put(m.getVariation4());
|
||||
value.put(m.getVariation5());
|
||||
value.putString(m.getUrl());
|
||||
value.put(m.getCharacteristic() != null ? m.getCharacteristic().id() : null);
|
||||
value.put(m.getRequirement() != null ? m.getRequirement().id() : null);
|
||||
value.put(m.getPersonId() != null ? m.getPersonId().intValue() : null);
|
||||
value.putString(m.getPersistenceMode() != null ? m.getPersistenceMode().name() : null);
|
||||
}
|
||||
|
||||
public Object get(Value value, Class clazz, CoderContext context) {
|
||||
Measure<?> m = new Measure();
|
||||
String metricKey = value.getString();
|
||||
m.setMetric(metricFinder.findByKey(metricKey));
|
||||
m.setRawValue(value.isNull(true) ? null : value.getDouble());
|
||||
m.setData(value.getString());
|
||||
m.setDescription(value.getString());
|
||||
m.setAlertStatus(value.isNull(true) ? null : Metric.Level.valueOf(value.getString()));
|
||||
m.setAlertText(value.getString());
|
||||
m.setTendency(value.isNull(true) ? null : value.getInt());
|
||||
m.setDate(value.getDate());
|
||||
m.setVariation1(value.isNull(true) ? null : value.getDouble());
|
||||
m.setVariation2(value.isNull(true) ? null : value.getDouble());
|
||||
m.setVariation3(value.isNull(true) ? null : value.getDouble());
|
||||
m.setVariation4(value.isNull(true) ? null : value.getDouble());
|
||||
m.setVariation5(value.isNull(true) ? null : value.getDouble());
|
||||
m.setUrl(value.getString());
|
||||
m.setCharacteristic(value.isNull(true) ? null : techDebtModel.characteristicById(value.getInt()));
|
||||
m.setRequirement(value.isNull(true) ? null : techDebtModel.requirementsById(value.getInt()));
|
||||
m.setPersonId(value.isNull(true) ? null : value.getInt());
|
||||
m.setPersistenceMode(value.isNull(true) ? null : PersistenceMode.valueOf(value.getString()));
|
||||
return m;
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@
|
||||
*/
|
||||
package org.sonar.batch.scan.measure;
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
@ -27,6 +28,8 @@ import org.junit.rules.ExpectedException;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.sonar.api.measures.CoreMetrics;
|
||||
import org.sonar.api.measures.Measure;
|
||||
import org.sonar.api.measures.Metric.Level;
|
||||
import org.sonar.api.measures.MetricFinder;
|
||||
import org.sonar.api.measures.RuleMeasure;
|
||||
import org.sonar.api.resources.Directory;
|
||||
import org.sonar.api.resources.File;
|
||||
@ -34,6 +37,9 @@ import org.sonar.api.resources.Project;
|
||||
import org.sonar.api.resources.Resource;
|
||||
import org.sonar.api.rule.RuleKey;
|
||||
import org.sonar.api.rules.RulePriority;
|
||||
import org.sonar.api.technicaldebt.batch.Characteristic;
|
||||
import org.sonar.api.technicaldebt.batch.Requirement;
|
||||
import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
|
||||
import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
|
||||
import org.sonar.batch.index.Cache.Entry;
|
||||
import org.sonar.batch.index.Caches;
|
||||
@ -43,6 +49,8 @@ import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class MeasureCacheTest {
|
||||
|
||||
@ -54,10 +62,17 @@ public class MeasureCacheTest {
|
||||
|
||||
Caches caches;
|
||||
|
||||
private MetricFinder metricFinder;
|
||||
|
||||
private TechnicalDebtModel techDebtModel;
|
||||
|
||||
@Before
|
||||
public void start() throws Exception {
|
||||
caches = CachesTest.createCacheOnTemp(temp);
|
||||
caches.start();
|
||||
metricFinder = mock(MetricFinder.class);
|
||||
when(metricFinder.findByKey(CoreMetrics.NCLOC_KEY)).thenReturn(CoreMetrics.NCLOC);
|
||||
techDebtModel = mock(TechnicalDebtModel.class);
|
||||
}
|
||||
|
||||
@After
|
||||
@ -67,7 +82,7 @@ public class MeasureCacheTest {
|
||||
|
||||
@Test
|
||||
public void should_add_measure() throws Exception {
|
||||
MeasureCache cache = new MeasureCache(caches);
|
||||
MeasureCache cache = new MeasureCache(caches, metricFinder, techDebtModel);
|
||||
Project p = new Project("struts");
|
||||
|
||||
assertThat(cache.entries()).hasSize(0);
|
||||
@ -102,7 +117,7 @@ public class MeasureCacheTest {
|
||||
*/
|
||||
@Test
|
||||
public void should_add_measure_with_big_data() throws Exception {
|
||||
MeasureCache cache = new MeasureCache(caches);
|
||||
MeasureCache cache = new MeasureCache(caches, metricFinder, techDebtModel);
|
||||
Project p = new Project("struts");
|
||||
|
||||
assertThat(cache.entries()).hasSize(0);
|
||||
@ -142,7 +157,7 @@ public class MeasureCacheTest {
|
||||
*/
|
||||
@Test
|
||||
public void should_add_measure_with_too_big_data_for_persistit_pre_patch() throws Exception {
|
||||
MeasureCache cache = new MeasureCache(caches);
|
||||
MeasureCache cache = new MeasureCache(caches, metricFinder, techDebtModel);
|
||||
Project p = new Project("struts");
|
||||
|
||||
assertThat(cache.entries()).hasSize(0);
|
||||
@ -178,7 +193,7 @@ public class MeasureCacheTest {
|
||||
|
||||
@Test
|
||||
public void should_add_measure_with_too_big_data_for_persistit() throws Exception {
|
||||
MeasureCache cache = new MeasureCache(caches);
|
||||
MeasureCache cache = new MeasureCache(caches, metricFinder, techDebtModel);
|
||||
Project p = new Project("struts");
|
||||
|
||||
assertThat(cache.entries()).hasSize(0);
|
||||
@ -201,7 +216,7 @@ public class MeasureCacheTest {
|
||||
|
||||
@Test
|
||||
public void should_add_measure_with_same_metric() throws Exception {
|
||||
MeasureCache cache = new MeasureCache(caches);
|
||||
MeasureCache cache = new MeasureCache(caches, metricFinder, techDebtModel);
|
||||
Project p = new Project("struts");
|
||||
|
||||
assertThat(cache.entries()).hasSize(0);
|
||||
@ -223,7 +238,7 @@ public class MeasureCacheTest {
|
||||
|
||||
@Test
|
||||
public void should_get_measures() throws Exception {
|
||||
MeasureCache cache = new MeasureCache(caches);
|
||||
MeasureCache cache = new MeasureCache(caches, metricFinder, techDebtModel);
|
||||
Project p = new Project("struts");
|
||||
Resource dir = new Directory("foo/bar").setEffectiveKey("struts:foo/bar");
|
||||
Resource file1 = new File("foo/bar/File1.txt").setEffectiveKey("struts:foo/bar/File1.txt");
|
||||
@ -260,4 +275,46 @@ public class MeasureCacheTest {
|
||||
assertThat(cache.byResource(dir)).hasSize(1);
|
||||
assertThat(cache.byResource(dir).iterator().next()).isEqualTo(mDir);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_measure_coder() throws Exception {
|
||||
MeasureCache cache = new MeasureCache(caches, metricFinder, techDebtModel);
|
||||
Resource file1 = new File("foo/bar/File1.txt").setEffectiveKey("struts:foo/bar/File1.txt");
|
||||
|
||||
Measure measure = new Measure(CoreMetrics.NCLOC, 1.786, 5);
|
||||
cache.put(file1, measure);
|
||||
|
||||
Measure savedMeasure = cache.byResource(file1).iterator().next();
|
||||
|
||||
assertThat(EqualsBuilder.reflectionEquals(measure, savedMeasure)).isTrue();
|
||||
|
||||
measure = new Measure(CoreMetrics.NCLOC);
|
||||
measure.setData("data");
|
||||
measure.setAlertStatus(Level.ERROR);
|
||||
measure.setAlertText("alert");
|
||||
Characteristic c = mock(Characteristic.class);
|
||||
when(c.id()).thenReturn(1);
|
||||
when(techDebtModel.characteristicById(1)).thenReturn(c);
|
||||
measure.setCharacteristic(c);
|
||||
measure.setDate(new Date());
|
||||
measure.setDescription("description");
|
||||
measure.setPersistenceMode(null);
|
||||
measure.setPersonId(3);
|
||||
Requirement r = mock(Requirement.class);
|
||||
when(r.id()).thenReturn(7);
|
||||
when(techDebtModel.requirementsById(7)).thenReturn(r);
|
||||
measure.setRequirement(r);
|
||||
measure.setTendency(4);
|
||||
measure.setUrl("http://foo");
|
||||
measure.setVariation1(11.0);
|
||||
measure.setVariation2(12.0);
|
||||
measure.setVariation3(13.0);
|
||||
measure.setVariation4(14.0);
|
||||
measure.setVariation5(15.0);
|
||||
cache.put(file1, measure);
|
||||
|
||||
savedMeasure = cache.byResource(file1).iterator().next();
|
||||
assertThat(EqualsBuilder.reflectionEquals(measure, savedMeasure)).isTrue();
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
<mapper namespace="org.sonar.core.source.db.SnapshotSourceMapper">
|
||||
|
||||
<select id="selectSnapshotSource" parameterType="int" resultType="string">
|
||||
<select id="selectSnapshotSource" parameterType="long" resultType="string">
|
||||
SELECT data
|
||||
FROM snapshot_sources
|
||||
WHERE snapshot_id = #{sid}
|
||||
|
@ -289,6 +289,14 @@ public class Measure<G extends Serializable> implements Serializable {
|
||||
return setValue(v, DEFAULT_PRECISION);
|
||||
}
|
||||
|
||||
/**
|
||||
* For internal use
|
||||
*/
|
||||
public Measure setRawValue(@Nullable Double v) {
|
||||
this.value = v;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the measure value as an int
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user