From c94f5b99de4f9f7f686d277c3ab06189a333b125 Mon Sep 17 00:00:00 2001 From: Armin Braun Date: Thu, 10 Sep 2020 20:50:33 +0200 Subject: [PATCH] Speed up Version Checks (#62216) The `fromId` method would show up in profiling and JIT analysis as not-inlinable because it's too large in the contexts it's used in in many cases and was consuming a surprising amount of cycles for computing the min compat versions. -> extract cold path from `fromId` to make JIT happy and cache minimumg compatible versions to fields. --- .../main/java/org/elasticsearch/Version.java | 83 ++++++++++++------- 1 file changed, 55 insertions(+), 28 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/Version.java b/server/src/main/java/org/elasticsearch/Version.java index 98f63cef8682e..60fc6eedf7ad8 100644 --- a/server/src/main/java/org/elasticsearch/Version.java +++ b/server/src/main/java/org/elasticsearch/Version.java @@ -121,6 +121,7 @@ public class Version implements Comparable, ToXContentFragment { assert CURRENT.luceneVersion.equals(org.apache.lucene.util.Version.LATEST) : "Version must be upgraded to [" + org.apache.lucene.util.Version.LATEST + "] is still set to [" + CURRENT.luceneVersion + "]"; + builder.put(V_EMPTY_ID, V_EMPTY); idToVersion = builder.build(); } @@ -129,36 +130,36 @@ public static Version readVersion(StreamInput in) throws IOException { } public static Version fromId(int id) { - if (idToVersion.containsKey(id)) { - return idToVersion.get(id); + final Version known = idToVersion.get(id); + if (known != null) { + return known; } - switch (id) { - case V_EMPTY_ID: - return V_EMPTY; - default: - // We need at least the major of the Lucene version to be correct. - // Our best guess is to use the same Lucene version as the previous - // version in the list, assuming that it didn't change. - List versions = DeclaredVersionsHolder.DECLARED_VERSIONS; - Version tmp = new Version(id, org.apache.lucene.util.Version.LATEST); - int index = Collections.binarySearch(versions, tmp); - if (index < 0) { - index = -2 - index; - } else { - assert false : "Version [" + tmp + "] is declared but absent from the switch statement in Version#fromId"; - } - final org.apache.lucene.util.Version luceneVersion; - if (index == -1) { - // this version is older than any supported version, so we - // assume it is the previous major to the oldest Lucene version - // that we know about - luceneVersion = org.apache.lucene.util.Version.fromBits( - versions.get(0).luceneVersion.major - 1, 0, 0); - } else { - luceneVersion = versions.get(index).luceneVersion; - } - return new Version(id, luceneVersion); + return fromIdSlow(id); + } + + private static Version fromIdSlow(int id) { + // We need at least the major of the Lucene version to be correct. + // Our best guess is to use the same Lucene version as the previous + // version in the list, assuming that it didn't change. + List versions = DeclaredVersionsHolder.DECLARED_VERSIONS; + Version tmp = new Version(id, org.apache.lucene.util.Version.LATEST); + int index = Collections.binarySearch(versions, tmp); + if (index < 0) { + index = -2 - index; + } else { + assert false : "Version [" + tmp + "] is declared but absent from the switch statement in Version#fromId"; + } + final org.apache.lucene.util.Version luceneVersion; + if (index == -1) { + // this version is older than any supported version, so we + // assume it is the previous major to the oldest Lucene version + // that we know about + luceneVersion = org.apache.lucene.util.Version.fromBits( + versions.get(0).luceneVersion.major - 1, 0, 0); + } else { + luceneVersion = versions.get(index).luceneVersion; } + return new Version(id, luceneVersion); } /** @@ -285,6 +286,14 @@ private static class DeclaredVersionsHolder { static final List DECLARED_VERSIONS = Collections.unmodifiableList(getDeclaredVersions(Version.class)); } + // lazy initialized because we don't yet have the declared versions ready when instantiating the cached Version + // instances + private Version minCompatVersion; + + // lazy initialized because we don't yet have the declared versions ready when instantiating the cached Version + // instances + private Version minIndexCompatVersion; + /** * Returns the minimum compatible version based on the current * version. Ie a node needs to have at least the return version in order @@ -293,6 +302,15 @@ private static class DeclaredVersionsHolder { * is a beta or RC release then the version itself is returned. */ public Version minimumCompatibilityVersion() { + Version res = minCompatVersion; + if (res == null) { + res = computeMinCompatVersion(); + minCompatVersion = res; + } + return res; + } + + private Version computeMinCompatVersion() { if (major == 6) { // force the minimum compatibility for version 6 to 5.6 since we don't reference version 5 anymore return Version.fromId(5060099); @@ -324,6 +342,15 @@ public Version minimumCompatibilityVersion() { * code that is used to read / write file formats like transaction logs, cluster state, and index metadata. */ public Version minimumIndexCompatibilityVersion() { + Version res = minIndexCompatVersion; + if (res == null) { + res = computeMinIndexCompatVersion(); + minIndexCompatVersion = res; + } + return res; + } + + private Version computeMinIndexCompatVersion() { final int bwcMajor; if (major == 5) { bwcMajor = 2; // we jumped from 2 to 5