Browse Source

Add TransportVersion to represent wire transport version separately to node version (#92869)

This change doesn't actually modify any behaviour, it just adds the initial set of classes needed for further work in this area.

For the moment, each TransportVersion maps one-to-one onto each Version. When all transport code is migrated over to TransportVersion, we will then introduce separate transport version numbers.

Co-authored-by: Przemyslaw Gomulka <przemyslaw.gomulka@elastic.co>
Simon Cooper 2 years ago
parent
commit
6ebd74cdf9

+ 295 - 0
server/src/main/java/org/elasticsearch/TransportVersion.java

@@ -0,0 +1,295 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+package org.elasticsearch;
+
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.common.io.stream.StreamOutput;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.NavigableSet;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * Represents the version of the wire protocol used to communicate between ES nodes.
+ * <p>
+ * Prior to 8.7.0, the node {@link Version} was used everywhere. This class separates the wire protocol version
+ * from the running node version. Each node version has a reference to a specific transport version used by that node.
+ * <p>
+ * Each transport version constant has an id number, which for versions prior to 8.7.0 is the same as the node version
+ * for backwards compatibility.
+ * There is also a unique id string. This is not actually used in the protocol, but is there to ensure each protocol version
+ * is only added to the source file once. This string needs to be unique (here, a UUID, but can be any other unique nonempty string).
+ * If two concurrent PRs added the same protocol version, the unique string causes a git conflict, ensuring the second PR to be merged
+ * must be updated with the next free version. Without the unique id string, git will happily merge the two versions together,
+ * causing problems when you try to upgrade between those two PRs.
+ * <p>
+ * When adding new transport versions, it is recommended to leave a gap in the id number (say, 100)
+ * to leave space for any intermediate fixes that may be needed in the future.
+ * <p>
+ * The earliest compatible version is hardcoded at {@link #MINIMUM_COMPATIBLE}. Previously, this was dynamically calculated
+ * from the major/minor versions of {@link Version}, but {@code TransportVersion} does not have separate major/minor version numbers.
+ * So the minimum compatible version needs to be hard-coded as the transport version of the minimum compatible node version.
+ * That variable should be updated appropriately whenever we do a major version release.
+ */
+public class TransportVersion implements Comparable<TransportVersion> {
+    public static final TransportVersion ZERO = new TransportVersion(0, "00000000-0000-0000-0000-000000000000");
+    /*
+     * Legacy transport versions that match the node version
+     */
+    public static final TransportVersion V_7_0_0 = new TransportVersion(7_00_00_99, "7505fd05-d982-43ce-a63f-ff4c6c8bdeec");
+    public static final TransportVersion V_7_0_1 = new TransportVersion(7_00_01_99, "ae772780-e6f9-46a1-b0a0-20ed0cae37f7");
+    public static final TransportVersion V_7_1_0 = new TransportVersion(7_01_00_99, "fd09007c-1c54-450a-af99-9f941e1a53c2");
+    public static final TransportVersion V_7_1_1 = new TransportVersion(7_01_01_99, "f7ddb16c-3495-42ef-8d54-1461570ca68c");
+    public static final TransportVersion V_7_2_0 = new TransportVersion(7_02_00_99, "b74dbc52-e727-472c-af21-2156482e8796");
+    public static final TransportVersion V_7_2_1 = new TransportVersion(7_02_01_99, "a3217b94-f436-4aab-a020-162c83ba18f2");
+    public static final TransportVersion V_7_3_0 = new TransportVersion(7_03_00_99, "4f04e4c9-c5aa-49e4-8b99-abeb4e284a5a");
+    public static final TransportVersion V_7_3_1 = new TransportVersion(7_03_01_99, "532b9bc9-e11f-48a2-b997-67ca68ffb354");
+    public static final TransportVersion V_7_3_2 = new TransportVersion(7_03_02_99, "60da3953-8415-4d4f-a18d-853c3e68ebd6");
+    public static final TransportVersion V_7_4_0 = new TransportVersion(7_04_00_99, "ec7e58aa-55b4-4064-a9dd-fd723a2ba7a8");
+    public static final TransportVersion V_7_4_1 = new TransportVersion(7_04_01_99, "a316c26d-8e6a-4608-b1ec-062331552b98");
+    public static final TransportVersion V_7_4_2 = new TransportVersion(7_04_02_99, "031a77e1-3640-4c8a-80cf-28ded96bab48");
+    public static final TransportVersion V_7_5_0 = new TransportVersion(7_05_00_99, "cc6e14dc-9dc7-4b74-8e15-1f99a6cfbe03");
+    public static final TransportVersion V_7_5_1 = new TransportVersion(7_05_01_99, "9d12be44-16dc-44a8-a89a-45c9174ea596");
+    public static final TransportVersion V_7_5_2 = new TransportVersion(7_05_02_99, "484ed9de-7f5b-4e6b-a79a-0cb5e7570093");
+    public static final TransportVersion V_7_6_0 = new TransportVersion(7_06_00_99, "4637b8ae-f3df-43ae-a065-ad4c29f3373a");
+    public static final TransportVersion V_7_6_1 = new TransportVersion(7_06_01_99, "fe5b9f95-a311-4a92-943b-30ec256a331c");
+    public static final TransportVersion V_7_6_2 = new TransportVersion(7_06_02_99, "5396cb30-d91c-4789-85e8-77efd552c785");
+    public static final TransportVersion V_7_7_0 = new TransportVersion(7_07_00_99, "7bb73c48-ddb8-4437-b184-30371c35dd4b");
+    public static final TransportVersion V_7_7_1 = new TransportVersion(7_07_01_99, "85507b0f-0fca-4daf-a80b-451fe75e04a0");
+    public static final TransportVersion V_7_8_0 = new TransportVersion(7_08_00_99, "c3cc74af-d15e-494b-a907-6ad6dd2f4660");
+    public static final TransportVersion V_7_8_1 = new TransportVersion(7_08_01_99, "7acb9f6e-32f2-45ce-b87d-ca1f165b8e7a");
+    public static final TransportVersion V_7_9_0 = new TransportVersion(7_09_00_99, "9388fe76-192a-4053-b51c-d2a7b8eae545");
+    public static final TransportVersion V_7_9_1 = new TransportVersion(7_09_01_99, "30fa10fc-df6b-4435-bd9e-acdb9ae1b268");
+    public static final TransportVersion V_7_9_2 = new TransportVersion(7_09_02_99, "b58bb181-cecc-464e-b955-f6c1c1e7b4d0");
+    public static final TransportVersion V_7_9_3 = new TransportVersion(7_09_03_99, "4406926c-e2b6-4b9a-a72a-1bee8357ad3e");
+    public static final TransportVersion V_7_10_0 = new TransportVersion(7_10_00_99, "4efca195-38e4-4f74-b877-c26fb2a40733");
+    public static final TransportVersion V_7_10_1 = new TransportVersion(7_10_01_99, "0070260c-aa0b-4fc2-9c87-5cd5f23b005f");
+    public static final TransportVersion V_7_10_2 = new TransportVersion(7_10_02_99, "b369e2ed-261c-4b2f-8b42-0f0ba0549f8c");
+    public static final TransportVersion V_7_11_0 = new TransportVersion(7_11_00_99, "3b43bcbc-1c5e-4cc2-a3b4-8ac8b64239e8");
+    public static final TransportVersion V_7_11_1 = new TransportVersion(7_11_01_99, "2f75d13c-adde-4762-a46e-def8acce62b7");
+    public static final TransportVersion V_7_11_2 = new TransportVersion(7_11_02_99, "2c852a4b-236d-4e8b-9373-336c9b52685a");
+    public static final TransportVersion V_7_12_0 = new TransportVersion(7_12_00_99, "3be9ff6f-2d9f-4fc2-ba91-394dd5ebcf33");
+    public static final TransportVersion V_7_12_1 = new TransportVersion(7_12_01_99, "ee4fdfac-2039-4b00-b42d-579cbde7120c");
+    public static final TransportVersion V_7_13_0 = new TransportVersion(7_13_00_99, "e1fe494a-7c66-4571-8f8f-1d7e6d8df1b3");
+    public static final TransportVersion V_7_13_1 = new TransportVersion(7_13_01_99, "66bc8d82-36da-4d54-b22d-aca691dc3d70");
+    public static final TransportVersion V_7_13_2 = new TransportVersion(7_13_02_99, "2a6fc74c-4c44-4264-a619-37437cd2c5a0");
+    public static final TransportVersion V_7_13_3 = new TransportVersion(7_13_03_99, "a31592f5-f8d2-490c-a02e-da9501823d8d");
+    public static final TransportVersion V_7_13_4 = new TransportVersion(7_13_04_99, "3143240d-1831-4186-8a19-963336c4cea0");
+    public static final TransportVersion V_7_14_0 = new TransportVersion(7_14_00_99, "8cf0954c-b085-467f-b20b-3cb4b2e69e3e");
+    public static final TransportVersion V_7_14_1 = new TransportVersion(7_14_01_99, "3dbb62c3-cf73-4c76-8d5a-4ca70afe2c70");
+    public static final TransportVersion V_7_14_2 = new TransportVersion(7_14_02_99, "7943ae20-df60-45e5-97ba-82fc0dfc8b89");
+    public static final TransportVersion V_7_15_0 = new TransportVersion(7_15_00_99, "2273ac0e-00bb-4024-9e2e-ab78981623c6");
+    public static final TransportVersion V_7_15_1 = new TransportVersion(7_15_01_99, "a8c3503d-3452-45cf-b385-e855e16547fe");
+    public static final TransportVersion V_7_15_2 = new TransportVersion(7_15_02_99, "fbb8ad69-02e2-4c90-b2e4-23947107f8b4");
+    public static final TransportVersion V_7_16_0 = new TransportVersion(7_16_00_99, "59abadd2-25db-4547-a991-c92306a3934e");
+    public static final TransportVersion V_7_16_1 = new TransportVersion(7_16_01_99, "4ace6b6b-8bba-427f-8755-9e3b40092138");
+    public static final TransportVersion V_7_16_2 = new TransportVersion(7_16_02_99, "785567b9-b320-48ef-b538-1753228904cd");
+    public static final TransportVersion V_7_16_3 = new TransportVersion(7_16_03_99, "facf5ae7-3d4e-479c-9142-72529b784e30");
+    public static final TransportVersion V_7_17_0 = new TransportVersion(7_17_00_99, "322efe93-4c73-4e15-9274-bb76836c8fa8");
+    public static final TransportVersion V_7_17_1 = new TransportVersion(7_17_01_99, "51c72842-7974-4669-ad25-bf13ba307307");
+    public static final TransportVersion V_7_17_2 = new TransportVersion(7_17_02_99, "82bea8d0-bfea-47c2-b7d3-217d8feb67e3");
+    public static final TransportVersion V_7_17_3 = new TransportVersion(7_17_03_99, "a909c2f4-5cb8-46bf-af0f-cd18d1b7e9d2");
+    public static final TransportVersion V_7_17_4 = new TransportVersion(7_17_04_99, "5076e164-18a4-4373-8be7-15f1843c46db");
+    public static final TransportVersion V_7_17_5 = new TransportVersion(7_17_05_99, "da7e3509-7f61-4dd2-8d23-a61f628a62f6");
+    public static final TransportVersion V_7_17_6 = new TransportVersion(7_17_06_99, "a47ecf02-e457-474f-887d-ee15a7ebd969");
+    public static final TransportVersion V_7_17_7 = new TransportVersion(7_17_07_99, "108ba576-bb28-42f4-bcbf-845a0ce52560");
+    public static final TransportVersion V_7_17_8 = new TransportVersion(7_17_08_99, "82a3e70d-cf0e-4efb-ad16-6077ab9fe19f");
+    public static final TransportVersion V_7_17_9 = new TransportVersion(7_17_09_99, "afd50dda-735f-4eae-9309-3218ffec1b2d");
+    public static final TransportVersion V_8_0_0 = new TransportVersion(8_00_00_99, "c7d2372c-9f01-4a79-8b11-227d862dfe4f");
+    public static final TransportVersion V_8_0_1 = new TransportVersion(8_00_01_99, "56e044c3-37e5-4f7e-bd38-f493927354ac");
+    public static final TransportVersion V_8_1_0 = new TransportVersion(8_01_00_99, "3dc49dce-9cef-492a-ac8d-3cc79f6b4280");
+    public static final TransportVersion V_8_1_1 = new TransportVersion(8_01_01_99, "40cf32e5-17b0-4187-9de1-022cdea69db9");
+    public static final TransportVersion V_8_1_2 = new TransportVersion(8_01_02_99, "54aa6394-08f3-4db7-b82e-314ae4b5b562");
+    public static final TransportVersion V_8_1_3 = new TransportVersion(8_01_03_99, "9772b54b-1e14-485f-92e8-8847b3a3d569");
+    public static final TransportVersion V_8_2_0 = new TransportVersion(8_02_00_99, "8ce6d555-202e-47db-ab7d-ade9dda1b7e8");
+    public static final TransportVersion V_8_2_1 = new TransportVersion(8_02_01_99, "ffbb67e8-cc33-4b02-a995-b461d9ee36c8");
+    public static final TransportVersion V_8_2_2 = new TransportVersion(8_02_02_99, "2499ee77-187d-4e10-8366-8e60d5f03676");
+    public static final TransportVersion V_8_2_3 = new TransportVersion(8_02_03_99, "046aae43-3090-4ece-8c27-8d489f097548");
+    public static final TransportVersion V_8_3_0 = new TransportVersion(8_03_00_99, "559ddb66-d857-4208-bed5-a995ccf478ea");
+    public static final TransportVersion V_8_3_1 = new TransportVersion(8_03_01_99, "31f9b136-dbbe-4fa1-b811-d6afa2a1b472");
+    public static final TransportVersion V_8_3_2 = new TransportVersion(8_03_02_99, "f6e9cd4c-2a71-4f9b-80d4-7ba97ebd18b2");
+    public static final TransportVersion V_8_3_3 = new TransportVersion(8_03_03_99, "a784de3e-533e-4844-8728-c55c6932dd8e");
+    public static final TransportVersion V_8_4_0 = new TransportVersion(8_04_00_99, "c0d12906-aa5b-45d4-94c7-cbcf4d9818ca");
+    public static final TransportVersion V_8_4_1 = new TransportVersion(8_04_01_99, "9a915f76-f259-4361-b53d-3f19c7797fd8");
+    public static final TransportVersion V_8_4_2 = new TransportVersion(8_04_02_99, "87c5b7b2-0f57-4172-8a81-b9f9a0198525");
+    public static final TransportVersion V_8_4_3 = new TransportVersion(8_04_03_99, "327cb1a0-9b5d-4be9-8033-285c2549f770");
+    public static final TransportVersion V_8_5_0 = new TransportVersion(8_05_00_99, "be3d7f23-7240-4904-9d7f-e25a0f766eca");
+    public static final TransportVersion V_8_5_1 = new TransportVersion(8_05_01_99, "d349d202-f01c-4dbb-85dd-947fb4267c99");
+    public static final TransportVersion V_8_5_2 = new TransportVersion(8_05_02_99, "b68b1331-fd64-44d9-9e71-f6796ec2024c");
+    public static final TransportVersion V_8_5_3 = new TransportVersion(8_05_03_99, "9ca3c835-e3b7-4622-a08e-d51e42403b06");
+    public static final TransportVersion V_8_5_4 = new TransportVersion(8_05_04_99, "97ee525c-555d-45ca-83dc-59cd592c8e86");
+    public static final TransportVersion V_8_6_0 = new TransportVersion(8_06_00_99, "e209c5ed-3488-4415-b561-33492ca3b789");
+    public static final TransportVersion V_8_6_1 = new TransportVersion(8_06_01_99, "9f113acb-1b21-4fda-bef9-2a3e669b5c7b");
+    public static final TransportVersion V_8_7_0 = new TransportVersion(8_07_00_99, "f1ee7a85-4fa6-43f5-8679-33e2b750448b");
+    /*
+     * READ THE JAVADOC ABOVE BEFORE ADDING NEW TRANSPORT VERSIONS
+     * Detached transport versions added below here. Starts at ES major version 10 equivalent.
+     */
+    // NOTE: DO NOT UNCOMMENT until all transport code uses TransportVersion
+    // public static final TransportVersion V_10_000_000 = new TransportVersion(10_000_000, "dc3cbf06-3ed5-4e1b-9978-ee1d04d235bc");
+    /*
+     * When adding a new transport version, ensure there is a gap (say, 100) between versions
+     * This is to make it possible to add intermediate versions for any bug fixes that may be required.
+     *
+     * When adding versions for patch fixes, add numbers in the middle of the gap. This is to ensure there is always some space
+     * for patch fixes between any two versions.
+     */
+
+    /** Reference to the current transport version */
+    public static final TransportVersion CURRENT = V_8_7_0;
+
+    /** Reference to the earliest compatible transport version to this version of the codebase */
+    // TODO: can we programmatically calculate or check this? Don't want to introduce circular ref between Version/TransportVersion
+    public static final TransportVersion MINIMUM_COMPATIBLE = V_7_17_0;
+
+    static Map<Integer, TransportVersion> getAllVersionIds(Class<?> cls) {
+        Map<Integer, TransportVersion> builder = new HashMap<>();
+        Map<String, TransportVersion> uniqueIds = new HashMap<>();
+
+        Set<String> ignore = Set.of("ZERO", "CURRENT", "MINIMUM_COMPATIBLE");
+        for (Field declaredField : cls.getFields()) {
+            if (declaredField.getType().equals(TransportVersion.class)) {
+                String fieldName = declaredField.getName();
+                if (ignore.contains(fieldName)) {
+                    continue;
+                }
+                try {
+                    TransportVersion version = (TransportVersion) declaredField.get(null);
+
+                    TransportVersion maybePrevious = builder.put(version.id, version);
+                    assert maybePrevious == null
+                        : "expected [" + version.id + "] to be uniquely mapped but saw [" + maybePrevious + "] and [" + version + "]";
+
+                    TransportVersion sameUniqueId = uniqueIds.put(version.uniqueId, version);
+                    assert sameUniqueId == null
+                        : "Versions "
+                            + version
+                            + " and "
+                            + sameUniqueId
+                            + " have the same unique id. Each TransportVersion should have a different unique id";
+                } catch (IllegalAccessException e) {
+                    assert false : "Version field [" + fieldName + "] should be public";
+                }
+            }
+        }
+
+        return Map.copyOf(builder);
+    }
+
+    private static final Map<Integer, TransportVersion> VERSION_IDS;
+
+    private static final NavigableSet<TransportVersion> ALL_VERSIONS;
+
+    static {
+        VERSION_IDS = getAllVersionIds(TransportVersion.class);
+        ALL_VERSIONS = Collections.unmodifiableNavigableSet(new TreeSet<>(VERSION_IDS.values()));
+    }
+
+    public static TransportVersion readVersion(StreamInput in) throws IOException {
+        return fromId(in.readVInt());
+    }
+
+    public static TransportVersion fromId(int id) {
+        TransportVersion known = VERSION_IDS.get(id);
+        if (known != null) {
+            return known;
+        }
+        // this is a version we don't otherwise know about - just create a placeholder
+        return new TransportVersion(id, "<unknown>");
+    }
+
+    public static void writeVersion(TransportVersion version, StreamOutput out) throws IOException {
+        out.writeVInt(version.id);
+    }
+
+    /**
+     * Returns the minimum version of {@code version1} and {@code version2}
+     */
+    public static TransportVersion min(TransportVersion version1, TransportVersion version2) {
+        return version1.id < version2.id ? version1 : version2;
+    }
+
+    /**
+     * Returns the maximum version of {@code version1} and {@code version2}
+     */
+    public static TransportVersion max(TransportVersion version1, TransportVersion version2) {
+        return version1.id > version2.id ? version1 : version2;
+    }
+
+    /**
+     * returns a sorted set of all transport version constants
+     */
+    public static NavigableSet<TransportVersion> getAllVersions() {
+        return ALL_VERSIONS;
+    }
+
+    final int id;
+    private final String uniqueId;
+
+    TransportVersion(int id, String uniqueId) {
+        this.id = id;
+        this.uniqueId = Strings.requireNonEmpty(uniqueId, "Each TransportVersion needs a unique string id");
+    }
+
+    public boolean after(TransportVersion version) {
+        return version.id < id;
+    }
+
+    public boolean onOrAfter(TransportVersion version) {
+        return version.id <= id;
+    }
+
+    public boolean before(TransportVersion version) {
+        return version.id > id;
+    }
+
+    public boolean onOrBefore(TransportVersion version) {
+        return version.id >= id;
+    }
+
+    @Override
+    public int compareTo(TransportVersion other) {
+        return Integer.compare(this.id, other.id);
+    }
+
+    @Override
+    public String toString() {
+        return Integer.toString(id);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        TransportVersion version = (TransportVersion) o;
+
+        if (id != version.id) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return id;
+    }
+
+}

+ 100 - 96
server/src/main/java/org/elasticsearch/Version.java

@@ -46,95 +46,96 @@ public class Version implements Comparable<Version>, ToXContentFragment {
      */
      */
 
 
     public static final int V_EMPTY_ID = 0;
     public static final int V_EMPTY_ID = 0;
-    public static final Version V_EMPTY = new Version(V_EMPTY_ID, org.apache.lucene.util.Version.LATEST);
-    public static final Version V_7_0_0 = new Version(7_00_00_99, org.apache.lucene.util.Version.LUCENE_8_0_0);
-    public static final Version V_7_0_1 = new Version(7_00_01_99, org.apache.lucene.util.Version.LUCENE_8_0_0);
-    public static final Version V_7_1_0 = new Version(7_01_00_99, org.apache.lucene.util.Version.LUCENE_8_0_0);
-    public static final Version V_7_1_1 = new Version(7_01_01_99, org.apache.lucene.util.Version.LUCENE_8_0_0);
-    public static final Version V_7_2_0 = new Version(7_02_00_99, org.apache.lucene.util.Version.LUCENE_8_0_0);
-    public static final Version V_7_2_1 = new Version(7_02_01_99, org.apache.lucene.util.Version.LUCENE_8_0_0);
-    public static final Version V_7_3_0 = new Version(7_03_00_99, org.apache.lucene.util.Version.LUCENE_8_1_0);
-    public static final Version V_7_3_1 = new Version(7_03_01_99, org.apache.lucene.util.Version.LUCENE_8_1_0);
-    public static final Version V_7_3_2 = new Version(7_03_02_99, org.apache.lucene.util.Version.LUCENE_8_1_0);
-    public static final Version V_7_4_0 = new Version(7_04_00_99, org.apache.lucene.util.Version.LUCENE_8_2_0);
-    public static final Version V_7_4_1 = new Version(7_04_01_99, org.apache.lucene.util.Version.LUCENE_8_2_0);
-    public static final Version V_7_4_2 = new Version(7_04_02_99, org.apache.lucene.util.Version.LUCENE_8_2_0);
-    public static final Version V_7_5_0 = new Version(7_05_00_99, org.apache.lucene.util.Version.LUCENE_8_3_0);
-    public static final Version V_7_5_1 = new Version(7_05_01_99, org.apache.lucene.util.Version.LUCENE_8_3_0);
-    public static final Version V_7_5_2 = new Version(7_05_02_99, org.apache.lucene.util.Version.LUCENE_8_3_0);
-    public static final Version V_7_6_0 = new Version(7_06_00_99, org.apache.lucene.util.Version.LUCENE_8_4_0);
-    public static final Version V_7_6_1 = new Version(7_06_01_99, org.apache.lucene.util.Version.LUCENE_8_4_0);
-    public static final Version V_7_6_2 = new Version(7_06_02_99, org.apache.lucene.util.Version.LUCENE_8_4_0);
-    public static final Version V_7_7_0 = new Version(7_07_00_99, org.apache.lucene.util.Version.LUCENE_8_5_1);
-    public static final Version V_7_7_1 = new Version(7_07_01_99, org.apache.lucene.util.Version.LUCENE_8_5_1);
-    public static final Version V_7_8_0 = new Version(7_08_00_99, org.apache.lucene.util.Version.LUCENE_8_5_1);
-    public static final Version V_7_8_1 = new Version(7_08_01_99, org.apache.lucene.util.Version.LUCENE_8_5_1);
-    public static final Version V_7_9_0 = new Version(7_09_00_99, org.apache.lucene.util.Version.LUCENE_8_6_0);
-    public static final Version V_7_9_1 = new Version(7_09_01_99, org.apache.lucene.util.Version.LUCENE_8_6_2);
-    public static final Version V_7_9_2 = new Version(7_09_02_99, org.apache.lucene.util.Version.LUCENE_8_6_2);
-    public static final Version V_7_9_3 = new Version(7_09_03_99, org.apache.lucene.util.Version.LUCENE_8_6_2);
-    public static final Version V_7_10_0 = new Version(7_10_00_99, org.apache.lucene.util.Version.LUCENE_8_7_0);
-    public static final Version V_7_10_1 = new Version(7_10_01_99, org.apache.lucene.util.Version.LUCENE_8_7_0);
-    public static final Version V_7_10_2 = new Version(7_10_02_99, org.apache.lucene.util.Version.LUCENE_8_7_0);
-    public static final Version V_7_11_0 = new Version(7_11_00_99, org.apache.lucene.util.Version.LUCENE_8_7_0);
-    public static final Version V_7_11_1 = new Version(7_11_01_99, org.apache.lucene.util.Version.LUCENE_8_7_0);
-    public static final Version V_7_11_2 = new Version(7_11_02_99, org.apache.lucene.util.Version.LUCENE_8_7_0);
-    public static final Version V_7_12_0 = new Version(7_12_00_99, org.apache.lucene.util.Version.LUCENE_8_8_0);
-    public static final Version V_7_12_1 = new Version(7_12_01_99, org.apache.lucene.util.Version.LUCENE_8_8_0);
-    public static final Version V_7_13_0 = new Version(7_13_00_99, org.apache.lucene.util.Version.LUCENE_8_8_2);
-    public static final Version V_7_13_1 = new Version(7_13_01_99, org.apache.lucene.util.Version.LUCENE_8_8_2);
-    public static final Version V_7_13_2 = new Version(7_13_02_99, org.apache.lucene.util.Version.LUCENE_8_8_2);
-    public static final Version V_7_13_3 = new Version(7_13_03_99, org.apache.lucene.util.Version.LUCENE_8_8_2);
-    public static final Version V_7_13_4 = new Version(7_13_04_99, org.apache.lucene.util.Version.LUCENE_8_8_2);
-    public static final Version V_7_14_0 = new Version(7_14_00_99, org.apache.lucene.util.Version.LUCENE_8_9_0);
-    public static final Version V_7_14_1 = new Version(7_14_01_99, org.apache.lucene.util.Version.LUCENE_8_9_0);
-    public static final Version V_7_14_2 = new Version(7_14_02_99, org.apache.lucene.util.Version.LUCENE_8_9_0);
-    public static final Version V_7_15_0 = new Version(7_15_00_99, org.apache.lucene.util.Version.LUCENE_8_9_0);
-    public static final Version V_7_15_1 = new Version(7_15_01_99, org.apache.lucene.util.Version.LUCENE_8_9_0);
-    public static final Version V_7_15_2 = new Version(7_15_02_99, org.apache.lucene.util.Version.LUCENE_8_9_0);
-    public static final Version V_7_16_0 = new Version(7_16_00_99, org.apache.lucene.util.Version.LUCENE_8_10_1);
-    public static final Version V_7_16_1 = new Version(7_16_01_99, org.apache.lucene.util.Version.LUCENE_8_10_1);
-    public static final Version V_7_16_2 = new Version(7_16_02_99, org.apache.lucene.util.Version.LUCENE_8_10_1);
-    public static final Version V_7_16_3 = new Version(7_16_03_99, org.apache.lucene.util.Version.LUCENE_8_10_1);
-    public static final Version V_7_17_0 = new Version(7_17_00_99, org.apache.lucene.util.Version.LUCENE_8_11_1);
-    public static final Version V_7_17_1 = new Version(7_17_01_99, org.apache.lucene.util.Version.LUCENE_8_11_1);
-    public static final Version V_7_17_2 = new Version(7_17_02_99, org.apache.lucene.util.Version.LUCENE_8_11_1);
-    public static final Version V_7_17_3 = new Version(7_17_03_99, org.apache.lucene.util.Version.LUCENE_8_11_1);
-    public static final Version V_7_17_4 = new Version(7_17_04_99, org.apache.lucene.util.Version.LUCENE_8_11_1);
-    public static final Version V_7_17_5 = new Version(7_17_05_99, org.apache.lucene.util.Version.LUCENE_8_11_1);
-    public static final Version V_7_17_6 = new Version(7_17_06_99, org.apache.lucene.util.Version.LUCENE_8_11_1);
-    public static final Version V_7_17_7 = new Version(7_17_07_99, org.apache.lucene.util.Version.LUCENE_8_11_1);
-    public static final Version V_7_17_8 = new Version(7_17_08_99, org.apache.lucene.util.Version.LUCENE_8_11_1);
-    public static final Version V_7_17_9 = new Version(7_17_09_99, org.apache.lucene.util.Version.LUCENE_8_11_1);
-    public static final Version V_8_0_0 = new Version(8_00_00_99, org.apache.lucene.util.Version.LUCENE_9_0_0);
-    public static final Version V_8_0_1 = new Version(8_00_01_99, org.apache.lucene.util.Version.LUCENE_9_0_0);
-    public static final Version V_8_1_0 = new Version(8_01_00_99, org.apache.lucene.util.Version.LUCENE_9_0_0);
-    public static final Version V_8_1_1 = new Version(8_01_01_99, org.apache.lucene.util.Version.LUCENE_9_0_0);
-    public static final Version V_8_1_2 = new Version(8_01_02_99, org.apache.lucene.util.Version.LUCENE_9_0_0);
-    public static final Version V_8_1_3 = new Version(8_01_03_99, org.apache.lucene.util.Version.LUCENE_9_0_0);
-    public static final Version V_8_2_0 = new Version(8_02_00_99, org.apache.lucene.util.Version.LUCENE_9_1_0);
-    public static final Version V_8_2_1 = new Version(8_02_01_99, org.apache.lucene.util.Version.LUCENE_9_1_0);
-    public static final Version V_8_2_2 = new Version(8_02_02_99, org.apache.lucene.util.Version.LUCENE_9_1_0);
-    public static final Version V_8_2_3 = new Version(8_02_03_99, org.apache.lucene.util.Version.LUCENE_9_1_0);
-    public static final Version V_8_3_0 = new Version(8_03_00_99, org.apache.lucene.util.Version.LUCENE_9_2_0);
-    public static final Version V_8_3_1 = new Version(8_03_01_99, org.apache.lucene.util.Version.LUCENE_9_2_0);
-    public static final Version V_8_3_2 = new Version(8_03_02_99, org.apache.lucene.util.Version.LUCENE_9_2_0);
-    public static final Version V_8_3_3 = new Version(8_03_03_99, org.apache.lucene.util.Version.LUCENE_9_2_0);
-    public static final Version V_8_4_0 = new Version(8_04_00_99, org.apache.lucene.util.Version.LUCENE_9_3_0);
-    public static final Version V_8_4_1 = new Version(8_04_01_99, org.apache.lucene.util.Version.LUCENE_9_3_0);
-    public static final Version V_8_4_2 = new Version(8_04_02_99, org.apache.lucene.util.Version.LUCENE_9_3_0);
-    public static final Version V_8_4_3 = new Version(8_04_03_99, org.apache.lucene.util.Version.LUCENE_9_3_0);
-    public static final Version V_8_5_0 = new Version(8_05_00_99, org.apache.lucene.util.Version.LUCENE_9_4_1);
-    public static final Version V_8_5_1 = new Version(8_05_01_99, org.apache.lucene.util.Version.LUCENE_9_4_1);
-    public static final Version V_8_5_2 = new Version(8_05_02_99, org.apache.lucene.util.Version.LUCENE_9_4_1);
-    public static final Version V_8_5_3 = new Version(8_05_03_99, org.apache.lucene.util.Version.LUCENE_9_4_2);
-    public static final Version V_8_6_0 = new Version(8_06_00_99, org.apache.lucene.util.Version.LUCENE_9_4_2);
-    public static final Version V_8_6_1 = new Version(8_06_01_99, org.apache.lucene.util.Version.LUCENE_9_4_2);
-    public static final Version V_8_7_0 = new Version(8_07_00_99, org.apache.lucene.util.Version.LUCENE_9_4_2);
+    public static final Version V_EMPTY = new Version(V_EMPTY_ID, TransportVersion.ZERO, org.apache.lucene.util.Version.LATEST);
+    public static final Version V_7_0_0 = new Version(7_00_00_99, TransportVersion.V_7_0_0, org.apache.lucene.util.Version.LUCENE_8_0_0);
+    public static final Version V_7_0_1 = new Version(7_00_01_99, TransportVersion.V_7_0_1, org.apache.lucene.util.Version.LUCENE_8_0_0);
+    public static final Version V_7_1_0 = new Version(7_01_00_99, TransportVersion.V_7_1_0, org.apache.lucene.util.Version.LUCENE_8_0_0);
+    public static final Version V_7_1_1 = new Version(7_01_01_99, TransportVersion.V_7_1_1, org.apache.lucene.util.Version.LUCENE_8_0_0);
+    public static final Version V_7_2_0 = new Version(7_02_00_99, TransportVersion.V_7_2_0, org.apache.lucene.util.Version.LUCENE_8_0_0);
+    public static final Version V_7_2_1 = new Version(7_02_01_99, TransportVersion.V_7_2_1, org.apache.lucene.util.Version.LUCENE_8_0_0);
+    public static final Version V_7_3_0 = new Version(7_03_00_99, TransportVersion.V_7_3_0, org.apache.lucene.util.Version.LUCENE_8_1_0);
+    public static final Version V_7_3_1 = new Version(7_03_01_99, TransportVersion.V_7_3_1, org.apache.lucene.util.Version.LUCENE_8_1_0);
+    public static final Version V_7_3_2 = new Version(7_03_02_99, TransportVersion.V_7_3_2, org.apache.lucene.util.Version.LUCENE_8_1_0);
+    public static final Version V_7_4_0 = new Version(7_04_00_99, TransportVersion.V_7_4_0, org.apache.lucene.util.Version.LUCENE_8_2_0);
+    public static final Version V_7_4_1 = new Version(7_04_01_99, TransportVersion.V_7_4_1, org.apache.lucene.util.Version.LUCENE_8_2_0);
+    public static final Version V_7_4_2 = new Version(7_04_02_99, TransportVersion.V_7_4_2, org.apache.lucene.util.Version.LUCENE_8_2_0);
+    public static final Version V_7_5_0 = new Version(7_05_00_99, TransportVersion.V_7_5_0, org.apache.lucene.util.Version.LUCENE_8_3_0);
+    public static final Version V_7_5_1 = new Version(7_05_01_99, TransportVersion.V_7_5_1, org.apache.lucene.util.Version.LUCENE_8_3_0);
+    public static final Version V_7_5_2 = new Version(7_05_02_99, TransportVersion.V_7_5_2, org.apache.lucene.util.Version.LUCENE_8_3_0);
+    public static final Version V_7_6_0 = new Version(7_06_00_99, TransportVersion.V_7_6_0, org.apache.lucene.util.Version.LUCENE_8_4_0);
+    public static final Version V_7_6_1 = new Version(7_06_01_99, TransportVersion.V_7_6_1, org.apache.lucene.util.Version.LUCENE_8_4_0);
+    public static final Version V_7_6_2 = new Version(7_06_02_99, TransportVersion.V_7_6_2, org.apache.lucene.util.Version.LUCENE_8_4_0);
+    public static final Version V_7_7_0 = new Version(7_07_00_99, TransportVersion.V_7_7_0, org.apache.lucene.util.Version.LUCENE_8_5_1);
+    public static final Version V_7_7_1 = new Version(7_07_01_99, TransportVersion.V_7_7_1, org.apache.lucene.util.Version.LUCENE_8_5_1);
+    public static final Version V_7_8_0 = new Version(7_08_00_99, TransportVersion.V_7_8_0, org.apache.lucene.util.Version.LUCENE_8_5_1);
+    public static final Version V_7_8_1 = new Version(7_08_01_99, TransportVersion.V_7_8_1, org.apache.lucene.util.Version.LUCENE_8_5_1);
+    public static final Version V_7_9_0 = new Version(7_09_00_99, TransportVersion.V_7_9_0, org.apache.lucene.util.Version.LUCENE_8_6_0);
+    public static final Version V_7_9_1 = new Version(7_09_01_99, TransportVersion.V_7_9_1, org.apache.lucene.util.Version.LUCENE_8_6_2);
+    public static final Version V_7_9_2 = new Version(7_09_02_99, TransportVersion.V_7_9_2, org.apache.lucene.util.Version.LUCENE_8_6_2);
+    public static final Version V_7_9_3 = new Version(7_09_03_99, TransportVersion.V_7_9_3, org.apache.lucene.util.Version.LUCENE_8_6_2);
+    public static final Version V_7_10_0 = new Version(7_10_00_99, TransportVersion.V_7_10_0, org.apache.lucene.util.Version.LUCENE_8_7_0);
+    public static final Version V_7_10_1 = new Version(7_10_01_99, TransportVersion.V_7_10_1, org.apache.lucene.util.Version.LUCENE_8_7_0);
+    public static final Version V_7_10_2 = new Version(7_10_02_99, TransportVersion.V_7_10_2, org.apache.lucene.util.Version.LUCENE_8_7_0);
+    public static final Version V_7_11_0 = new Version(7_11_00_99, TransportVersion.V_7_11_0, org.apache.lucene.util.Version.LUCENE_8_7_0);
+    public static final Version V_7_11_1 = new Version(7_11_01_99, TransportVersion.V_7_11_1, org.apache.lucene.util.Version.LUCENE_8_7_0);
+    public static final Version V_7_11_2 = new Version(7_11_02_99, TransportVersion.V_7_11_2, org.apache.lucene.util.Version.LUCENE_8_7_0);
+    public static final Version V_7_12_0 = new Version(7_12_00_99, TransportVersion.V_7_12_0, org.apache.lucene.util.Version.LUCENE_8_8_0);
+    public static final Version V_7_12_1 = new Version(7_12_01_99, TransportVersion.V_7_12_1, org.apache.lucene.util.Version.LUCENE_8_8_0);
+    public static final Version V_7_13_0 = new Version(7_13_00_99, TransportVersion.V_7_13_0, org.apache.lucene.util.Version.LUCENE_8_8_2);
+    public static final Version V_7_13_1 = new Version(7_13_01_99, TransportVersion.V_7_13_1, org.apache.lucene.util.Version.LUCENE_8_8_2);
+    public static final Version V_7_13_2 = new Version(7_13_02_99, TransportVersion.V_7_13_2, org.apache.lucene.util.Version.LUCENE_8_8_2);
+    public static final Version V_7_13_3 = new Version(7_13_03_99, TransportVersion.V_7_13_3, org.apache.lucene.util.Version.LUCENE_8_8_2);
+    public static final Version V_7_13_4 = new Version(7_13_04_99, TransportVersion.V_7_13_4, org.apache.lucene.util.Version.LUCENE_8_8_2);
+    public static final Version V_7_14_0 = new Version(7_14_00_99, TransportVersion.V_7_14_0, org.apache.lucene.util.Version.LUCENE_8_9_0);
+    public static final Version V_7_14_1 = new Version(7_14_01_99, TransportVersion.V_7_14_1, org.apache.lucene.util.Version.LUCENE_8_9_0);
+    public static final Version V_7_14_2 = new Version(7_14_02_99, TransportVersion.V_7_14_2, org.apache.lucene.util.Version.LUCENE_8_9_0);
+    public static final Version V_7_15_0 = new Version(7_15_00_99, TransportVersion.V_7_15_0, org.apache.lucene.util.Version.LUCENE_8_9_0);
+    public static final Version V_7_15_1 = new Version(7_15_01_99, TransportVersion.V_7_15_1, org.apache.lucene.util.Version.LUCENE_8_9_0);
+    public static final Version V_7_15_2 = new Version(7_15_02_99, TransportVersion.V_7_15_2, org.apache.lucene.util.Version.LUCENE_8_9_0);
+    public static final Version V_7_16_0 = new Version(7_16_00_99, TransportVersion.V_7_16_0, org.apache.lucene.util.Version.LUCENE_8_10_1);
+    public static final Version V_7_16_1 = new Version(7_16_01_99, TransportVersion.V_7_16_1, org.apache.lucene.util.Version.LUCENE_8_10_1);
+    public static final Version V_7_16_2 = new Version(7_16_02_99, TransportVersion.V_7_16_2, org.apache.lucene.util.Version.LUCENE_8_10_1);
+    public static final Version V_7_16_3 = new Version(7_16_03_99, TransportVersion.V_7_16_3, org.apache.lucene.util.Version.LUCENE_8_10_1);
+    public static final Version V_7_17_0 = new Version(7_17_00_99, TransportVersion.V_7_17_0, org.apache.lucene.util.Version.LUCENE_8_11_1);
+    public static final Version V_7_17_1 = new Version(7_17_01_99, TransportVersion.V_7_17_1, org.apache.lucene.util.Version.LUCENE_8_11_1);
+    public static final Version V_7_17_2 = new Version(7_17_02_99, TransportVersion.V_7_17_2, org.apache.lucene.util.Version.LUCENE_8_11_1);
+    public static final Version V_7_17_3 = new Version(7_17_03_99, TransportVersion.V_7_17_3, org.apache.lucene.util.Version.LUCENE_8_11_1);
+    public static final Version V_7_17_4 = new Version(7_17_04_99, TransportVersion.V_7_17_4, org.apache.lucene.util.Version.LUCENE_8_11_1);
+    public static final Version V_7_17_5 = new Version(7_17_05_99, TransportVersion.V_7_17_5, org.apache.lucene.util.Version.LUCENE_8_11_1);
+    public static final Version V_7_17_6 = new Version(7_17_06_99, TransportVersion.V_7_17_6, org.apache.lucene.util.Version.LUCENE_8_11_1);
+    public static final Version V_7_17_7 = new Version(7_17_07_99, TransportVersion.V_7_17_7, org.apache.lucene.util.Version.LUCENE_8_11_1);
+    public static final Version V_7_17_8 = new Version(7_17_08_99, TransportVersion.V_7_17_8, org.apache.lucene.util.Version.LUCENE_8_11_1);
+    public static final Version V_7_17_9 = new Version(7_17_09_99, TransportVersion.V_7_17_9, org.apache.lucene.util.Version.LUCENE_8_11_1);
+    public static final Version V_8_0_0 = new Version(8_00_00_99, TransportVersion.V_8_0_0, org.apache.lucene.util.Version.LUCENE_9_0_0);
+    public static final Version V_8_0_1 = new Version(8_00_01_99, TransportVersion.V_8_0_1, org.apache.lucene.util.Version.LUCENE_9_0_0);
+    public static final Version V_8_1_0 = new Version(8_01_00_99, TransportVersion.V_8_1_0, org.apache.lucene.util.Version.LUCENE_9_0_0);
+    public static final Version V_8_1_1 = new Version(8_01_01_99, TransportVersion.V_8_1_1, org.apache.lucene.util.Version.LUCENE_9_0_0);
+    public static final Version V_8_1_2 = new Version(8_01_02_99, TransportVersion.V_8_1_2, org.apache.lucene.util.Version.LUCENE_9_0_0);
+    public static final Version V_8_1_3 = new Version(8_01_03_99, TransportVersion.V_8_1_3, org.apache.lucene.util.Version.LUCENE_9_0_0);
+    public static final Version V_8_2_0 = new Version(8_02_00_99, TransportVersion.V_8_2_0, org.apache.lucene.util.Version.LUCENE_9_1_0);
+    public static final Version V_8_2_1 = new Version(8_02_01_99, TransportVersion.V_8_2_1, org.apache.lucene.util.Version.LUCENE_9_1_0);
+    public static final Version V_8_2_2 = new Version(8_02_02_99, TransportVersion.V_8_2_2, org.apache.lucene.util.Version.LUCENE_9_1_0);
+    public static final Version V_8_2_3 = new Version(8_02_03_99, TransportVersion.V_8_2_3, org.apache.lucene.util.Version.LUCENE_9_1_0);
+    public static final Version V_8_3_0 = new Version(8_03_00_99, TransportVersion.V_8_3_0, org.apache.lucene.util.Version.LUCENE_9_2_0);
+    public static final Version V_8_3_1 = new Version(8_03_01_99, TransportVersion.V_8_3_1, org.apache.lucene.util.Version.LUCENE_9_2_0);
+    public static final Version V_8_3_2 = new Version(8_03_02_99, TransportVersion.V_8_3_2, org.apache.lucene.util.Version.LUCENE_9_2_0);
+    public static final Version V_8_3_3 = new Version(8_03_03_99, TransportVersion.V_8_3_3, org.apache.lucene.util.Version.LUCENE_9_2_0);
+    public static final Version V_8_4_0 = new Version(8_04_00_99, TransportVersion.V_8_4_0, org.apache.lucene.util.Version.LUCENE_9_3_0);
+    public static final Version V_8_4_1 = new Version(8_04_01_99, TransportVersion.V_8_4_1, org.apache.lucene.util.Version.LUCENE_9_3_0);
+    public static final Version V_8_4_2 = new Version(8_04_02_99, TransportVersion.V_8_4_2, org.apache.lucene.util.Version.LUCENE_9_3_0);
+    public static final Version V_8_4_3 = new Version(8_04_03_99, TransportVersion.V_8_4_3, org.apache.lucene.util.Version.LUCENE_9_3_0);
+    public static final Version V_8_5_0 = new Version(8_05_00_99, TransportVersion.V_8_5_0, org.apache.lucene.util.Version.LUCENE_9_4_1);
+    public static final Version V_8_5_1 = new Version(8_05_01_99, TransportVersion.V_8_5_1, org.apache.lucene.util.Version.LUCENE_9_4_1);
+    public static final Version V_8_5_2 = new Version(8_05_02_99, TransportVersion.V_8_5_2, org.apache.lucene.util.Version.LUCENE_9_4_1);
+    public static final Version V_8_5_3 = new Version(8_05_03_99, TransportVersion.V_8_5_3, org.apache.lucene.util.Version.LUCENE_9_4_2);
+    public static final Version V_8_5_4 = new Version(8_05_04_99, TransportVersion.V_8_5_4, org.apache.lucene.util.Version.LUCENE_9_4_2);
+    public static final Version V_8_6_0 = new Version(8_06_00_99, TransportVersion.V_8_6_0, org.apache.lucene.util.Version.LUCENE_9_4_2);
+    public static final Version V_8_6_1 = new Version(8_06_01_99, TransportVersion.V_8_6_1, org.apache.lucene.util.Version.LUCENE_9_4_2);
+    public static final Version V_8_7_0 = new Version(8_07_00_99, TransportVersion.V_8_7_0, org.apache.lucene.util.Version.LUCENE_9_4_2);
     public static final Version CURRENT = V_8_7_0;
     public static final Version CURRENT = V_8_7_0;
 
 
-    private static final Map<Integer, Version> idToVersion;
-    private static final Map<String, Version> stringToVersion;
+    private static final Map<Integer, Version> VERSION_IDS;
+    private static final Map<String, Version> VERSION_STRINGS;
 
 
     static {
     static {
         final Map<Integer, Version> builder = new HashMap<>();
         final Map<Integer, Version> builder = new HashMap<>();
@@ -179,8 +180,8 @@ public class Version implements Comparable<Version>, ToXContentFragment {
                 + "]";
                 + "]";
         builder.put(V_EMPTY_ID, V_EMPTY);
         builder.put(V_EMPTY_ID, V_EMPTY);
         builderByString.put(V_EMPTY.toString(), V_EMPTY);
         builderByString.put(V_EMPTY.toString(), V_EMPTY);
-        idToVersion = Map.copyOf(builder);
-        stringToVersion = Map.copyOf(builderByString);
+        VERSION_IDS = Map.copyOf(builder);
+        VERSION_STRINGS = Map.copyOf(builderByString);
     }
     }
 
 
     public static Version readVersion(StreamInput in) throws IOException {
     public static Version readVersion(StreamInput in) throws IOException {
@@ -188,7 +189,7 @@ public class Version implements Comparable<Version>, ToXContentFragment {
     }
     }
 
 
     public static Version fromId(int id) {
     public static Version fromId(int id) {
-        final Version known = idToVersion.get(id);
+        final Version known = VERSION_IDS.get(id);
         if (known != null) {
         if (known != null) {
             return known;
             return known;
         }
         }
@@ -200,7 +201,7 @@ public class Version implements Comparable<Version>, ToXContentFragment {
         // Our best guess is to use the same Lucene version as the previous
         // Our best guess is to use the same Lucene version as the previous
         // version in the list, assuming that it didn't change.
         // version in the list, assuming that it didn't change.
         List<Version> versions = DeclaredVersionsHolder.DECLARED_VERSIONS;
         List<Version> versions = DeclaredVersionsHolder.DECLARED_VERSIONS;
-        Version tmp = new Version(id, org.apache.lucene.util.Version.LATEST);
+        Version tmp = new Version(id, TransportVersion.CURRENT, org.apache.lucene.util.Version.LATEST);
         int index = Collections.binarySearch(versions, tmp);
         int index = Collections.binarySearch(versions, tmp);
         if (index < 0) {
         if (index < 0) {
             index = -2 - index;
             index = -2 - index;
@@ -216,7 +217,8 @@ public class Version implements Comparable<Version>, ToXContentFragment {
         } else {
         } else {
             luceneVersion = versions.get(index).luceneVersion;
             luceneVersion = versions.get(index).luceneVersion;
         }
         }
-        return new Version(id, luceneVersion);
+        // TODO: assume this is an old version that has transport version == release version
+        return new Version(id, TransportVersion.fromId(id), luceneVersion);
     }
     }
 
 
     public static void writeVersion(Version version, StreamOutput out) throws IOException {
     public static void writeVersion(Version version, StreamOutput out) throws IOException {
@@ -224,14 +226,14 @@ public class Version implements Comparable<Version>, ToXContentFragment {
     }
     }
 
 
     /**
     /**
-     * Returns the minimum version between the 2.
+     * Returns the minimum version of {@code version1} and {@code version2}
      */
      */
     public static Version min(Version version1, Version version2) {
     public static Version min(Version version1, Version version2) {
         return version1.id < version2.id ? version1 : version2;
         return version1.id < version2.id ? version1 : version2;
     }
     }
 
 
     /**
     /**
-     * Returns the maximum version between the 2
+     * Returns the maximum version of {@code version1} and {@code version2}
      */
      */
     public static Version max(Version version1, Version version2) {
     public static Version max(Version version1, Version version2) {
         return version1.id > version2.id ? version1 : version2;
         return version1.id > version2.id ? version1 : version2;
@@ -244,7 +246,7 @@ public class Version implements Comparable<Version>, ToXContentFragment {
         if (Strings.hasLength(version) == false) {
         if (Strings.hasLength(version) == false) {
             return Version.CURRENT;
             return Version.CURRENT;
         }
         }
-        final Version cached = stringToVersion.get(version);
+        final Version cached = VERSION_STRINGS.get(version);
         if (cached != null) {
         if (cached != null) {
             return cached;
             return cached;
         }
         }
@@ -299,16 +301,18 @@ public class Version implements Comparable<Version>, ToXContentFragment {
     public final byte minor;
     public final byte minor;
     public final byte revision;
     public final byte revision;
     public final byte build;
     public final byte build;
+    public final TransportVersion transportVersion;
     public final org.apache.lucene.util.Version luceneVersion;
     public final org.apache.lucene.util.Version luceneVersion;
     private final String toString;
     private final String toString;
     private final int previousMajorId;
     private final int previousMajorId;
 
 
-    Version(int id, org.apache.lucene.util.Version luceneVersion) {
+    Version(int id, TransportVersion transportVersion, org.apache.lucene.util.Version luceneVersion) {
         this.id = id;
         this.id = id;
         this.major = (byte) ((id / 1000000) % 100);
         this.major = (byte) ((id / 1000000) % 100);
         this.minor = (byte) ((id / 10000) % 100);
         this.minor = (byte) ((id / 10000) % 100);
         this.revision = (byte) ((id / 100) % 100);
         this.revision = (byte) ((id / 100) % 100);
         this.build = (byte) (id % 100);
         this.build = (byte) (id % 100);
+        this.transportVersion = Objects.requireNonNull(transportVersion);
         this.luceneVersion = Objects.requireNonNull(luceneVersion);
         this.luceneVersion = Objects.requireNonNull(luceneVersion);
         this.toString = major + "." + minor + "." + revision;
         this.toString = major + "." + minor + "." + revision;
         this.previousMajorId = major > 0 ? (major - 1) * 1000000 + 99 : major;
         this.previousMajorId = major > 0 ? (major - 1) * 1000000 + 99 : major;

+ 6 - 0
server/src/main/java/org/elasticsearch/common/io/stream/FilterStreamInput.java

@@ -8,6 +8,7 @@
 
 
 package org.elasticsearch.common.io.stream;
 package org.elasticsearch.common.io.stream;
 
 
+import org.elasticsearch.TransportVersion;
 import org.elasticsearch.Version;
 import org.elasticsearch.Version;
 import org.elasticsearch.common.bytes.ReleasableBytesReference;
 import org.elasticsearch.common.bytes.ReleasableBytesReference;
 
 
@@ -90,6 +91,11 @@ public abstract class FilterStreamInput extends StreamInput {
         return delegate.getVersion();
         return delegate.getVersion();
     }
     }
 
 
+    @Override
+    public TransportVersion getTransportVersion() {
+        return delegate.getTransportVersion();
+    }
+
     @Override
     @Override
     public void setVersion(Version version) {
     public void setVersion(Version version) {
         delegate.setVersion(version);
         delegate.setVersion(version);

+ 8 - 0
server/src/main/java/org/elasticsearch/common/io/stream/StreamInput.java

@@ -17,6 +17,7 @@ import org.apache.lucene.util.ArrayUtil;
 import org.apache.lucene.util.BitUtil;
 import org.apache.lucene.util.BitUtil;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.BytesRef;
 import org.elasticsearch.ElasticsearchException;
 import org.elasticsearch.ElasticsearchException;
+import org.elasticsearch.TransportVersion;
 import org.elasticsearch.Version;
 import org.elasticsearch.Version;
 import org.elasticsearch.common.Strings;
 import org.elasticsearch.common.Strings;
 import org.elasticsearch.common.bytes.BytesArray;
 import org.elasticsearch.common.bytes.BytesArray;
@@ -92,6 +93,13 @@ public abstract class StreamInput extends InputStream {
         return this.version;
         return this.version;
     }
     }
 
 
+    /**
+     * The transport version the data is serialized as.
+     */
+    public TransportVersion getTransportVersion() {
+        return this.version.transportVersion;
+    }
+
     /**
     /**
      * Set the version of the node on the other side of this stream.
      * Set the version of the node on the other side of this stream.
      */
      */

+ 8 - 0
server/src/main/java/org/elasticsearch/common/io/stream/StreamOutput.java

@@ -17,6 +17,7 @@ import org.apache.lucene.util.BitUtil;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.BytesRefBuilder;
 import org.apache.lucene.util.BytesRefBuilder;
 import org.elasticsearch.ElasticsearchException;
 import org.elasticsearch.ElasticsearchException;
+import org.elasticsearch.TransportVersion;
 import org.elasticsearch.Version;
 import org.elasticsearch.Version;
 import org.elasticsearch.common.bytes.BytesArray;
 import org.elasticsearch.common.bytes.BytesArray;
 import org.elasticsearch.common.bytes.BytesReference;
 import org.elasticsearch.common.bytes.BytesReference;
@@ -86,6 +87,13 @@ public abstract class StreamOutput extends OutputStream {
         return this.version;
         return this.version;
     }
     }
 
 
+    /**
+     * The transport version to serialize the data as.
+     */
+    public TransportVersion getTransportVersion() {
+        return this.version.transportVersion;
+    }
+
     /**
     /**
      * Set the version of the node on the other side of this stream.
      * Set the version of the node on the other side of this stream.
      */
      */

+ 179 - 0
server/src/test/java/org/elasticsearch/TransportVersionTests.java

@@ -0,0 +1,179 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+package org.elasticsearch;
+
+import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.TransportVersionUtils;
+
+import java.lang.reflect.Modifier;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.lessThan;
+import static org.hamcrest.Matchers.sameInstance;
+
+public class TransportVersionTests extends ESTestCase {
+
+    public void testVersionComparison() {
+        TransportVersion V_7_2_0 = TransportVersion.V_7_2_0;
+        TransportVersion V_8_0_0 = TransportVersion.V_8_0_0;
+        assertThat(V_7_2_0.before(V_8_0_0), is(true));
+        assertThat(V_7_2_0.before(V_7_2_0), is(false));
+        assertThat(V_8_0_0.before(V_7_2_0), is(false));
+
+        assertThat(V_7_2_0.onOrBefore(V_8_0_0), is(true));
+        assertThat(V_7_2_0.onOrBefore(V_7_2_0), is(true));
+        assertThat(V_8_0_0.onOrBefore(V_7_2_0), is(false));
+
+        assertThat(V_7_2_0.after(V_8_0_0), is(false));
+        assertThat(V_7_2_0.after(V_7_2_0), is(false));
+        assertThat(V_8_0_0.after(V_7_2_0), is(true));
+
+        assertThat(V_7_2_0.onOrAfter(V_8_0_0), is(false));
+        assertThat(V_7_2_0.onOrAfter(V_7_2_0), is(true));
+        assertThat(V_8_0_0.onOrAfter(V_7_2_0), is(true));
+
+        assertThat(V_7_2_0, is(lessThan(V_8_0_0)));
+        assertThat(V_7_2_0.compareTo(V_7_2_0), is(0));
+        assertThat(V_8_0_0, is(greaterThan(V_7_2_0)));
+    }
+
+    private static String padNumber(String number) {
+        return number.length() == 1 ? "0" + number : number;
+    }
+
+    public static class CorrectFakeVersion {
+        public static final TransportVersion V1 = new TransportVersion(1, "1");
+        public static final TransportVersion V2 = new TransportVersion(2, "2");
+        public static final TransportVersion V3 = new TransportVersion(3, "3");
+    }
+
+    public static class DuplicatedIdFakeVersion {
+        public static final TransportVersion V1 = new TransportVersion(1, "1");
+        public static final TransportVersion V2 = new TransportVersion(2, "2");
+        public static final TransportVersion V3 = new TransportVersion(2, "3");
+    }
+
+    public static class DuplicatedStringIdFakeVersion {
+        public static final TransportVersion V1 = new TransportVersion(1, "1");
+        public static final TransportVersion V2 = new TransportVersion(2, "2");
+        public static final TransportVersion V3 = new TransportVersion(3, "2");
+    }
+
+    public void testStaticTransportVersionChecks() {
+        assertThat(
+            TransportVersion.getAllVersionIds(CorrectFakeVersion.class),
+            equalTo(Map.of(1, CorrectFakeVersion.V1, 2, CorrectFakeVersion.V2, 3, CorrectFakeVersion.V3))
+        );
+        expectThrows(AssertionError.class, () -> TransportVersion.getAllVersionIds(DuplicatedIdFakeVersion.class));
+        expectThrows(AssertionError.class, () -> TransportVersion.getAllVersionIds(DuplicatedStringIdFakeVersion.class));
+    }
+
+    public void testDefinedConstants() throws IllegalAccessException {
+        Pattern historicalVersion = Pattern.compile("^V_(\\d{1,2})_(\\d{1,2})_(\\d{1,2})$");
+        Pattern transportVersion = Pattern.compile("^V_(\\d{2,})_(\\d{3})_(\\d{3})$");
+        Set<String> ignore = Set.of("ZERO", "CURRENT", "MINIMUM_COMPATIBLE");
+
+        for (java.lang.reflect.Field field : TransportVersion.class.getFields()) {
+            if (Modifier.isStatic(field.getModifiers())
+                && field.getType() == TransportVersion.class
+                && ignore.contains(field.getName()) == false) {
+                Matcher historical = historicalVersion.matcher(field.getName());
+                Matcher transport;
+                if (historical.matches()) {
+                    // old-style version constant
+                    String idString = historical.group(1) + padNumber(historical.group(2)) + padNumber(historical.group(3)) + "99";
+                    assertEquals(
+                        "Field " + field.getName() + " does not have expected id " + idString,
+                        idString,
+                        field.get(null).toString()
+                    );
+                } else if ((transport = transportVersion.matcher(field.getName())).matches()) {
+                    String idString = transport.group(1) + transport.group(2) + transport.group(3);
+                    assertEquals(
+                        "Field " + field.getName() + " does not have expected id " + idString,
+                        idString,
+                        field.get(null).toString()
+                    );
+                } else {
+                    fail("Field " + field.getName() + " does not have expected format");
+                }
+            }
+        }
+    }
+
+    public void testMin() {
+        assertEquals(
+            TransportVersionUtils.getPreviousVersion(),
+            TransportVersion.min(TransportVersion.CURRENT, TransportVersionUtils.getPreviousVersion())
+        );
+        assertEquals(
+            TransportVersion.fromId(1_01_01_99),
+            TransportVersion.min(TransportVersion.fromId(1_01_01_99), TransportVersion.CURRENT)
+        );
+        TransportVersion version = TransportVersionUtils.randomVersion();
+        TransportVersion version1 = TransportVersionUtils.randomVersion();
+        if (version.id <= version1.id) {
+            assertEquals(version, TransportVersion.min(version1, version));
+        } else {
+            assertEquals(version1, TransportVersion.min(version1, version));
+        }
+    }
+
+    public void testMax() {
+        assertEquals(TransportVersion.CURRENT, TransportVersion.max(TransportVersion.CURRENT, TransportVersionUtils.getPreviousVersion()));
+        assertEquals(TransportVersion.CURRENT, TransportVersion.max(TransportVersion.fromId(1_01_01_99), TransportVersion.CURRENT));
+        TransportVersion version = TransportVersionUtils.randomVersion();
+        TransportVersion version1 = TransportVersionUtils.randomVersion();
+        if (version.id >= version1.id) {
+            assertEquals(version, TransportVersion.max(version1, version));
+        } else {
+            assertEquals(version1, TransportVersion.max(version1, version));
+        }
+    }
+
+    public void testVersionConstantPresent() {
+        // TODO those versions are not cached at the moment, perhaps we should add them to idToVersion set too?
+        Set<TransportVersion> ignore = Set.of(TransportVersion.ZERO, TransportVersion.CURRENT, TransportVersion.MINIMUM_COMPATIBLE);
+        assertThat(TransportVersion.CURRENT, sameInstance(TransportVersion.fromId(TransportVersion.CURRENT.id)));
+        final int iters = scaledRandomIntBetween(20, 100);
+        for (int i = 0; i < iters; i++) {
+            TransportVersion version = TransportVersionUtils.randomVersion(ignore);
+
+            assertThat(version, sameInstance(TransportVersion.fromId(version.id)));
+        }
+    }
+
+    public void testCURRENTIsLatest() {
+        final int iters = scaledRandomIntBetween(100, 1000);
+        for (int i = 0; i < iters; i++) {
+            TransportVersion version = TransportVersionUtils.randomVersion();
+            if (version != TransportVersion.CURRENT) {
+                assertThat(
+                    "Version: " + version + " should be before: " + Version.CURRENT + " but wasn't",
+                    version.before(TransportVersion.CURRENT),
+                    is(true)
+                );
+            }
+        }
+    }
+
+    public void testToString() {
+        assertEquals("5000099", TransportVersion.fromId(5_00_00_99).toString());
+        assertEquals("2030099", TransportVersion.fromId(2_03_00_99).toString());
+        assertEquals("1000099", TransportVersion.fromId(1_00_00_99).toString());
+        assertEquals("2000099", TransportVersion.fromId(2_00_00_99).toString());
+        assertEquals("5000099", TransportVersion.fromId(5_00_00_99).toString());
+    }
+}

+ 2 - 2
server/src/test/java/org/elasticsearch/VersionTests.java

@@ -34,7 +34,7 @@ import static org.hamcrest.Matchers.sameInstance;
 
 
 public class VersionTests extends ESTestCase {
 public class VersionTests extends ESTestCase {
 
 
-    public void testVersionComparison() throws Exception {
+    public void testVersionComparison() {
         Version V_7_2_0 = Version.fromString("7.2.0");
         Version V_7_2_0 = Version.fromString("7.2.0");
         Version V_8_0_0 = Version.fromString("8.0.0");
         Version V_8_0_0 = Version.fromString("8.0.0");
         assertThat(V_7_2_0.before(V_8_0_0), is(true));
         assertThat(V_7_2_0.before(V_8_0_0), is(true));
@@ -178,7 +178,7 @@ public class VersionTests extends ESTestCase {
         for (int i = 0; i < iters; i++) {
         for (int i = 0; i < iters; i++) {
             Version version = randomVersion(random());
             Version version = randomVersion(random());
             if (random().nextBoolean()) {
             if (random().nextBoolean()) {
-                version = new Version(version.id, version.luceneVersion);
+                version = new Version(version.id, version.transportVersion, version.luceneVersion);
             }
             }
             Version parsedVersion = Version.fromString(version.toString());
             Version parsedVersion = Version.fromString(version.toString());
             assertEquals(version, parsedVersion);
             assertEquals(version, parsedVersion);

+ 47 - 0
test/framework/src/main/java/org/elasticsearch/test/TransportVersionUtils.java

@@ -0,0 +1,47 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+package org.elasticsearch.test;
+
+import org.elasticsearch.TransportVersion;
+
+import java.util.NavigableSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class TransportVersionUtils {
+    private static final NavigableSet<TransportVersion> ALL_VERSIONS;
+
+    static {
+        ALL_VERSIONS = TransportVersion.getAllVersions();
+    }
+
+    /** Returns a random {@link TransportVersion} from all available versions. */
+    public static TransportVersion randomVersion() {
+        return ESTestCase.randomFrom(ALL_VERSIONS);
+    }
+
+    /** Returns a random {@link TransportVersion} from all available versions without the ignore set */
+    public static TransportVersion randomVersion(Set<TransportVersion> ignore) {
+        return ESTestCase.randomFrom(ALL_VERSIONS.stream().filter(v -> ignore.contains(v) == false).collect(Collectors.toList()));
+    }
+
+    public static TransportVersion getPreviousVersion() {
+        TransportVersion version = getPreviousVersion(TransportVersion.CURRENT);
+        assert version.before(TransportVersion.CURRENT);
+        return version;
+    }
+
+    public static TransportVersion getPreviousVersion(TransportVersion version) {
+        TransportVersion prev = ALL_VERSIONS.lower(version);
+        if (prev == null) {
+            throw new IllegalArgumentException("couldn't find any released versions before [" + version + "]");
+        }
+        return prev;
+    }
+}