Skip to content

Commit

Permalink
Merge pull request #522 from bonitoo-io/stringbuilder-cache
Browse files Browse the repository at this point in the history
- fixing memory leak and performance #521
  • Loading branch information
fmachado authored Sep 25, 2018
2 parents 3ff7c42 + fd729f6 commit 8e5f235
Showing 1 changed file with 24 additions and 50 deletions.
74 changes: 24 additions & 50 deletions src/main/java/org/influxdb/dto/Point.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;

import org.influxdb.impl.Preconditions;

/**
Expand All @@ -35,8 +33,9 @@ public class Point {
return numberFormat;
});

private static final ThreadLocal<Map<String, MeasurementStringBuilder>> CACHED_STRINGBUILDERS =
ThreadLocal.withInitial(HashMap::new);
private static final int DEFAULT_STRING_BUILDER_SIZE = 1024;
private static final ThreadLocal<StringBuilder> CACHED_STRINGBUILDERS =
ThreadLocal.withInitial(() -> new StringBuilder(DEFAULT_STRING_BUILDER_SIZE));

Point() {
}
Expand Down Expand Up @@ -318,35 +317,29 @@ public String toString() {
* @return the String without newLine.
*/
public String lineProtocol() {
final StringBuilder sb = CACHED_STRINGBUILDERS
.get()
.computeIfAbsent(this.measurement, MeasurementStringBuilder::new)
.resetForUse();
return lineProtocol(null);
}

/**
* Calculate the lineprotocol entry for a single point, using a specific {@link TimeUnit} for the timestamp.
* @param precision the time precision unit for this point
* @return the String without newLine
*/
public String lineProtocol(final TimeUnit precision) {

// setLength(0) is used for reusing cached StringBuilder instance per thread
// it reduces GC activity and performs better then new StringBuilder()
StringBuilder sb = CACHED_STRINGBUILDERS.get();
sb.setLength(0);

escapeKey(sb, measurement);
concatenatedTags(sb);
concatenatedFields(sb);
formatedTime(sb);
formatedTime(sb, precision);

return sb.toString();
}

/**
* Calculate the lineprotocol entry for a single point, using a specific {@link TimeUnit} for the timestamp.
* @param precision the time precision unit for this point
* @return the String without newLine
*/
public String lineProtocol(final TimeUnit precision) {
final StringBuilder sb = CACHED_STRINGBUILDERS
.get()
.computeIfAbsent(this.measurement, MeasurementStringBuilder::new)
.resetForUse();

concatenatedTags(sb);
concatenatedFields(sb);
formatedTime(sb, precision);
return sb.toString();
}

private void concatenatedTags(final StringBuilder sb) {
for (Entry<String, String> tag : this.tags.entrySet()) {
sb.append(',');
Expand Down Expand Up @@ -415,33 +408,14 @@ static void escapeField(final StringBuilder sb, final String field) {
}
}

private void formatedTime(final StringBuilder sb) {
if (this.time == null || this.precision == null) {
private void formatedTime(final StringBuilder sb, final TimeUnit precision) {
if (this.time == null) {
return;
}
sb.append(' ').append(TimeUnit.NANOSECONDS.convert(this.time, this.precision));
}

private StringBuilder formatedTime(final StringBuilder sb, final TimeUnit precision) {
if (this.time == null || this.precision == null) {
return sb;
if (precision == null) {
sb.append(" ").append(TimeUnit.NANOSECONDS.convert(this.time, this.precision));
return;
}
sb.append(" ").append(precision.convert(this.time, this.precision));
return sb;
}

private static class MeasurementStringBuilder {
private final StringBuilder sb = new StringBuilder(128);
private final int length;

MeasurementStringBuilder(final String measurement) {
escapeKey(this.sb, measurement);
this.length = sb.length();
}

StringBuilder resetForUse() {
sb.setLength(length);
return sb;
}
}
}

0 comments on commit 8e5f235

Please sign in to comment.