Fix synchronization issue in OpenTSDBMetricWriter

Closes gh-4010
pull/3901/merge
Thomas Badie 9 years ago committed by Phillip Webb
parent c629813165
commit 2fd1cacbf3

@ -18,6 +18,7 @@ package org.springframework.boot.actuate.metrics.opentsdb;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -43,6 +44,7 @@ import org.springframework.web.client.RestTemplate;
* task to flush periodically. * task to flush periodically.
* *
* @author Dave Syer * @author Dave Syer
* @author Thomas Badie
* @since 1.3.0 * @since 1.3.0
*/ */
public class OpenTsdbMetricWriter implements MetricWriter { public class OpenTsdbMetricWriter implements MetricWriter {
@ -67,7 +69,7 @@ public class OpenTsdbMetricWriter implements MetricWriter {
*/ */
private MediaType mediaType = MediaType.APPLICATION_JSON; private MediaType mediaType = MediaType.APPLICATION_JSON;
private List<OpenTsdbData> buffer = new ArrayList<OpenTsdbData>(this.bufferSize); private final List<OpenTsdbData> buffer = new ArrayList<OpenTsdbData>(this.bufferSize);
private OpenTsdbNamingStrategy namingStrategy = new DefaultOpenTsdbNamingStrategy(); private OpenTsdbNamingStrategy namingStrategy = new DefaultOpenTsdbNamingStrategy();
@ -105,35 +107,42 @@ public class OpenTsdbMetricWriter implements MetricWriter {
OpenTsdbData data = new OpenTsdbData( OpenTsdbData data = new OpenTsdbData(
this.namingStrategy.getName(value.getName()), value.getValue(), value this.namingStrategy.getName(value.getName()), value.getValue(), value
.getTimestamp().getTime()); .getTimestamp().getTime());
this.buffer.add(data); synchronized (this.buffer) {
if (this.buffer.size() >= this.bufferSize) { this.buffer.add(data);
flush(); if (this.buffer.size() >= this.bufferSize) {
flush();
}
} }
} }
/** /**
* Flush the buffer without waiting for it to fill any further. * Flush the buffer without waiting for it to fill any further.
*/ */
@SuppressWarnings("rawtypes")
public void flush() { public void flush() {
if (this.buffer.isEmpty()) { List<OpenTsdbData> snapshot = getBufferSnapshot();
if (snapshot.isEmpty()) {
return; return;
} }
List<OpenTsdbData> temp = new ArrayList<OpenTsdbData>();
synchronized (this.buffer) {
temp.addAll(this.buffer);
this.buffer.clear();
}
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(this.mediaType)); headers.setAccept(Arrays.asList(this.mediaType));
headers.setContentType(this.mediaType); headers.setContentType(this.mediaType);
HttpEntity<List<OpenTsdbData>> request = new HttpEntity<List<OpenTsdbData>>(temp, ResponseEntity<Map> response = this.restTemplate.postForEntity(this.url,
headers); new HttpEntity<List<OpenTsdbData>>(snapshot, headers), Map.class);
@SuppressWarnings("rawtypes")
ResponseEntity<Map> response = this.restTemplate.postForEntity(this.url, request,
Map.class);
if (!response.getStatusCode().is2xxSuccessful()) { if (!response.getStatusCode().is2xxSuccessful()) {
logger.warn("Cannot write metrics (discarded " + temp.size() + " values): " logger.warn("Cannot write metrics (discarded " + snapshot.size()
+ response.getBody()); + " values): " + response.getBody());
}
}
private List<OpenTsdbData> getBufferSnapshot() {
synchronized (this.buffer) {
if (this.buffer.isEmpty()) {
return Collections.emptyList();
}
List<OpenTsdbData> snapshot = new ArrayList<OpenTsdbData>(this.buffer);
this.buffer.clear();
return snapshot;
} }
} }

@ -40,6 +40,7 @@ import static org.mockito.Mockito.verify;
public class OpenTsdbMetricWriterTests { public class OpenTsdbMetricWriterTests {
private OpenTsdbMetricWriter writer; private OpenTsdbMetricWriter writer;
private RestOperations restTemplate = Mockito.mock(RestOperations.class); private RestOperations restTemplate = Mockito.mock(RestOperations.class);
@Before @Before

Loading…
Cancel
Save