Version.java 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. /*
  2. * Licensed to Elasticsearch under one or more contributor
  3. * license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright
  5. * ownership. Elasticsearch licenses this file to you under
  6. * the Apache License, Version 2.0 (the "License"); you may
  7. * not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. package org.elasticsearch;
  20. import org.elasticsearch.cluster.metadata.IndexMetaData;
  21. import org.elasticsearch.common.Strings;
  22. import org.elasticsearch.common.SuppressForbidden;
  23. import org.elasticsearch.common.io.stream.StreamInput;
  24. import org.elasticsearch.common.io.stream.StreamOutput;
  25. import org.elasticsearch.common.settings.Settings;
  26. import org.elasticsearch.common.xcontent.ToXContentFragment;
  27. import org.elasticsearch.common.xcontent.XContentBuilder;
  28. import org.elasticsearch.monitor.jvm.JvmInfo;
  29. import java.io.IOException;
  30. import java.lang.reflect.Field;
  31. import java.lang.reflect.Modifier;
  32. import java.util.ArrayList;
  33. import java.util.Collections;
  34. import java.util.List;
  35. import java.util.Locale;
  36. public class Version implements Comparable<Version>, ToXContentFragment {
  37. /*
  38. * The logic for ID is: XXYYZZAA, where XX is major version, YY is minor version, ZZ is revision, and AA is alpha/beta/rc indicator AA
  39. * values below 25 are for alpha builder (since 5.0), and above 25 and below 50 are beta builds, and below 99 are RC builds, with 99
  40. * indicating a release the (internal) format of the id is there so we can easily do after/before checks on the id
  41. */
  42. public static final int V_EMPTY_ID = 0;
  43. public static final Version V_EMPTY = new Version(V_EMPTY_ID, org.apache.lucene.util.Version.LATEST);
  44. public static final int V_6_0_0_alpha1_ID = 6000001;
  45. public static final Version V_6_0_0_alpha1 =
  46. new Version(V_6_0_0_alpha1_ID, org.apache.lucene.util.Version.LUCENE_7_0_0);
  47. public static final int V_6_0_0_alpha2_ID = 6000002;
  48. public static final Version V_6_0_0_alpha2 =
  49. new Version(V_6_0_0_alpha2_ID, org.apache.lucene.util.Version.LUCENE_7_0_0);
  50. public static final int V_6_0_0_beta1_ID = 6000026;
  51. public static final Version V_6_0_0_beta1 =
  52. new Version(V_6_0_0_beta1_ID, org.apache.lucene.util.Version.LUCENE_7_0_0);
  53. public static final int V_6_0_0_beta2_ID = 6000027;
  54. public static final Version V_6_0_0_beta2 =
  55. new Version(V_6_0_0_beta2_ID, org.apache.lucene.util.Version.LUCENE_7_0_0);
  56. public static final int V_6_0_0_rc1_ID = 6000051;
  57. public static final Version V_6_0_0_rc1 =
  58. new Version(V_6_0_0_rc1_ID, org.apache.lucene.util.Version.LUCENE_7_0_0);
  59. public static final int V_6_0_0_rc2_ID = 6000052;
  60. public static final Version V_6_0_0_rc2 =
  61. new Version(V_6_0_0_rc2_ID, org.apache.lucene.util.Version.LUCENE_7_0_1);
  62. public static final int V_6_0_0_ID = 6000099;
  63. public static final Version V_6_0_0 =
  64. new Version(V_6_0_0_ID, org.apache.lucene.util.Version.LUCENE_7_0_1);
  65. public static final int V_6_0_1_ID = 6000199;
  66. public static final Version V_6_0_1 =
  67. new Version(V_6_0_1_ID, org.apache.lucene.util.Version.LUCENE_7_0_1);
  68. public static final int V_6_1_0_ID = 6010099;
  69. public static final Version V_6_1_0 = new Version(V_6_1_0_ID, org.apache.lucene.util.Version.LUCENE_7_1_0);
  70. public static final int V_6_1_1_ID = 6010199;
  71. public static final Version V_6_1_1 = new Version(V_6_1_1_ID, org.apache.lucene.util.Version.LUCENE_7_1_0);
  72. public static final int V_6_1_2_ID = 6010299;
  73. public static final Version V_6_1_2 = new Version(V_6_1_2_ID, org.apache.lucene.util.Version.LUCENE_7_1_0);
  74. public static final int V_6_1_3_ID = 6010399;
  75. public static final Version V_6_1_3 = new Version(V_6_1_3_ID, org.apache.lucene.util.Version.LUCENE_7_1_0);
  76. public static final int V_6_1_4_ID = 6010499;
  77. public static final Version V_6_1_4 = new Version(V_6_1_4_ID, org.apache.lucene.util.Version.LUCENE_7_1_0);
  78. // The below version is missing from the 7.3 JAR
  79. private static final org.apache.lucene.util.Version LUCENE_7_2_1 = org.apache.lucene.util.Version.fromBits(7, 2, 1);
  80. public static final int V_6_2_0_ID = 6020099;
  81. public static final Version V_6_2_0 = new Version(V_6_2_0_ID, LUCENE_7_2_1);
  82. public static final int V_6_2_1_ID = 6020199;
  83. public static final Version V_6_2_1 = new Version(V_6_2_1_ID, LUCENE_7_2_1);
  84. public static final int V_6_2_2_ID = 6020299;
  85. public static final Version V_6_2_2 = new Version(V_6_2_2_ID, LUCENE_7_2_1);
  86. public static final int V_6_2_3_ID = 6020399;
  87. public static final Version V_6_2_3 = new Version(V_6_2_3_ID, LUCENE_7_2_1);
  88. public static final int V_6_2_4_ID = 6020499;
  89. public static final Version V_6_2_4 = new Version(V_6_2_4_ID, LUCENE_7_2_1);
  90. public static final int V_6_3_0_ID = 6030099;
  91. public static final Version V_6_3_0 = new Version(V_6_3_0_ID, org.apache.lucene.util.Version.LUCENE_7_3_1);
  92. public static final int V_6_3_1_ID = 6030199;
  93. public static final Version V_6_3_1 = new Version(V_6_3_1_ID, org.apache.lucene.util.Version.LUCENE_7_3_1);
  94. public static final int V_6_3_2_ID = 6030299;
  95. public static final Version V_6_3_2 = new Version(V_6_3_2_ID, org.apache.lucene.util.Version.LUCENE_7_3_1);
  96. public static final int V_6_4_0_ID = 6040099;
  97. public static final Version V_6_4_0 = new Version(V_6_4_0_ID, org.apache.lucene.util.Version.LUCENE_7_4_0);
  98. public static final int V_6_4_1_ID = 6040199;
  99. public static final Version V_6_4_1 = new Version(V_6_4_1_ID, org.apache.lucene.util.Version.LUCENE_7_4_0);
  100. public static final int V_6_4_2_ID = 6040299;
  101. public static final Version V_6_4_2 = new Version(V_6_4_2_ID, org.apache.lucene.util.Version.LUCENE_7_4_0);
  102. public static final int V_6_4_3_ID = 6040399;
  103. public static final Version V_6_4_3 = new Version(V_6_4_3_ID, org.apache.lucene.util.Version.LUCENE_7_4_0);
  104. public static final int V_6_5_0_ID = 6050099;
  105. public static final Version V_6_5_0 = new Version(V_6_5_0_ID, org.apache.lucene.util.Version.LUCENE_7_5_0);
  106. public static final int V_6_6_0_ID = 6060099;
  107. public static final Version V_6_6_0 = new Version(V_6_6_0_ID, org.apache.lucene.util.Version.LUCENE_7_5_0);
  108. public static final int V_7_0_0_alpha1_ID = 7000001;
  109. public static final Version V_7_0_0_alpha1 =
  110. new Version(V_7_0_0_alpha1_ID, org.apache.lucene.util.Version.LUCENE_8_0_0);
  111. public static final Version CURRENT = V_7_0_0_alpha1;
  112. static {
  113. assert CURRENT.luceneVersion.equals(org.apache.lucene.util.Version.LATEST) : "Version must be upgraded to ["
  114. + org.apache.lucene.util.Version.LATEST + "] is still set to [" + CURRENT.luceneVersion + "]";
  115. }
  116. public static Version readVersion(StreamInput in) throws IOException {
  117. return fromId(in.readVInt());
  118. }
  119. public static Version fromId(int id) {
  120. switch (id) {
  121. case V_7_0_0_alpha1_ID:
  122. return V_7_0_0_alpha1;
  123. case V_6_6_0_ID:
  124. return V_6_6_0;
  125. case V_6_5_0_ID:
  126. return V_6_5_0;
  127. case V_6_4_3_ID:
  128. return V_6_4_3;
  129. case V_6_4_2_ID:
  130. return V_6_4_2;
  131. case V_6_4_1_ID:
  132. return V_6_4_1;
  133. case V_6_4_0_ID:
  134. return V_6_4_0;
  135. case V_6_3_2_ID:
  136. return V_6_3_2;
  137. case V_6_3_1_ID:
  138. return V_6_3_1;
  139. case V_6_3_0_ID:
  140. return V_6_3_0;
  141. case V_6_2_4_ID:
  142. return V_6_2_4;
  143. case V_6_2_3_ID:
  144. return V_6_2_3;
  145. case V_6_2_2_ID:
  146. return V_6_2_2;
  147. case V_6_2_1_ID:
  148. return V_6_2_1;
  149. case V_6_2_0_ID:
  150. return V_6_2_0;
  151. case V_6_1_4_ID:
  152. return V_6_1_4;
  153. case V_6_1_3_ID:
  154. return V_6_1_3;
  155. case V_6_1_2_ID:
  156. return V_6_1_2;
  157. case V_6_1_1_ID:
  158. return V_6_1_1;
  159. case V_6_1_0_ID:
  160. return V_6_1_0;
  161. case V_6_0_1_ID:
  162. return V_6_0_1;
  163. case V_6_0_0_ID:
  164. return V_6_0_0;
  165. case V_6_0_0_rc2_ID:
  166. return V_6_0_0_rc2;
  167. case V_6_0_0_beta2_ID:
  168. return V_6_0_0_beta2;
  169. case V_6_0_0_rc1_ID:
  170. return V_6_0_0_rc1;
  171. case V_6_0_0_beta1_ID:
  172. return V_6_0_0_beta1;
  173. case V_6_0_0_alpha2_ID:
  174. return V_6_0_0_alpha2;
  175. case V_6_0_0_alpha1_ID:
  176. return V_6_0_0_alpha1;
  177. case V_EMPTY_ID:
  178. return V_EMPTY;
  179. default:
  180. return new Version(id, org.apache.lucene.util.Version.LATEST);
  181. }
  182. }
  183. /**
  184. * Return the {@link Version} of Elasticsearch that has been used to create an index given its settings.
  185. *
  186. * @throws IllegalStateException if the given index settings doesn't contain a value for the key
  187. * {@value IndexMetaData#SETTING_VERSION_CREATED}
  188. */
  189. public static Version indexCreated(Settings indexSettings) {
  190. final Version indexVersion = IndexMetaData.SETTING_INDEX_VERSION_CREATED.get(indexSettings);
  191. if (indexVersion == V_EMPTY) {
  192. final String message = String.format(
  193. Locale.ROOT,
  194. "[%s] is not present in the index settings for index with UUID [%s]",
  195. IndexMetaData.SETTING_INDEX_VERSION_CREATED.getKey(),
  196. indexSettings.get(IndexMetaData.SETTING_INDEX_UUID));
  197. throw new IllegalStateException(message);
  198. }
  199. return indexVersion;
  200. }
  201. public static void writeVersion(Version version, StreamOutput out) throws IOException {
  202. out.writeVInt(version.id);
  203. }
  204. /**
  205. * Returns the minimum version between the 2.
  206. */
  207. public static Version min(Version version1, Version version2) {
  208. return version1.id < version2.id ? version1 : version2;
  209. }
  210. /**
  211. * Returns the maximum version between the 2
  212. */
  213. public static Version max(Version version1, Version version2) { return version1.id > version2.id ? version1 : version2; }
  214. /**
  215. * Returns the version given its string representation, current version if the argument is null or empty
  216. */
  217. public static Version fromString(String version) {
  218. if (!Strings.hasLength(version)) {
  219. return Version.CURRENT;
  220. }
  221. final boolean snapshot; // this is some BWC for 2.x and before indices
  222. if (snapshot = version.endsWith("-SNAPSHOT")) {
  223. version = version.substring(0, version.length() - 9);
  224. }
  225. String[] parts = version.split("[.-]");
  226. if (parts.length < 3 || parts.length > 4) {
  227. throw new IllegalArgumentException(
  228. "the version needs to contain major, minor, and revision, and optionally the build: " + version);
  229. }
  230. try {
  231. final int rawMajor = Integer.parseInt(parts[0]);
  232. if (rawMajor >= 5 && snapshot) { // we don't support snapshot as part of the version here anymore
  233. throw new IllegalArgumentException("illegal version format - snapshots are only supported until version 2.x");
  234. }
  235. final int betaOffset = rawMajor < 5 ? 0 : 25;
  236. //we reverse the version id calculation based on some assumption as we can't reliably reverse the modulo
  237. final int major = rawMajor * 1000000;
  238. final int minor = Integer.parseInt(parts[1]) * 10000;
  239. final int revision = Integer.parseInt(parts[2]) * 100;
  240. int build = 99;
  241. if (parts.length == 4) {
  242. String buildStr = parts[3];
  243. if (buildStr.startsWith("alpha")) {
  244. assert rawMajor >= 5 : "major must be >= 5 but was " + major;
  245. build = Integer.parseInt(buildStr.substring(5));
  246. assert build < 25 : "expected a beta build but " + build + " >= 25";
  247. } else if (buildStr.startsWith("Beta") || buildStr.startsWith("beta")) {
  248. build = betaOffset + Integer.parseInt(buildStr.substring(4));
  249. assert build < 50 : "expected a beta build but " + build + " >= 50";
  250. } else if (buildStr.startsWith("RC") || buildStr.startsWith("rc")) {
  251. build = Integer.parseInt(buildStr.substring(2)) + 50;
  252. } else {
  253. throw new IllegalArgumentException("unable to parse version " + version);
  254. }
  255. }
  256. return fromId(major + minor + revision + build);
  257. } catch (NumberFormatException e) {
  258. throw new IllegalArgumentException("unable to parse version " + version, e);
  259. }
  260. }
  261. public final int id;
  262. public final byte major;
  263. public final byte minor;
  264. public final byte revision;
  265. public final byte build;
  266. public final org.apache.lucene.util.Version luceneVersion;
  267. Version(int id, org.apache.lucene.util.Version luceneVersion) {
  268. this.id = id;
  269. this.major = (byte) ((id / 1000000) % 100);
  270. this.minor = (byte) ((id / 10000) % 100);
  271. this.revision = (byte) ((id / 100) % 100);
  272. this.build = (byte) (id % 100);
  273. this.luceneVersion = luceneVersion;
  274. }
  275. public boolean after(Version version) {
  276. return version.id < id;
  277. }
  278. public boolean onOrAfter(Version version) {
  279. return version.id <= id;
  280. }
  281. public boolean before(Version version) {
  282. return version.id > id;
  283. }
  284. public boolean onOrBefore(Version version) {
  285. return version.id >= id;
  286. }
  287. @Override
  288. public int compareTo(Version other) {
  289. return Integer.compare(this.id, other.id);
  290. }
  291. @Override
  292. public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
  293. return builder.value(toString());
  294. }
  295. /*
  296. * We need the declared versions when computing the minimum compatibility version. As computing the declared versions uses reflection it
  297. * is not cheap. Since computing the minimum compatibility version can occur often, we use this holder to compute the declared versions
  298. * lazily once.
  299. */
  300. private static class DeclaredVersionsHolder {
  301. static final List<Version> DECLARED_VERSIONS = Collections.unmodifiableList(getDeclaredVersions(Version.class));
  302. }
  303. /**
  304. * Returns the minimum compatible version based on the current
  305. * version. Ie a node needs to have at least the return version in order
  306. * to communicate with a node running the current version. The returned version
  307. * is in most of the cases the smallest major version release unless the current version
  308. * is a beta or RC release then the version itself is returned.
  309. */
  310. public Version minimumCompatibilityVersion() {
  311. if (major == 6) {
  312. // force the minimum compatibility for version 6 to 5.6 since we don't reference version 5 anymore
  313. return Version.fromId(5060099);
  314. } else if (major >= 7) {
  315. // all major versions from 7 onwards are compatible with last minor series of the previous major
  316. Version bwcVersion = null;
  317. for (int i = DeclaredVersionsHolder.DECLARED_VERSIONS.size() - 1; i >= 0; i--) {
  318. final Version candidateVersion = DeclaredVersionsHolder.DECLARED_VERSIONS.get(i);
  319. if (candidateVersion.major == major - 1 && candidateVersion.isRelease() && after(candidateVersion)) {
  320. if (bwcVersion != null && candidateVersion.minor < bwcVersion.minor) {
  321. break;
  322. }
  323. bwcVersion = candidateVersion;
  324. }
  325. }
  326. return bwcVersion == null ? this : bwcVersion;
  327. }
  328. return Version.min(this, fromId((int) major * 1000000 + 0 * 10000 + 99));
  329. }
  330. /**
  331. * Returns the minimum created index version that this version supports. Indices created with lower versions
  332. * can't be used with this version. This should also be used for file based serialization backwards compatibility ie. on serialization
  333. * code that is used to read / write file formats like transaction logs, cluster state, and index metadata.
  334. */
  335. public Version minimumIndexCompatibilityVersion() {
  336. final int bwcMajor;
  337. if (major == 5) {
  338. bwcMajor = 2; // we jumped from 2 to 5
  339. } else if (major == 7) {
  340. return V_6_0_0_beta1;
  341. } else {
  342. bwcMajor = major - 1;
  343. }
  344. final int bwcMinor = 0;
  345. return Version.min(this, fromId(bwcMajor * 1000000 + bwcMinor * 10000 + 99));
  346. }
  347. /**
  348. * Returns <code>true</code> iff both version are compatible. Otherwise <code>false</code>
  349. */
  350. public boolean isCompatible(Version version) {
  351. boolean compatible = onOrAfter(version.minimumCompatibilityVersion())
  352. && version.onOrAfter(minimumCompatibilityVersion());
  353. assert compatible == false || Math.max(major, version.major) - Math.min(major, version.major) <= 1;
  354. return compatible;
  355. }
  356. @SuppressForbidden(reason = "System.out.*")
  357. public static void main(String[] args) {
  358. final String versionOutput = String.format(
  359. Locale.ROOT,
  360. "Version: %s, Build: %s/%s/%s/%s, JVM: %s",
  361. Version.displayVersion(Version.CURRENT, Build.CURRENT.isSnapshot()),
  362. Build.CURRENT.flavor().displayName(),
  363. Build.CURRENT.type().displayName(),
  364. Build.CURRENT.shortHash(),
  365. Build.CURRENT.date(),
  366. JvmInfo.jvmInfo().version());
  367. System.out.println(versionOutput);
  368. }
  369. @Override
  370. public String toString() {
  371. StringBuilder sb = new StringBuilder();
  372. sb.append(major).append('.').append(minor).append('.').append(revision);
  373. if (isAlpha()) {
  374. sb.append("-alpha");
  375. sb.append(build);
  376. } else if (isBeta()) {
  377. if (major >= 2) {
  378. sb.append("-beta");
  379. } else {
  380. sb.append(".Beta");
  381. }
  382. sb.append(major < 5 ? build : build-25);
  383. } else if (build < 99) {
  384. if (major >= 2) {
  385. sb.append("-rc");
  386. } else {
  387. sb.append(".RC");
  388. }
  389. sb.append(build - 50);
  390. }
  391. return sb.toString();
  392. }
  393. public static String displayVersion(final Version version, final boolean isSnapshot) {
  394. return version + (isSnapshot ? "-SNAPSHOT" : "");
  395. }
  396. @Override
  397. public boolean equals(Object o) {
  398. if (this == o) {
  399. return true;
  400. }
  401. if (o == null || getClass() != o.getClass()) {
  402. return false;
  403. }
  404. Version version = (Version) o;
  405. if (id != version.id) {
  406. return false;
  407. }
  408. return true;
  409. }
  410. @Override
  411. public int hashCode() {
  412. return id;
  413. }
  414. public boolean isBeta() {
  415. return major < 5 ? build < 50 : build >= 25 && build < 50;
  416. }
  417. /**
  418. * Returns true iff this version is an alpha version
  419. * Note: This has been introduced in elasticsearch version 5. Previous versions will never
  420. * have an alpha version.
  421. */
  422. public boolean isAlpha() {
  423. return major < 5 ? false : build < 25;
  424. }
  425. public boolean isRC() {
  426. return build > 50 && build < 99;
  427. }
  428. public boolean isRelease() {
  429. return build == 99;
  430. }
  431. /**
  432. * Extracts a sorted list of declared version constants from a class.
  433. * The argument would normally be Version.class but is exposed for
  434. * testing with other classes-containing-version-constants.
  435. */
  436. public static List<Version> getDeclaredVersions(final Class<?> versionClass) {
  437. final Field[] fields = versionClass.getFields();
  438. final List<Version> versions = new ArrayList<>(fields.length);
  439. for (final Field field : fields) {
  440. final int mod = field.getModifiers();
  441. if (false == Modifier.isStatic(mod) && Modifier.isFinal(mod) && Modifier.isPublic(mod)) {
  442. continue;
  443. }
  444. if (field.getType() != Version.class) {
  445. continue;
  446. }
  447. switch (field.getName()) {
  448. case "CURRENT":
  449. case "V_EMPTY":
  450. continue;
  451. }
  452. assert field.getName().matches("V(_\\d+)+(_(alpha|beta|rc)\\d+)?") : field.getName();
  453. try {
  454. versions.add(((Version) field.get(null)));
  455. } catch (final IllegalAccessException e) {
  456. throw new RuntimeException(e);
  457. }
  458. }
  459. Collections.sort(versions);
  460. return versions;
  461. }
  462. }