aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/Batch.java7
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/DefaultDecoratorContext.java10
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java16
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java4
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java17
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/MemoryOptimizer.java97
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java3
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/phases/DecoratorsExecutor.java7
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/phases/SensorsExecutor.java7
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java16
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/MemoryOptimizerTest.java95
-rw-r--r--sonar-batch/src/test/resources/org/sonar/batch/index/MemoryOptimizerTest/shouldReloadEvictedMeasure.xml8
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java1
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java8
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java11
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/measures/MeasureTest.java13
16 files changed, 300 insertions, 20 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/Batch.java b/sonar-batch/src/main/java/org/sonar/batch/Batch.java
index 36a702073cd..c2b15adda09 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/Batch.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/Batch.java
@@ -19,9 +19,6 @@
*/
package org.sonar.batch;
-import java.net.URLClassLoader;
-import java.util.Arrays;
-
import org.apache.commons.configuration.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -43,6 +40,9 @@ import org.sonar.jpa.session.DatabaseSessionProvider;
import org.sonar.jpa.session.DriverDatabaseConnector;
import org.sonar.jpa.session.ThreadLocalDatabaseSessionFactory;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+
public class Batch {
private static final Logger LOG = LoggerFactory.getLogger(Batch.class);
@@ -89,6 +89,7 @@ public class Batch {
addComponent(EventPersister.class);
addComponent(LinkPersister.class);
addComponent(MeasurePersister.class);
+ addComponent(MemoryOptimizer.class);
addComponent(DefaultResourcePersister.class);
addComponent(SourcePersister.class);
addComponent(ViolationPersister.class);
diff --git a/sonar-batch/src/main/java/org/sonar/batch/DefaultDecoratorContext.java b/sonar-batch/src/main/java/org/sonar/batch/DefaultDecoratorContext.java
index 5272ab80cb1..dedee60406a 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/DefaultDecoratorContext.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/DefaultDecoratorContext.java
@@ -19,6 +19,7 @@
*/
package org.sonar.batch;
+import com.google.common.collect.Lists;
import org.sonar.api.batch.DecoratorContext;
import org.sonar.api.batch.Event;
import org.sonar.api.database.DatabaseSession;
@@ -32,7 +33,10 @@ import org.sonar.api.resources.Resource;
import org.sonar.api.rules.Violation;
import org.sonar.batch.index.DefaultIndex;
-import java.util.*;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
public class DefaultDecoratorContext implements DecoratorContext {
@@ -79,11 +83,11 @@ public class DefaultDecoratorContext implements DecoratorContext {
}
public Measure getMeasure(Metric metric) {
- return index.getMeasures(resource, MeasuresFilters.metric(metric));
+ return index.getMeasure(resource, metric);
}
public Collection<Measure> getChildrenMeasures(MeasuresFilter filter) {
- List<Measure> result = new ArrayList<Measure>();
+ List<Measure> result = Lists.newArrayList();
for (DecoratorContext childContext : childrenContexts) {
Object childResult = childContext.getMeasures(filter);
if (childResult != null) {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
index abafcdb150e..494e1a84997 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
@@ -19,8 +19,6 @@
*/
package org.sonar.batch.index;
-import java.util.*;
-
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@@ -43,6 +41,8 @@ import org.sonar.batch.ProjectTree;
import org.sonar.batch.ResourceFilters;
import org.sonar.batch.ViolationFilters;
+import java.util.*;
+
public class DefaultIndex extends SonarIndex {
private static final Logger LOG = LoggerFactory.getLogger(DefaultIndex.class);
@@ -136,7 +136,10 @@ public class DefaultIndex extends SonarIndex {
public Measure getMeasure(Resource resource, Metric metric) {
Bucket bucket = buckets.get(resource);
if (bucket != null) {
- return bucket.getMeasures(MeasuresFilters.metric(metric));
+ Measure measure = bucket.getMeasures(MeasuresFilters.metric(metric));
+ if (measure!=null) {
+ return persistence.reloadMeasure(measure);
+ }
}
return null;
}
@@ -144,6 +147,7 @@ public class DefaultIndex extends SonarIndex {
public <M> M getMeasures(Resource resource, MeasuresFilter<M> filter) {
Bucket bucket = buckets.get(resource);
if (bucket != null) {
+ // TODO the data measures which are not kept in memory are not reloaded yet. Use getMeasure().
return bucket.getMeasures(filter);
}
return null;
@@ -160,13 +164,11 @@ public class DefaultIndex extends SonarIndex {
throw new SonarException("Unknown metric: " + measure.getMetricKey());
}
measure.setMetric(metric);
- if (measure.getPersistenceMode().useMemory()) {
- bucket.addMeasure(measure);
- }
+ bucket.addMeasure(measure);
+
if (measure.getPersistenceMode().useDatabase()) {
persistence.saveMeasure(resource, measure);
}
- // TODO keep database measures in cache but remove data
}
return measure;
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java
index a89991610e4..f5722b7f5a2 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java
@@ -84,6 +84,10 @@ public final class DefaultPersistenceManager implements PersistenceManager {
}
}
+ public Measure reloadMeasure(Measure measure) {
+ return measurePersister.reloadMeasure(measure);
+ }
+
public void saveDependency(Project project, Dependency dependency, Dependency parentDependency) {
if (ResourceUtils.isPersistable(dependency.getFrom()) && ResourceUtils.isPersistable(dependency.getTo())) {
dependencyPersister.saveDependency(project, dependency, parentDependency);
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java
index 97942ef8f30..e11ab691509 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java
@@ -45,11 +45,14 @@ public final class MeasurePersister {
private DatabaseSession session;
private ResourcePersister resourcePersister;
private RuleFinder ruleFinder;
+ private MemoryOptimizer memoryOptimizer;
- public MeasurePersister(DatabaseSession session, ResourcePersister resourcePersister, RuleFinder ruleFinder) {
+
+ public MeasurePersister(DatabaseSession session, ResourcePersister resourcePersister, RuleFinder ruleFinder, MemoryOptimizer memoryOptimizer) {
this.session = session;
this.resourcePersister = resourcePersister;
this.ruleFinder = ruleFinder;
+ this.memoryOptimizer = memoryOptimizer;
}
public void setDelayedMode(boolean delayedMode) {
@@ -63,22 +66,30 @@ public final class MeasurePersister {
} else {
Snapshot snapshot = resourcePersister.getSnapshotOrFail(resource);
+ MeasureModel model = null;
if (measure.getId() != null) {
// update
- MeasureModel model = session.reattach(MeasureModel.class, measure.getId());
+ model = session.reattach(MeasureModel.class, measure.getId());
model = mergeModel(measure, model);
model.save(session);
} else if (shouldPersistMeasure(resource, measure)) {
// insert
- MeasureModel model = createModel(measure);
+ model = createModel(measure);
model.setSnapshotId(snapshot.getId());
model.save(session);
measure.setId(model.getId()); // could be removed
}
+ if (model != null) {
+ memoryOptimizer.evictDataMeasure(measure, model);
+ }
}
}
+ public Measure reloadMeasure(Measure measure) {
+ return memoryOptimizer.reloadMeasure(measure);
+ }
+
static boolean shouldPersistMeasure(Resource resource, Measure measure) {
Metric metric = measure.getMetric();
return measure.getPersistenceMode().useDatabase() &&
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/MemoryOptimizer.java b/sonar-batch/src/main/java/org/sonar/batch/index/MemoryOptimizer.java
new file mode 100644
index 00000000000..0fa0610d900
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/MemoryOptimizer.java
@@ -0,0 +1,97 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.index;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.database.DatabaseSession;
+import org.sonar.api.database.model.MeasureData;
+import org.sonar.api.database.model.MeasureModel;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.measures.PersistenceMode;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @since 2.7
+ */
+public class MemoryOptimizer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MemoryOptimizer.class);
+
+ private List<Measure> loadedMeasures = Lists.newArrayList();
+ private Map<Long, Integer> dataIdByMeasureId = Maps.newHashMap();
+ private DatabaseSession session;
+
+ public MemoryOptimizer(DatabaseSession session) {
+ this.session = session;
+ }
+
+ /**
+ * Remove data of a database measure from memory.
+ */
+ public void evictDataMeasure(Measure measure, MeasureModel model) {
+ if (PersistenceMode.DATABASE.equals(measure.getPersistenceMode())) {
+ MeasureData data = model.getMeasureData();
+ if (data != null && data.getId() != null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Remove data measure from memory: " + measure.getMetricKey() + ", id=" + measure.getId());
+ }
+ measure.unsetData();
+ dataIdByMeasureId.put(measure.getId(), data.getId());
+ }
+ }
+ }
+
+ public Measure reloadMeasure(Measure measure) {
+ if (measure.getId() != null && dataIdByMeasureId.containsKey(measure.getId()) && !measure.hasData()) {
+ Integer dataId = dataIdByMeasureId.get(measure.getId());
+ MeasureData data = session.getSingleResult(MeasureData.class, "id", dataId);
+ if (data == null) {
+ LoggerFactory.getLogger(getClass()).error("The MEASURE_DATA row with id " + dataId + " is lost");
+
+ } else {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Reload the data measure: " + measure.getMetricKey() + ", id=" + measure.getId());
+ }
+ measure.setData(data.getText());
+ loadedMeasures.add(measure);
+ }
+ }
+ return measure;
+ }
+
+ public void flushMemory() {
+ if (LOG.isDebugEnabled() && loadedMeasures.size() > 0) {
+ LOG.debug("Flush " + loadedMeasures.size() + " data measures from memory: ");
+ }
+ for (Measure measure : loadedMeasures) {
+ measure.unsetData();
+ }
+ loadedMeasures.clear();
+ }
+
+ boolean isTracked(Long measureId) {
+ return dataIdByMeasureId.get(measureId)!=null;
+ }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java b/sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java
index cef245960c9..98de69eb77f 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java
@@ -23,7 +23,6 @@ import org.sonar.api.batch.Event;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.design.Dependency;
import org.sonar.api.measures.Measure;
-import org.sonar.api.resources.File;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.ProjectLink;
import org.sonar.api.resources.Resource;
@@ -45,6 +44,8 @@ public interface PersistenceManager {
void saveMeasure(Resource resource, Measure measure);
+ Measure reloadMeasure(Measure measure);
+
void saveDependency(Project project, Dependency dependency, Dependency parentDependency);
void saveLink(Project project, ProjectLink link);
diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/DecoratorsExecutor.java b/sonar-batch/src/main/java/org/sonar/batch/phases/DecoratorsExecutor.java
index 74b7179b16a..15532994702 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/phases/DecoratorsExecutor.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/phases/DecoratorsExecutor.java
@@ -34,6 +34,7 @@ import org.sonar.api.resources.Resource;
import org.sonar.batch.DecoratorsSelector;
import org.sonar.batch.DefaultDecoratorContext;
import org.sonar.batch.index.DefaultIndex;
+import org.sonar.batch.index.MemoryOptimizer;
import java.util.Collection;
import java.util.IdentityHashMap;
@@ -46,11 +47,14 @@ public class DecoratorsExecutor implements BatchComponent {
private DatabaseSession session;
private static final Logger LOG = LoggerFactory.getLogger(DecoratorsExecutor.class);
private DefaultIndex index;
+ private MemoryOptimizer memoryOptimizer;
- public DecoratorsExecutor(BatchExtensionDictionnary extensionDictionnary, DefaultIndex index, DatabaseSession session) {
+ public DecoratorsExecutor(BatchExtensionDictionnary extensionDictionnary, DefaultIndex index, DatabaseSession session,
+ MemoryOptimizer memoryOptimizer) {
this.decoratorsSelector = new DecoratorsSelector(extensionDictionnary);
this.session = session;
this.index = index;
+ this.memoryOptimizer = memoryOptimizer;
}
@@ -81,6 +85,7 @@ public class DecoratorsExecutor implements BatchComponent {
for (Decorator decorator : decorators) {
profiler.start(decorator);
decorator.decorate(resource, context);
+ memoryOptimizer.flushMemory();
profiler.stop();
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/SensorsExecutor.java b/sonar-batch/src/main/java/org/sonar/batch/phases/SensorsExecutor.java
index 707015d2d5a..e78a56f25c7 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/phases/SensorsExecutor.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/phases/SensorsExecutor.java
@@ -32,6 +32,7 @@ import org.sonar.api.database.DatabaseSession;
import org.sonar.api.resources.Project;
import org.sonar.api.utils.TimeProfiler;
import org.sonar.batch.MavenPluginExecutor;
+import org.sonar.batch.index.MemoryOptimizer;
import java.util.Collection;
@@ -41,11 +42,14 @@ public class SensorsExecutor implements BatchComponent {
private Collection<Sensor> sensors;
private DatabaseSession session;
private MavenPluginExecutor mavenExecutor;
+ private MemoryOptimizer memoryOptimizer;
- public SensorsExecutor(BatchExtensionDictionnary selector, Project project, DatabaseSession session, MavenPluginExecutor mavenExecutor) {
+ public SensorsExecutor(BatchExtensionDictionnary selector, Project project, DatabaseSession session, MavenPluginExecutor mavenExecutor,
+ MemoryOptimizer memoryOptimizer) {
this.sensors = selector.select(Sensor.class, project, true);
this.session = session;
this.mavenExecutor = mavenExecutor;
+ this.memoryOptimizer = memoryOptimizer;
}
public void execute(Project project, SensorContext context) {
@@ -58,6 +62,7 @@ public class SensorsExecutor implements BatchComponent {
TimeProfiler profiler = new TimeProfiler(logger).start("Sensor " + sensor);
sensor.analyse(project, context);
+ memoryOptimizer.flushMemory();
session.commit();
profiler.stop();
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java
index 81dd495a9f5..3753b6752e8 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java
@@ -36,11 +36,13 @@ import org.sonar.jpa.test.AbstractDbUnitTestCase;
import java.util.List;
+import static org.hamcrest.CoreMatchers.anyOf;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class MeasurePersisterTest extends AbstractDbUnitTestCase {
@@ -57,6 +59,7 @@ public class MeasurePersisterTest extends AbstractDbUnitTestCase {
private JavaFile aFile = new JavaFile("org.foo.Bar");
private Snapshot projectSnapshot, packageSnapshot, fileSnapshot;
private Metric ncloc, coverage;
+ private MemoryOptimizer memoryOptimizer;
@Before
public void mockResourcePersister() {
@@ -73,7 +76,8 @@ public class MeasurePersisterTest extends AbstractDbUnitTestCase {
when(resourcePersister.getSnapshot(project)).thenReturn(projectSnapshot);
when(resourcePersister.getSnapshot(aPackage)).thenReturn(packageSnapshot);
when(resourcePersister.getSnapshot(aFile)).thenReturn(fileSnapshot);
- measurePersister = new MeasurePersister(getSession(), resourcePersister, new DefaultRuleFinder(getSessionFactory()));
+ memoryOptimizer = mock(MemoryOptimizer.class);
+ measurePersister = new MeasurePersister(getSession(), resourcePersister, new DefaultRuleFinder(getSessionFactory()), memoryOptimizer);
}
@Test
@@ -86,6 +90,16 @@ public class MeasurePersisterTest extends AbstractDbUnitTestCase {
}
@Test
+ public void shouldRegisterPersistedMeasureToMemoryOptimizer() {
+ Measure measure = new Measure(ncloc).setValue(1234.0);
+
+ measurePersister.saveMeasure(project, measure);
+
+ verify(memoryOptimizer).evictDataMeasure(eq(measure), (MeasureModel)anyObject());
+ }
+
+
+ @Test
public void shouldUpdateMeasure() {
Measure measure = new Measure(coverage).setValue(12.5);
measure.setId(1L);
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/MemoryOptimizerTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/MemoryOptimizerTest.java
new file mode 100644
index 00000000000..6b3e0b86316
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/MemoryOptimizerTest.java
@@ -0,0 +1,95 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.index;
+
+import org.hamcrest.core.IsNull;
+import org.junit.Test;
+import org.sonar.api.database.model.MeasureData;
+import org.sonar.api.database.model.MeasureModel;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.measures.PersistenceMode;
+import org.sonar.jpa.test.AbstractDbUnitTestCase;
+
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.junit.Assert.assertThat;
+
+public class MemoryOptimizerTest extends AbstractDbUnitTestCase {
+
+ @Test
+ public void shouldEvictDatabaseOnlyMeasure() {
+ MemoryOptimizer optimizer = new MemoryOptimizer(getSession());
+ Measure measure = new Measure(CoreMetrics.CONDITIONS_BY_LINE)
+ .setData("10=23")
+ .setPersistenceMode(PersistenceMode.DATABASE)
+ .setId(12345L);
+ MeasureModel model = newPersistedModel();
+
+ optimizer.evictDataMeasure(measure, model);
+
+ assertThat(optimizer.isTracked(12345L),is(true));
+ assertThat(measure.getData(), nullValue());// data has been removed from memory
+ }
+
+ @Test
+ public void shouldNotEvictStandardMeasure() {
+ MemoryOptimizer optimizer = new MemoryOptimizer(getSession());
+ Measure measure = new Measure(CoreMetrics.PROFILE)
+ .setData("Sonar way")
+ .setId(12345L);
+ MeasureModel model = newPersistedModel();
+
+ optimizer.evictDataMeasure(measure, model);
+
+ assertThat(optimizer.isTracked(12345L),is(false));
+ assertThat(measure.getData(), is("Sonar way"));
+ }
+
+ @Test
+ public void shouldReloadEvictedMeasure() {
+ setupData("shouldReloadEvictedMeasure");
+ MemoryOptimizer optimizer = new MemoryOptimizer(getSession());
+ Measure measure = new Measure(CoreMetrics.CONDITIONS_BY_LINE)
+ .setData("initial")
+ .setPersistenceMode(PersistenceMode.DATABASE)
+ .setId(12345L);
+
+ optimizer.evictDataMeasure(measure, newPersistedModel());
+ assertThat(measure.getData(), nullValue());
+
+ optimizer.reloadMeasure(measure);
+
+ assertThat(measure.getData().length(), greaterThan(5));
+
+ optimizer.flushMemory();
+ assertThat(measure.getData(), nullValue());
+ }
+
+ private MeasureModel newPersistedModel() {
+ MeasureModel model = new MeasureModel();
+ model.setId(12345L);
+ MeasureData measureData = new MeasureData();
+ measureData.setId(500);
+ model.setMeasureData(measureData);
+ return model;
+ }
+}
diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/MemoryOptimizerTest/shouldReloadEvictedMeasure.xml b/sonar-batch/src/test/resources/org/sonar/batch/index/MemoryOptimizerTest/shouldReloadEvictedMeasure.xml
new file mode 100644
index 00000000000..5f40b829f73
--- /dev/null
+++ b/sonar-batch/src/test/resources/org/sonar/batch/index/MemoryOptimizerTest/shouldReloadEvictedMeasure.xml
@@ -0,0 +1,8 @@
+<dataset>
+
+
+ <measure_data id="2" measure_id="2" snapshot_id="2" data="[null]"/>
+ <measure_data id="500" measure_id="12345" snapshot_id="1" data="value from database"/>
+
+
+</dataset> \ No newline at end of file
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java
index 59c1f66ed9a..b33487af40f 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java
@@ -600,6 +600,7 @@ public final class CoreMetrics {
// SCM
+ // These metrics are computed by the SCM Activity plugin, since version 1.2.
public static final String SCM_COMMITS_KEY = "commits";
public static final Metric SCM_COMMITS = new Metric.Builder(SCM_COMMITS_KEY, Metric.ValueType.INT)
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java
index 3b64b89da3f..6462db590d5 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java
@@ -323,6 +323,14 @@ public class Measure {
}
/**
+ * @since 2.7
+ */
+ public Measure unsetData() {
+ this.data=null;
+ return this;
+ }
+
+ /**
* @return the description of the measure
*/
public String getDescription() {
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java
index 92050c92d81..e0ec08d89aa 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java
@@ -130,7 +130,9 @@ public class Metric implements ServerExtension, BatchExtension {
* Creates a metric based on its key. Shortcut to Metric(key, ValueType.INT)
*
* @param key the metric key
+ * @deprecated since 2.7 use the Builder factory.
*/
+ @Deprecated
public Metric(String key) {
this(key, ValueType.INT);
}
@@ -141,11 +143,17 @@ public class Metric implements ServerExtension, BatchExtension {
*
* @param key the key
* @param type the type
+ * @deprecated since 2.7 use the Builder factory.
*/
+ @Deprecated
public Metric(String key, ValueType type) {
this(key, key, key, type, -1, Boolean.FALSE, null, false);
}
+ /**
+ * @deprecated since 2.7 use the Builder factory.
+ */
+ @Deprecated
public Metric(String key, String name, String description, ValueType type, Integer direction, Boolean qualitative, String domain) {
this(key, name, description, type, direction, qualitative, domain, false);
}
@@ -164,6 +172,7 @@ public class Metric implements ServerExtension, BatchExtension {
* @param qualitative whether the metric is qualitative
* @param domain the metric domain
* @param userManaged whether the metric is user managed
+ * @deprecated since 2.7 use the Builder factory.
*/
@Deprecated
public Metric(String key, String name, String description, ValueType type, Integer direction, Boolean qualitative, String domain, boolean userManaged) {
@@ -197,7 +206,9 @@ public class Metric implements ServerExtension, BatchExtension {
* @param qualitative whether the metric is qualitative
* @param domain the metric domain
* @param formula the metric formula
+ * @deprecated since 2.7 use the Builder factory.
*/
+ @Deprecated
public Metric(String key, String name, ValueType type, Integer direction, Boolean qualitative, String domain, Formula formula) {
this.key = key;
this.name = name;
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/measures/MeasureTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/measures/MeasureTest.java
index 50f2a329574..6a29f0c1c22 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/measures/MeasureTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/measures/MeasureTest.java
@@ -114,4 +114,17 @@ public class MeasureTest {
assertFalse(measure.equals(ruleMeasure));
assertFalse(ruleMeasure.equals(measure));
}
+
+ @Test
+ public void shouldUnsetData() {
+ String data = "1=10;21=456";
+ Measure measure = new Measure(CoreMetrics.CONDITIONS_BY_LINE).setData( data);
+ assertThat(measure.hasData(), is(true));
+ assertThat(measure.getData(), is(data));
+
+ measure.unsetData();
+
+ assertThat(measure.hasData(), is(false));
+ assertThat(measure.getData(), nullValue());
+ }
}