Make InMemoryMetricRepository.increment() thread safe
This commit is contained in:
parent
eb246d6bed
commit
7a6131c466
|
@ -31,18 +31,26 @@ public class InMemoryMetricRepository implements MetricRepository {
|
|||
|
||||
private ConcurrentMap<String, Measurement> metrics = new ConcurrentHashMap<String, Measurement>();
|
||||
|
||||
private ConcurrentMap<String, Object> locks = new ConcurrentHashMap<String, Object>();
|
||||
|
||||
@Override
|
||||
public void increment(String metricName, int amount, Date timestamp) {
|
||||
Measurement current = this.metrics.get(metricName);
|
||||
if (current != null) {
|
||||
Metric metric = current.getMetric();
|
||||
this.metrics.replace(metricName, current,
|
||||
new Measurement(timestamp, metric.increment(amount)));
|
||||
}
|
||||
else {
|
||||
this.metrics.putIfAbsent(metricName, new Measurement(timestamp, new Metric(
|
||||
metricName, amount)));
|
||||
Object lock = this.locks.putIfAbsent(metricName, new Object());
|
||||
if (lock == null) {
|
||||
lock = this.locks.get(metricName);
|
||||
}
|
||||
synchronized (lock) {
|
||||
current = this.metrics.get(metricName);
|
||||
Metric metric = current.getMetric();
|
||||
this.metrics.replace(metricName, current, new Measurement(timestamp,
|
||||
metric.increment(amount)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.metrics.putIfAbsent(metricName, new Measurement(timestamp, new Metric(
|
||||
metricName, amount)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,24 +16,65 @@
|
|||
|
||||
package org.springframework.boot.actuate.metrics;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.actuate.metrics.InMemoryMetricRepository;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for {@link InMemoryMetricRepository}.
|
||||
*/
|
||||
@Ignore
|
||||
public class InMemoryMetricRepositoryTests {
|
||||
|
||||
// FIXME write tests
|
||||
// FIXME possibly also add Metric/Measurement tests
|
||||
private InMemoryMetricRepository repository = new InMemoryMetricRepository();
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
fail("Not yet implemented");
|
||||
public void increment() {
|
||||
this.repository.increment("foo", 1, new Date());
|
||||
assertEquals(1.0, this.repository.findOne("foo").getValue(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementConcurrent() throws Exception {
|
||||
Collection<Callable<Boolean>> tasks = new ArrayList<Callable<Boolean>>();
|
||||
for (int i = 0; i < 100; i++) {
|
||||
tasks.add(new Callable<Boolean>() {
|
||||
@Override
|
||||
public Boolean call() throws Exception {
|
||||
InMemoryMetricRepositoryTests.this.repository.increment("foo", 1,
|
||||
new Date());
|
||||
return true;
|
||||
}
|
||||
});
|
||||
tasks.add(new Callable<Boolean>() {
|
||||
@Override
|
||||
public Boolean call() throws Exception {
|
||||
InMemoryMetricRepositoryTests.this.repository.increment("foo", -1,
|
||||
new Date());
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
List<Future<Boolean>> all = Executors.newFixedThreadPool(10).invokeAll(tasks);
|
||||
for (Future<Boolean> future : all) {
|
||||
assertTrue(future.get(1, TimeUnit.SECONDS));
|
||||
}
|
||||
assertEquals(0, this.repository.findOne("foo").getValue(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void set() {
|
||||
this.repository.set("foo", 1, new Date());
|
||||
assertEquals(1.0, this.repository.findOne("foo").getValue(), 0.01);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue