Skip to content

Commit 8e5f235

Browse files
authored
Merge pull request #522 from bonitoo-io/stringbuilder-cache
- fixing memory leak and performance #521
2 parents 3ff7c42 + fd729f6 commit 8e5f235

File tree

1 file changed

+24
-50
lines changed

1 file changed

+24
-50
lines changed

src/main/java/org/influxdb/dto/Point.java

+24-50
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@
33
import java.math.BigDecimal;
44
import java.math.BigInteger;
55
import java.text.NumberFormat;
6-
import java.util.HashMap;
76
import java.util.Locale;
87
import java.util.Map;
98
import java.util.Map.Entry;
109
import java.util.Objects;
1110
import java.util.TreeMap;
1211
import java.util.concurrent.TimeUnit;
13-
1412
import org.influxdb.impl.Preconditions;
1513

1614
/**
@@ -35,8 +33,9 @@ public class Point {
3533
return numberFormat;
3634
});
3735

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

4140
Point() {
4241
}
@@ -318,35 +317,29 @@ public String toString() {
318317
* @return the String without newLine.
319318
*/
320319
public String lineProtocol() {
321-
final StringBuilder sb = CACHED_STRINGBUILDERS
322-
.get()
323-
.computeIfAbsent(this.measurement, MeasurementStringBuilder::new)
324-
.resetForUse();
320+
return lineProtocol(null);
321+
}
322+
323+
/**
324+
* Calculate the lineprotocol entry for a single point, using a specific {@link TimeUnit} for the timestamp.
325+
* @param precision the time precision unit for this point
326+
* @return the String without newLine
327+
*/
328+
public String lineProtocol(final TimeUnit precision) {
325329

330+
// setLength(0) is used for reusing cached StringBuilder instance per thread
331+
// it reduces GC activity and performs better then new StringBuilder()
332+
StringBuilder sb = CACHED_STRINGBUILDERS.get();
333+
sb.setLength(0);
334+
335+
escapeKey(sb, measurement);
326336
concatenatedTags(sb);
327337
concatenatedFields(sb);
328-
formatedTime(sb);
338+
formatedTime(sb, precision);
329339

330340
return sb.toString();
331341
}
332342

333-
/**
334-
* Calculate the lineprotocol entry for a single point, using a specific {@link TimeUnit} for the timestamp.
335-
* @param precision the time precision unit for this point
336-
* @return the String without newLine
337-
*/
338-
public String lineProtocol(final TimeUnit precision) {
339-
final StringBuilder sb = CACHED_STRINGBUILDERS
340-
.get()
341-
.computeIfAbsent(this.measurement, MeasurementStringBuilder::new)
342-
.resetForUse();
343-
344-
concatenatedTags(sb);
345-
concatenatedFields(sb);
346-
formatedTime(sb, precision);
347-
return sb.toString();
348-
}
349-
350343
private void concatenatedTags(final StringBuilder sb) {
351344
for (Entry<String, String> tag : this.tags.entrySet()) {
352345
sb.append(',');
@@ -415,33 +408,14 @@ static void escapeField(final StringBuilder sb, final String field) {
415408
}
416409
}
417410

418-
private void formatedTime(final StringBuilder sb) {
419-
if (this.time == null || this.precision == null) {
411+
private void formatedTime(final StringBuilder sb, final TimeUnit precision) {
412+
if (this.time == null) {
420413
return;
421414
}
422-
sb.append(' ').append(TimeUnit.NANOSECONDS.convert(this.time, this.precision));
423-
}
424-
425-
private StringBuilder formatedTime(final StringBuilder sb, final TimeUnit precision) {
426-
if (this.time == null || this.precision == null) {
427-
return sb;
415+
if (precision == null) {
416+
sb.append(" ").append(TimeUnit.NANOSECONDS.convert(this.time, this.precision));
417+
return;
428418
}
429419
sb.append(" ").append(precision.convert(this.time, this.precision));
430-
return sb;
431-
}
432-
433-
private static class MeasurementStringBuilder {
434-
private final StringBuilder sb = new StringBuilder(128);
435-
private final int length;
436-
437-
MeasurementStringBuilder(final String measurement) {
438-
escapeKey(this.sb, measurement);
439-
this.length = sb.length();
440-
}
441-
442-
StringBuilder resetForUse() {
443-
sb.setLength(length);
444-
return sb;
445-
}
446420
}
447421
}

0 commit comments

Comments
 (0)