Skip to content

Commit 3d1b73b

Browse files
committed
Allow resolveTransportVersionConflict to run without compilation (elastic#140851)
Transport version generation relies on finding uses of `TransportVersion.fromName` to identify the definition name to generate. In the case of resolving a merge conflict, a definition has already been generated, and the merge base is used to find differences in definition files. So in the resolve conflict case, we don't actually need to find uses of `TransportVersion.fromName`, and thus don't need compilation. This commit moves most of the logic from the generate task into a base class, which is then specialized by the normal generation task and the resolve conflict task. By avoiding compilation running resolveTransportVersionConflict should be much faster, and can run even if there are other merge conflicts which may break compilation. relates ES-14006
1 parent 18dbb77 commit 3d1b73b

File tree

4 files changed

+289
-189
lines changed

4 files changed

+289
-189
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.gradle.internal.transport;
11+
12+
import org.elasticsearch.gradle.internal.transport.TransportVersionResourcesService.IdAndDefinition;
13+
import org.gradle.api.DefaultTask;
14+
import org.gradle.api.file.RegularFileProperty;
15+
import org.gradle.api.provider.Property;
16+
import org.gradle.api.services.ServiceReference;
17+
import org.gradle.api.tasks.Input;
18+
import org.gradle.api.tasks.InputFile;
19+
import org.gradle.api.tasks.Optional;
20+
import org.gradle.api.tasks.TaskAction;
21+
import org.gradle.api.tasks.options.Option;
22+
23+
import java.io.IOException;
24+
import java.nio.charset.StandardCharsets;
25+
import java.nio.file.Files;
26+
import java.nio.file.Path;
27+
import java.util.ArrayList;
28+
import java.util.Collections;
29+
import java.util.List;
30+
import java.util.Map;
31+
import java.util.Set;
32+
33+
public abstract class AbstractGenerateTransportVersionDefinitionTask extends DefaultTask {
34+
35+
@ServiceReference("transportVersionResources")
36+
abstract Property<TransportVersionResourcesService> getResourceService();
37+
38+
@Input
39+
@Optional
40+
@Option(option = "increment", description = "The amount to increment the id from the current upper bounds file by")
41+
public abstract Property<Integer> getIncrement();
42+
43+
/**
44+
* The name of the upper bounds file which will be used at runtime on the current branch. Normally
45+
* this equates to VersionProperties.getElasticsearchVersion().
46+
*/
47+
@Input
48+
public abstract Property<String> getCurrentUpperBoundName();
49+
50+
/**
51+
* An additional upper bound file that will be consulted when generating a transport version.
52+
* The larger of this and the current upper bound will be used to create the new primary id.
53+
*/
54+
@InputFile
55+
@Optional
56+
public abstract RegularFileProperty getAlternateUpperBoundFile();
57+
58+
protected abstract void runGeneration(TransportVersionResourcesService resources, List<TransportVersionUpperBound> upstreamUpperBounds)
59+
throws IOException;
60+
61+
protected abstract Set<String> getTargetUpperBoundNames(
62+
TransportVersionResourcesService resources,
63+
List<TransportVersionUpperBound> upstreamUpperBounds,
64+
String targetDefinitionName
65+
) throws IOException;
66+
67+
protected abstract void writeUpperBound(TransportVersionResourcesService resources, TransportVersionUpperBound newUpperBound)
68+
throws IOException;
69+
70+
@TaskAction
71+
public void run() throws IOException {
72+
TransportVersionResourcesService resources = getResourceService().get();
73+
List<TransportVersionUpperBound> upstreamUpperBounds = resources.getUpperBoundsFromGitBase();
74+
boolean onReleaseBranch = resources.checkIfDefinitelyOnReleaseBranch(upstreamUpperBounds, getCurrentUpperBoundName().get());
75+
if (onReleaseBranch) {
76+
throw new IllegalArgumentException("Transport version generation cannot run on release branches");
77+
}
78+
79+
runGeneration(resources, upstreamUpperBounds);
80+
}
81+
82+
protected void generateTransportVersionDefinition(
83+
TransportVersionResourcesService resources,
84+
String targetDefinitionName,
85+
List<TransportVersionUpperBound> upstreamUpperBounds,
86+
Map<Integer, List<IdAndDefinition>> idsByBase
87+
) throws IOException {
88+
getLogger().lifecycle("Generating transport version name: " + targetDefinitionName);
89+
90+
Set<String> targetUpperBoundNames = getTargetUpperBoundNames(resources, upstreamUpperBounds, targetDefinitionName);
91+
92+
List<TransportVersionId> ids = updateUpperBounds(
93+
resources,
94+
upstreamUpperBounds,
95+
targetUpperBoundNames,
96+
idsByBase,
97+
targetDefinitionName
98+
);
99+
// (Re)write the definition file.
100+
resources.writeDefinition(new TransportVersionDefinition(targetDefinitionName, ids, true));
101+
}
102+
103+
private List<TransportVersionId> updateUpperBounds(
104+
TransportVersionResourcesService resources,
105+
List<TransportVersionUpperBound> existingUpperBounds,
106+
Set<String> targetUpperBoundNames,
107+
Map<Integer, List<IdAndDefinition>> idsByBase,
108+
String definitionName
109+
) throws IOException {
110+
String currentUpperBoundName = getCurrentUpperBoundName().get();
111+
int increment = getIncrement().get();
112+
if (increment <= 0) {
113+
throw new IllegalArgumentException("Invalid increment " + increment + ", must be a positive integer");
114+
}
115+
if (increment > 1000) {
116+
throw new IllegalArgumentException("Invalid increment " + increment + ", must be no larger than 1000");
117+
}
118+
List<TransportVersionId> ids = new ArrayList<>();
119+
120+
TransportVersionDefinition existingDefinition = resources.getReferableDefinitionFromGitBase(definitionName);
121+
for (TransportVersionUpperBound existingUpperBound : existingUpperBounds) {
122+
String upperBoundName = existingUpperBound.name();
123+
124+
if (targetUpperBoundNames.contains(upperBoundName)) {
125+
// Case: targeting this upper bound, find an existing id if it exists
126+
TransportVersionId targetId = maybeGetExistingId(existingUpperBound, existingDefinition, definitionName);
127+
if (targetId == null) {
128+
// Case: an id doesn't yet exist for this upper bound, so create one
129+
int targetIncrement = upperBoundName.equals(currentUpperBoundName) ? increment : 1;
130+
targetId = createTargetId(existingUpperBound, targetIncrement);
131+
var newUpperBound = new TransportVersionUpperBound(upperBoundName, definitionName, targetId);
132+
writeUpperBound(resources, newUpperBound);
133+
}
134+
ids.add(targetId);
135+
} else if (resources.getChangedUpperBoundNames().contains(upperBoundName)) {
136+
// Default case: we're not targeting this branch so reset it
137+
resetUpperBound(resources, existingUpperBound, idsByBase, definitionName);
138+
}
139+
}
140+
141+
Collections.sort(ids);
142+
return ids;
143+
}
144+
145+
private void resetUpperBound(
146+
TransportVersionResourcesService resources,
147+
TransportVersionUpperBound upperBound,
148+
Map<Integer, List<IdAndDefinition>> idsByBase,
149+
String ignoreDefinitionName
150+
) throws IOException {
151+
List<IdAndDefinition> idsForUpperBound = idsByBase.get(upperBound.definitionId().base());
152+
if (idsForUpperBound == null) {
153+
throw new RuntimeException("Could not find base id: " + upperBound.definitionId().base());
154+
}
155+
IdAndDefinition resetValue = idsForUpperBound.getLast();
156+
if (resetValue.definition().name().equals(ignoreDefinitionName)) {
157+
// there must be another definition in this base since the ignored definition is new
158+
assert idsForUpperBound.size() >= 2;
159+
resetValue = idsForUpperBound.get(idsForUpperBound.size() - 2);
160+
}
161+
var resetUpperBound = new TransportVersionUpperBound(upperBound.name(), resetValue.definition().name(), resetValue.id());
162+
resources.writeUpperBound(resetUpperBound, false);
163+
}
164+
165+
private TransportVersionId maybeGetExistingId(
166+
TransportVersionUpperBound upperBound,
167+
TransportVersionDefinition existingDefinition,
168+
String name
169+
) {
170+
if (existingDefinition == null) {
171+
// the name doesn't yet exist, so there is no id to return
172+
return null;
173+
}
174+
if (upperBound.definitionName().equals(name)) {
175+
// the name exists and this upper bound already points at it
176+
return upperBound.definitionId();
177+
}
178+
if (upperBound.name().equals(getCurrentUpperBoundName().get())) {
179+
// this is the upper bound of the current branch, so use the primary id
180+
return existingDefinition.ids().getFirst();
181+
}
182+
// the upper bound is for a non-current branch, so find the id with the same base
183+
for (TransportVersionId id : existingDefinition.ids()) {
184+
if (id.base() == upperBound.definitionId().base()) {
185+
return id;
186+
}
187+
}
188+
return null; // no existing id for this upper bound
189+
}
190+
191+
private TransportVersionId createTargetId(TransportVersionUpperBound existingUpperBound, int increment) throws IOException {
192+
int currentId = existingUpperBound.definitionId().complete();
193+
194+
// allow for an alternate upper bound file to be consulted. This supports Serverless basing its
195+
// own transport version ids on the greater of server or serverless
196+
if (getAlternateUpperBoundFile().isPresent()) {
197+
Path altUpperBoundPath = getAlternateUpperBoundFile().get().getAsFile().toPath();
198+
String contents = Files.readString(altUpperBoundPath, StandardCharsets.UTF_8);
199+
var altUpperBound = TransportVersionUpperBound.fromString(altUpperBoundPath, contents);
200+
if (altUpperBound.definitionId().complete() > currentId) {
201+
currentId = altUpperBound.definitionId().complete();
202+
}
203+
}
204+
205+
return TransportVersionId.fromInt(currentId + increment);
206+
}
207+
}

0 commit comments

Comments
 (0)