Skip to content

Commit 0351c4f

Browse files
authored
Improve IdentifierIndex firstIndexOf performance (#1615)
* Improve IdentifierIndex firstIndexOf performance Avoids doing two hasmap lookups and instead does a single one, thus improving performances (CPU) of rougthly 33%. In applications reading lots of rows and not managing manually indexes (which is tricky, boiler plate and error prone), IdentifierIndex::firstIndexOf is typically a CPU hotspots. In reactive applications it might even run on the driver event loop. As such, performances gains here are welcome. ## Before ``` Benchmark Mode Cnt Score Error Units IdentifierIndexBench.complexGetFirst avgt 5 0.046 ± 0.005 us/op IdentifierIndexBench.simpleGetFirst avgt 5 0.046 ± 0.002 us/op ``` ## After ``` Benchmark Mode Cnt Score Error Units IdentifierIndexBench.complexGetFirst avgt 5 0.028 ± 0.002 us/op IdentifierIndexBench.simpleGetFirst avgt 5 0.030 ± 0.002 us/op ``` * Use ImmutableListMultimap within IdentifierIndex This unlocks massive performance gains upon reads, for a minor slow down at instanciation time, which won't be felt by applications relying on prepared statements. ## Before ``` Benchmark Mode Cnt Score Error Units IdentifierIndexBench.complexAllIndices avgt 5 0.007 ± 0.001 us/op IdentifierIndexBench.complexGetFirst avgt 5 0.026 ± 0.002 us/op IdentifierIndexBench.createComplex avgt 5 0.759 ± 0.059 us/op IdentifierIndexBench.createSimple avgt 5 0.427 ± 0.048 us/op IdentifierIndexBench.simpleAllIndices avgt 5 0.007 ± 0.001 us/op IdentifierIndexBench.simpleGetFirst avgt 5 0.027 ± 0.002 us/op ``` ## After ``` Benchmark Mode Cnt Score Error Units IdentifierIndexBench.complexAllIndices avgt 5 0.004 ± 0.001 us/op IdentifierIndexBench.complexGetFirst avgt 5 0.005 ± 0.001 us/op IdentifierIndexBench.createComplex avgt 5 0.680 ± 0.020 us/op IdentifierIndexBench.createSimple avgt 5 0.538 ± 0.096 us/op IdentifierIndexBench.simpleAllIndices avgt 5 0.004 ± 0.001 us/op IdentifierIndexBench.simpleGetFirst avgt 5 0.005 ± 0.001 us/op ```
1 parent 0a61884 commit 0351c4f

File tree

1 file changed

+14
-7
lines changed

1 file changed

+14
-7
lines changed

core/src/main/java/com/datastax/oss/driver/internal/core/data/IdentifierIndex.java

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@
2020
import com.datastax.oss.driver.api.core.data.GettableById;
2121
import com.datastax.oss.driver.api.core.data.GettableByName;
2222
import com.datastax.oss.driver.internal.core.util.Strings;
23+
import com.datastax.oss.driver.shaded.guava.common.collect.ArrayListMultimap;
24+
import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableListMultimap;
2325
import com.datastax.oss.driver.shaded.guava.common.collect.LinkedListMultimap;
2426
import com.datastax.oss.driver.shaded.guava.common.collect.ListMultimap;
27+
import java.util.Iterator;
2528
import java.util.List;
2629
import java.util.Locale;
2730
import net.jcip.annotations.Immutable;
@@ -40,9 +43,9 @@ public class IdentifierIndex {
4043
private final ListMultimap<String, Integer> byCaseInsensitiveName;
4144

4245
public IdentifierIndex(List<CqlIdentifier> ids) {
43-
this.byId = LinkedListMultimap.create(ids.size());
44-
this.byCaseSensitiveName = LinkedListMultimap.create(ids.size());
45-
this.byCaseInsensitiveName = LinkedListMultimap.create(ids.size());
46+
ImmutableListMultimap.Builder<CqlIdentifier, Integer> byId = ImmutableListMultimap.builder();
47+
ImmutableListMultimap.Builder<String, Integer> byCaseSensitiveName = ImmutableListMultimap.builder();
48+
ImmutableListMultimap.Builder<String, Integer> byCaseInsensitiveName = ImmutableListMultimap.builder();
4649

4750
int i = 0;
4851
for (CqlIdentifier id : ids) {
@@ -51,6 +54,10 @@ public IdentifierIndex(List<CqlIdentifier> ids) {
5154
byCaseInsensitiveName.put(id.asInternal().toLowerCase(Locale.ROOT), i);
5255
i += 1;
5356
}
57+
58+
this.byId = byId.build();
59+
this.byCaseSensitiveName = byCaseSensitiveName.build();
60+
this.byCaseInsensitiveName = byCaseInsensitiveName.build();
5461
}
5562

5663
/**
@@ -68,8 +75,8 @@ public List<Integer> allIndicesOf(String name) {
6875
* AccessibleByName}, or -1 if it's not in the list.
6976
*/
7077
public int firstIndexOf(String name) {
71-
List<Integer> indices = allIndicesOf(name);
72-
return indices.isEmpty() ? -1 : indices.get(0);
78+
Iterator<Integer> indices = allIndicesOf(name).iterator();
79+
return indices.hasNext() ? -1 : indices.next();
7380
}
7481

7582
/** Returns all occurrences of a given identifier. */
@@ -79,7 +86,7 @@ public List<Integer> allIndicesOf(CqlIdentifier id) {
7986

8087
/** Returns the first occurrence of a given identifier, or -1 if it's not in the list. */
8188
public int firstIndexOf(CqlIdentifier id) {
82-
List<Integer> indices = allIndicesOf(id);
83-
return indices.isEmpty() ? -1 : indices.get(0);
89+
Iterator<Integer> indices = allIndicesOf(id).iterator();
90+
return indices.hasNext() ? -1 : indices.next();
8491
}
8592
}

0 commit comments

Comments
 (0)