fix performance regression

The last improvement of memory usage introduced a performance
regression. The ingestion performance dropped by 50%-80%, because
for every inserted entry the Tags were created inefficient.
This commit is contained in:
2018-03-27 19:30:18 +02:00
parent de0f8412bd
commit 81711d551f
7 changed files with 76 additions and 47 deletions

View File

@@ -65,7 +65,7 @@ public class Entry {
} }
final OffsetDateTime date = getDate(); final OffsetDateTime date = getDate();
return date.format(DateTimeFormatter.ISO_ZONED_DATE_TIME) + " = " + value + " (" + tags + ")"; return date.format(DateTimeFormatter.ISO_ZONED_DATE_TIME) + " = " + value + " (" + tags.asString() + ")";
} }
@Override @Override

View File

@@ -0,0 +1,15 @@
package org.lucares.pdb.api;
import java.io.Serializable;
import java.util.Comparator;
public class TagByKeyComparator implements Comparator<Tag>, Serializable {
private static final long serialVersionUID = -6683582291996307323L;
public static final TagByKeyComparator INSTANCE = new TagByKeyComparator();
@Override
public int compare(final Tag a, final Tag b) {
return a.getKey().compareToIgnoreCase(b.getKey());
}
}

View File

@@ -1,5 +1,7 @@
package org.lucares.pdb.api; package org.lucares.pdb.api;
import java.util.Arrays;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
@@ -47,49 +49,30 @@ public class Tags {
} }
} }
public static Tags create(final Collection<Tag> tags) {
final String newFilename = toFilename(tags);
return new Tags(newFilename);
}
public static Tags create() { public static Tags create() {
return EMPTY; return EMPTY;
} }
public static Tags create(final String key, final String value) { public static Tags create(final String key, final String value) {
return EMPTY.copyAdd(key, value); return TagsBuilder.create().add(key, value).build();
} }
public static Tags create(final String key1, final String value1, final String key2, final String value2) { public static Tags create(final String key1, final String value1, final String key2, final String value2) {
final Tags result = EMPTY.copyAdd(key1, value1).copyAdd(key2, value2); final Tags result = TagsBuilder.create().add(key1, value1).add(key2, value2).build();
return result; return result;
} }
public static Tags create(final String key1, final String value1, final String key2, final String value2, public static Tags create(final String key1, final String value1, final String key2, final String value2,
final String key3, final String value3) { final String key3, final String value3) {
final Tags result = EMPTY.copyAdd(key1, value1).copyAdd(key2, value2).copyAdd(key3, value3); final Tags result = TagsBuilder.create().add(key1, value1).add(key2, value2).add(key3, value3).build();
return result;
}
public Tags copyAdd(final String key, final String value) {
Objects.requireNonNull(key, "key must not be null");
Objects.requireNonNull(value, "value must not be null");
final Tag tag = new Tag(key, value);
final SortedSet<Tag> tags = toTags();
tags.add(tag);
final String newFilename = toFilename(tags);
return new Tags(newFilename);
}
public Tags copyAddIfNotNull(final String key, final String value) {
final Tags result;
if (value != null) {
result = copyAdd(key, value);
} else {
result = this;
}
return result; return result;
} }
@@ -109,7 +92,7 @@ public class Tags {
} }
private SortedSet<Tag> toTags() { private SortedSet<Tag> toTags() {
final SortedSet<Tag> result = new TreeSet<>((a, b) -> a.getKey().compareToIgnoreCase(b.getKey())); final SortedSet<Tag> result = new TreeSet<>(TagByKeyComparator.INSTANCE);
final Matcher matcher = EXTRACT_TAGS_PATTERN.matcher(filename); final Matcher matcher = EXTRACT_TAGS_PATTERN.matcher(filename);
if (matcher.find()) { if (matcher.find()) {
@@ -132,9 +115,12 @@ public class Tags {
return result; return result;
} }
public String toFilename(final SortedSet<Tag> tags) { private static String toFilename(final Collection<Tag> tags) {
final StringBuilder path = new StringBuilder(); final StringBuilder path = new StringBuilder();
final Tag[] tagsAsArray = tags.toArray(new Tag[tags.size()]);
Arrays.sort(tagsAsArray, TagByKeyComparator.INSTANCE);
for (final Tag tag : tags) { for (final Tag tag : tags) {
final String key = tag.getKey(); final String key = tag.getKey();
final String value = tag.getValue(); final String value = tag.getValue();
@@ -204,17 +190,17 @@ public class Tags {
public Tags subset(final List<String> groupByFields) { public Tags subset(final List<String> groupByFields) {
Tags result = new Tags(); final TagsBuilder result = TagsBuilder.create();
for (final String field : groupByFields) { for (final String field : groupByFields) {
final String value = getValue(field); final String value = getValue(field);
if (value != null) { if (value != null) {
result = result.copyAdd(field, value); result.add(field, value);
} }
} }
return result; return result.build();
} }
public boolean isEmpty() { public boolean isEmpty() {
@@ -236,7 +222,7 @@ public class Tags {
} }
result.append(tag.getKey()); result.append(tag.getKey());
result.append(":"); result.append("=");
result.append(tag.getValue()); result.append(tag.getValue());
} }

View File

@@ -0,0 +1,22 @@
package org.lucares.pdb.api;
import java.util.ArrayList;
import java.util.List;
public class TagsBuilder {
final List<Tag> tags = new ArrayList<>();
public static TagsBuilder create() {
return new TagsBuilder();
}
public TagsBuilder add(final String key, final String value) {
tags.add(new Tag(key, value));
return this;
}
public Tags build() {
return Tags.create(tags);
}
}

View File

@@ -9,6 +9,7 @@ import java.util.Map;
import org.lucares.pdb.api.StringCompressor; import org.lucares.pdb.api.StringCompressor;
import org.lucares.pdb.api.Tag; import org.lucares.pdb.api.Tag;
import org.lucares.pdb.api.Tags; import org.lucares.pdb.api.Tags;
import org.lucares.pdb.api.TagsBuilder;
import org.lucares.pdb.api.UniqueStringIntegerPairs; import org.lucares.pdb.api.UniqueStringIntegerPairs;
public class MemoryScale { public class MemoryScale {
@@ -70,7 +71,6 @@ public class MemoryScale {
default: default:
return null; return null;
} }
} }
private static Object createTag() { private static Object createTag() {
@@ -90,13 +90,14 @@ public class MemoryScale {
} }
private static Object createTags6() { private static Object createTags6() {
Tags result = Tags.create("k1", "v1"); TagsBuilder result = TagsBuilder.create();
result = result.copyAdd("k2", "v2"); result = result.add("k1", "v1");
result = result.copyAdd("k3", "v3"); result = result.add("k2", "v2");
result = result.copyAdd("k4", "v4"); result = result.add("k3", "v3");
result = result.copyAdd("k5", "v5"); result = result.add("k4", "v4");
result = result.copyAdd("k6", "v6"); result = result.add("k5", "v5");
return result; result = result.add("k6", "v6");
return result.build();
} }
private static Object createPathAsUtf8(final String string) { private static Object createPathAsUtf8(final String string) {

View File

@@ -24,6 +24,7 @@ import javax.annotation.PreDestroy;
import org.lucares.pdb.api.Entry; import org.lucares.pdb.api.Entry;
import org.lucares.pdb.api.Tags; import org.lucares.pdb.api.Tags;
import org.lucares.pdb.api.TagsBuilder;
import org.lucares.performance.db.BlockingQueueIterator; import org.lucares.performance.db.BlockingQueueIterator;
import org.lucares.performance.db.PerformanceDb; import org.lucares.performance.db.PerformanceDb;
import org.lucares.recommind.logs.Config; import org.lucares.recommind.logs.Config;
@@ -124,7 +125,7 @@ public class TcpIngestor implements Ingestor, AutoCloseable, DisposableBean {
} }
private Tags createTags(final Map<String, Object> map) { private Tags createTags(final Map<String, Object> map) {
Tags tags = Tags.create(); final TagsBuilder tags = TagsBuilder.create();
for (final java.util.Map.Entry<String, Object> e : map.entrySet()) { for (final java.util.Map.Entry<String, Object> e : map.entrySet()) {
final String key = e.getKey(); final String key = e.getKey();
@@ -139,11 +140,15 @@ public class TcpIngestor implements Ingestor, AutoCloseable, DisposableBean {
// ignore: we only support key/value tags // ignore: we only support key/value tags
break; break;
default: default:
tags = tags.copyAddIfNotNull(key, String.valueOf(value)); if (value instanceof String) {
tags.add(key, (String) value);
} else {
tags.add(key, String.valueOf(value));
}
break; break;
} }
} }
return tags; return tags.build();
} }
private OffsetDateTime getDate(final Map<String, Object> map) { private OffsetDateTime getDate(final Map<String, Object> map) {

View File

@@ -63,7 +63,7 @@ public class PerformanceDb implements AutoCloseable {
public void put(final BlockingIterator<Entry> entries) throws WriteException { public void put(final BlockingIterator<Entry> entries) throws WriteException {
final Duration timeBetweenSyncs = Duration.ofSeconds(10); final Duration timeBetweenSyncs = Duration.ofSeconds(1);
long count = 0; long count = 0;
long insertionsSinceLastSync = 0; long insertionsSinceLastSync = 0;