Skip to content

Commit 976c9f9

Browse files
Much faster indices lookup on metadata (#123749)
We mostly need the map for lookups in very tight loops but also rarely rely on the sortedness of this thing. Getting the best of both worlds at surprisingly only a ~10% increase in build time and ~25% increase in the heap consumption of this structure provides a massive speedup to e.g. search or field_caps over large numbers of indices thanks to the up to an order of magnitude cheaper lookups in index name resolution and security (as well as speedups in other areas).
1 parent 7731316 commit 976c9f9

File tree

1 file changed

+117
-2
lines changed

1 file changed

+117
-2
lines changed

server/src/main/java/org/elasticsearch/cluster/metadata/ProjectMetadata.java

Lines changed: 117 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import java.io.IOException;
4747
import java.util.ArrayList;
4848
import java.util.Arrays;
49+
import java.util.Collection;
4950
import java.util.Collections;
5051
import java.util.Comparator;
5152
import java.util.HashMap;
@@ -1761,15 +1762,129 @@ static SortedMap<String, IndexAbstraction> buildIndicesLookup(
17611762
if (indices.isEmpty()) {
17621763
return Collections.emptySortedMap();
17631764
}
1764-
SortedMap<String, IndexAbstraction> indicesLookup = new TreeMap<>();
1765+
Map<String, IndexAbstraction> indicesLookup = new HashMap<>();
17651766
Map<String, DataStream> indexToDataStreamLookup = new HashMap<>();
17661767
collectDataStreams(dataStreamMetadata, indicesLookup, indexToDataStreamLookup);
17671768

17681769
Map<String, List<IndexMetadata>> aliasToIndices = new HashMap<>();
17691770
collectIndices(indices, indexToDataStreamLookup, indicesLookup, aliasToIndices);
17701771
collectAliases(aliasToIndices, indicesLookup);
17711772

1772-
return Collections.unmodifiableSortedMap(indicesLookup);
1773+
// We do a ton of lookups on this map but also need its sorted properties at times.
1774+
// Using this hybrid of a sorted and a hash-map trades some heap overhead relative to just using a TreeMap
1775+
// for much faster O(1) lookups in large clusters.
1776+
return new SortedMap<>() {
1777+
1778+
private final SortedMap<String, IndexAbstraction> sortedMap = Collections.unmodifiableSortedMap(
1779+
new TreeMap<>(indicesLookup)
1780+
);
1781+
1782+
@Override
1783+
public Comparator<? super String> comparator() {
1784+
return sortedMap.comparator();
1785+
}
1786+
1787+
@Override
1788+
public SortedMap<String, IndexAbstraction> subMap(String fromKey, String toKey) {
1789+
return sortedMap.subMap(fromKey, toKey);
1790+
}
1791+
1792+
@Override
1793+
public SortedMap<String, IndexAbstraction> headMap(String toKey) {
1794+
return sortedMap.headMap(toKey);
1795+
}
1796+
1797+
@Override
1798+
public SortedMap<String, IndexAbstraction> tailMap(String fromKey) {
1799+
return sortedMap.tailMap(fromKey);
1800+
}
1801+
1802+
@Override
1803+
public String firstKey() {
1804+
return sortedMap.firstKey();
1805+
}
1806+
1807+
@Override
1808+
public String lastKey() {
1809+
return sortedMap.lastKey();
1810+
}
1811+
1812+
@Override
1813+
public Set<String> keySet() {
1814+
return sortedMap.keySet();
1815+
}
1816+
1817+
@Override
1818+
public Collection<IndexAbstraction> values() {
1819+
return sortedMap.values();
1820+
}
1821+
1822+
@Override
1823+
public Set<Entry<String, IndexAbstraction>> entrySet() {
1824+
return sortedMap.entrySet();
1825+
}
1826+
1827+
@Override
1828+
public int size() {
1829+
return indicesLookup.size();
1830+
}
1831+
1832+
@Override
1833+
public boolean isEmpty() {
1834+
return indicesLookup.isEmpty();
1835+
}
1836+
1837+
@Override
1838+
public boolean containsKey(Object key) {
1839+
return indicesLookup.containsKey(key);
1840+
}
1841+
1842+
@Override
1843+
public boolean containsValue(Object value) {
1844+
return indicesLookup.containsValue(value);
1845+
}
1846+
1847+
@Override
1848+
public IndexAbstraction get(Object key) {
1849+
return indicesLookup.get(key);
1850+
}
1851+
1852+
@Override
1853+
public IndexAbstraction put(String key, IndexAbstraction value) {
1854+
throw new UnsupportedOperationException();
1855+
}
1856+
1857+
@Override
1858+
public IndexAbstraction remove(Object key) {
1859+
throw new UnsupportedOperationException();
1860+
}
1861+
1862+
@Override
1863+
public void putAll(Map<? extends String, ? extends IndexAbstraction> m) {
1864+
throw new UnsupportedOperationException();
1865+
}
1866+
1867+
@Override
1868+
public void clear() {
1869+
throw new UnsupportedOperationException();
1870+
}
1871+
1872+
@Override
1873+
public boolean equals(Object obj) {
1874+
if (obj == null) {
1875+
return false;
1876+
}
1877+
if (getClass() != obj.getClass()) {
1878+
return false;
1879+
}
1880+
return indicesLookup.equals(obj);
1881+
}
1882+
1883+
@Override
1884+
public int hashCode() {
1885+
return indicesLookup.hashCode();
1886+
}
1887+
};
17731888
}
17741889

17751890
private static void collectAliases(Map<String, List<IndexMetadata>> aliasToIndices, Map<String, IndexAbstraction> indicesLookup) {

0 commit comments

Comments
 (0)