@@ -22,68 +22,126 @@ it could be any arbitrary string.
22
22
23
23
## Transport protocol
24
24
25
- The transport protocol is used to send binary data between Elasticsearch nodes;
26
- ` TransportVersion ` is the version number used for this protocol.
27
- This version number is negotiated between each pair of nodes in the cluster
28
- on first connection, and is set as the lower of the highest transport version
29
- understood by each node.
25
+ The transport protocol is used to send binary data between Elasticsearch nodes; a
26
+ ` TransportVersion ` encapsulates versioning of this protocol.
27
+ This version is negotiated between each pair of nodes in the cluster
28
+ on first connection, selecting the highest shared version.
30
29
This version is then accessible through the ` getTransportVersion ` method
31
30
on ` StreamInput ` and ` StreamOutput ` , so serialization code can read/write
32
31
objects in a form that will be understood by the other node.
33
32
34
- Every change to the transport protocol is represented by a new transport version,
35
- higher than all previous transport versions, which then becomes the highest version
36
- recognized by that build of Elasticsearch. The version ids are stored
37
- as constants in the ` TransportVersions ` class.
38
- Each id has a standard pattern ` M_NNN_S_PP ` , where:
39
- * ` M ` is the major version
40
- * ` NNN ` is an incrementing id
41
- * ` S ` is used in subsidiary repos amending the default transport protocol
42
- * ` PP ` is used for patches and backports
43
-
44
- When you make a change to the serialization form of any object,
45
- you need to create a new sequential constant in ` TransportVersions ` ,
46
- introduced in the same PR that adds the change, that increments
47
- the ` NNN ` component from the previous highest version,
48
- with other components set to zero.
49
- For example, if the previous version number is ` 8_413_0_01 ` ,
50
- the next version number should be ` 8_414_0_00 ` .
51
-
52
- Once you have defined your constant, you then need to use it
53
- in serialization code. If the transport version is at or above the new id,
54
- the modified protocol should be used:
55
-
56
- str = in.readString();
57
- bool = in.readBoolean();
58
- if (in.getTransportVersion().onOrAfter(TransportVersions.NEW_CONSTANT)) {
59
- num = in.readVInt();
60
- }
33
+ At a high level a ` TransportVersion ` contains one id per release branch it will
34
+ be committed to. Each ` TransportVersion ` has a name selected when it is generated.
35
+ In order to ensure consistency and robustness, all new ` TransportVersion ` s
36
+ must first be created in the ` main ` branch and then backported to the relevant
37
+ release branches.
38
+
39
+ ### Internal state files
40
+
41
+ The Elasticsearch server jar contains resource files representing each
42
+ transport version. These files are loaded at runtime to construct
43
+ ` TransportVersion ` instances. Since each transport version has its own file
44
+ they can be backported without conflict.
61
45
62
- If a transport version change needs to be reverted, a ** new** version constant
63
- should be added representing the revert, and the version id checks
64
- adjusted appropriately to only use the modified protocol between the version id
65
- the change was added, and the new version id used for the revert (exclusive).
66
- The ` between ` method can be used for this.
46
+ Additional resource files represent the latest transport version known on
47
+ each release branch. If two transport versions are added at the same time,
48
+ there will be a conflict in these internal state files, forcing one to be
49
+ regenerated to resolve the conflict before merging to ` main ` .
67
50
68
- Once a transport change with a new version has been merged into main or a release branch,
69
- it ** must not** be modified - this is so the meaning of that specific
70
- transport version does not change.
51
+ All of these internal state files are managed by gradle tasks; they should
52
+ not be edited directly.
71
53
72
54
_ Elastic developers_ - please see corresponding documentation for Serverless
73
55
on creating transport versions for Serverless changes.
74
56
75
- ### Collapsing transport versions
57
+ ### Creating transport versions locally
58
+
59
+ To create a transport version, declare a reference anywhere in java code. For example:
60
+
61
+ private static final TransportVersion MY_NEW_TV = TransportVersion.fromName("my_new_tv");
62
+
63
+ ` fromName ` takes an arbitrary String name. The String must be a String literal;
64
+ it cannot be a reference to a String. It must match the regex ` [_0-9a-zA-Z]+ ` .
65
+ You can reference the same transport version name from multiple classes, but
66
+ you must not use an existing transport version name after it as already been
67
+ committed to ` main ` .
68
+
69
+ Once you have declared your ` TransportVersion ` you can use it in serialization code.
70
+ For example, in a constructor that takes ` StreamInput in ` :
71
+
72
+ if (in.getTransportVersion().supports(MY_NEW_TV)) {
73
+ // new serialization code
74
+ }
75
+
76
+ Finally, in order to run Elasticsearch or run tests, the transport version ids
77
+ must be generated. Run the following gradle task:
78
+
79
+ ./gradlew generateTransportVersion
80
+
81
+ This will generate the internal state to support the new transport version. If
82
+ you also intend to backport your code, include branches you will backport to:
83
+
84
+ ./gradlew generateTransportVersion --backport-branches=9.1,8.19
85
+
86
+ ### Updating transport versions
87
+
88
+ You can modify a transport version before it is merged to ` main ` . This includes
89
+ renaming the transport version, updating the branches it will be backported to,
90
+ or even removing the transport version itself.
91
+
92
+ The generation task is idempotent. It can be re-run at any time and will result
93
+ in a valid internal state. For example, if you want to add an additional
94
+ backport branch, re-run the generation task with all the target backport
95
+ branches:
96
+
97
+ ./gradlew generateTransportVersion --backport-branches=9.1,9.0,8.19,8.18
98
+
99
+ You can also let CI handle updating transport versions for you. As version
100
+ labels are updated on your PR, the generation task is automatically run with
101
+ the appropriate backport branches and any changes to the internal state files
102
+ are committed to your branch.
103
+
104
+ Transport versions can also have additional branches added after merging to
105
+ ` main ` . When doing so, you must include all branches the transport version was
106
+ added to in addition to new branch. For example, if you originally committed
107
+ your transport version ` my_tv ` to ` main ` and ` 9.1 ` , and then realized you also
108
+ needed to backport to ` 8.19 ` you would run (in ` main ` ):
109
+
110
+ ./gradlew generateTransportVersion --name=my_tv --backport-branches=9.1,8.19
111
+
112
+ In the above case CI will not know what transport version name to update, so you
113
+ must run the generate task again as described. After merging the updated transport
114
+ version it will need to be backported to all the applicable branches.
115
+
116
+ ### Resolving merge conflicts
76
117
77
- As each change adds a new constant, the list of constants in ` TransportVersions `
78
- will keep growing. However, once there has been an official release of Elasticsearch,
79
- that includes that change, that specific transport version is no longer needed,
80
- apart from constants that happen to be used for release builds.
81
- As part of managing transport versions, consecutive transport versions can be
82
- periodically collapsed together into those that are only used for release builds.
83
- This task is normally performed by Core/Infra on a semi-regular basis,
84
- usually after each new minor release, to collapse the transport versions
85
- for the previous minor release. An example of such an operation can be found
86
- [ here] ( https://github.com/elastic/elasticsearch/pull/104937 ) .
118
+ Transport versions are created sequentially. If two developers create a transport
119
+ version at the same time, based on the same ` main ` commit, they will generate
120
+ the same internal ids. The first of these two merged into ` main ` will "win", and
121
+ the latter will have a merge conflict with ` main ` .
122
+
123
+ In the event of a conflict, merge ` main ` into your branch. You will have
124
+ conflict(s) with transport version internal state files. Run the following
125
+ generate task to resolve the conflict(s):
126
+
127
+ ./gradlew generateTransportVersion --resolve-conflict
128
+
129
+ This command will regenerate your transport version and stage the updated
130
+ state files in git. You can then proceed with your merge as usual.
131
+
132
+ ### Reverting changes
133
+
134
+ Transport versions cannot be removed, they can only be added. If the logic
135
+ using a transport version needs to be reverted, it must be done with a
136
+ new transport version.
137
+
138
+ For example, if you have previously added a transport version named
139
+ ` original_tv ` you could add ` revert_tv ` reversing the logic:
140
+
141
+ TransportVersion tv = in.getTransportVersion();
142
+ if (tv.supports(ORIGINAL_TV) && tv.supports(REVERT_TV) == false) {
143
+ // serialization code being reverted
144
+ }
87
145
88
146
### Minimum compatibility versions
89
147
@@ -114,54 +172,6 @@ is updated automatically as part of performing a release.
114
172
In releases that do not have a release version number, that method becomes
115
173
a no-op.
116
174
117
- ### Managing patches and backports
118
-
119
- Backporting transport version changes to previous releases
120
- should only be done if absolutely necessary, as it is very easy to get wrong
121
- and break the release in a way that is very hard to recover from.
122
-
123
- If we consider the version number as an incrementing line, what we are doing is
124
- grafting a change that takes effect at a certain point in the line,
125
- to additionally take effect in a fixed window earlier in the line.
126
-
127
- To take an example, using indicative version numbers, when the latest
128
- transport version is 52, we decide we need to backport a change done in
129
- transport version 50 to transport version 45. We use the ` P ` version id component
130
- to create version 45.1 with the backported change.
131
- This change will apply for version ids 45.1 to 45.9 (should they exist in the future).
132
-
133
- The serialization code in the backport needs to use the backported protocol
134
- for all version numbers 45.1 to 45.9. The ` TransportVersion.isPatchFrom ` method
135
- can be used to easily determine if this is the case: ` streamVersion.isPatchFrom(45.1) ` .
136
- However, the ` onOrAfter ` also does what is needed on patch branches.
137
-
138
- The serialization code in version 53 then needs to additionally check
139
- version numbers 45.1-45.9 to use the backported protocol, also using the ` isPatchFrom ` method.
140
-
141
- As an example, [ this transport change] ( https://github.com/elastic/elasticsearch/pull/107862 )
142
- was backported from 8.15 to [ 8.14.0] ( https://github.com/elastic/elasticsearch/pull/108251 )
143
- and [ 8.13.4] ( https://github.com/elastic/elasticsearch/pull/108250 ) at the same time
144
- (8.14 was a build candidate at the time).
145
-
146
- The 8.13 PR has:
147
-
148
- if (transportVersion.onOrAfter(8.13_backport_id))
149
-
150
- The 8.14 PR has:
151
-
152
- if (transportVersion.isPatchFrom(8.13_backport_id)
153
- || transportVersion.onOrAfter(8.14_backport_id))
154
-
155
- The 8.15 PR has:
156
-
157
- if (transportVersion.isPatchFrom(8.13_backport_id)
158
- || transportVersion.isPatchFrom(8.14_backport_id)
159
- || transportVersion.onOrAfter(8.15_transport_id))
160
-
161
- In particular, if you are backporting a change to a patch release,
162
- you also need to make sure that any subsequent released version on any branch
163
- also has that change, and knows about the patch backport ids and what they mean.
164
-
165
175
## Index version
166
176
167
177
Index version is a single incrementing version number for the index data format,
0 commit comments