Skip to content

Commit e2bce8e

Browse files
committed
Update to give more preference to operation with outputs
1 parent 6e0f677 commit e2bce8e

3 files changed

Lines changed: 532 additions & 0 deletions

File tree

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.codegen.poet.crac;
17+
18+
import java.util.Arrays;
19+
import java.util.Collections;
20+
import java.util.Comparator;
21+
import java.util.List;
22+
import java.util.Optional;
23+
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
24+
import software.amazon.awssdk.codegen.model.intermediate.MemberModel;
25+
import software.amazon.awssdk.codegen.model.intermediate.OperationModel;
26+
import software.amazon.awssdk.codegen.model.intermediate.ShapeModel;
27+
import software.amazon.awssdk.utils.CollectionUtils;
28+
import software.amazon.awssdk.utils.NumericUtils;
29+
30+
/**
31+
* Selects the operation used for the CRaC warm-up call: filters out streaming/event-stream and deprecated
32+
* operations, then ranks the rest (see {@link #warmUpPreference}).
33+
*/
34+
public final class WarmUpOperationSelector {
35+
36+
private static final List<String> PREFERRED_VERBS = Arrays.asList("List", "Describe", "Get");
37+
38+
private static final Comparator<OperationModel> BY_EMPTY_REQUEST_FIRST =
39+
Comparator.comparing(op -> !acceptsEmptyRequest(op));
40+
41+
private static final Comparator<OperationModel> BY_FEWEST_REQUIRED_INPUTS =
42+
Comparator.comparingInt(WarmUpOperationSelector::requiredInputMemberCount);
43+
44+
private static final Comparator<OperationModel> BY_HAS_OUTPUT_FIRST =
45+
Comparator.comparing(op -> !hasOutput(op));
46+
47+
private static final Comparator<OperationModel> BY_PREFERRED_VERB =
48+
Comparator.comparingInt(WarmUpOperationSelector::verbRank);
49+
50+
private static final Comparator<OperationModel> BY_NAME_ALPHABETICAL =
51+
Comparator.comparing(OperationModel::getOperationName);
52+
53+
private WarmUpOperationSelector() {
54+
}
55+
56+
/**
57+
* Selects the warm-up operation for the given service, or {@link Optional#empty()} if no operation is safe to
58+
* call as a warm-up.
59+
*/
60+
public static Optional<OperationModel> selectWarmUpOperation(IntermediateModel model) {
61+
List<String> verifiedSimpleMethods = model.getCustomizationConfig().getVerifiedSimpleMethods();
62+
Comparator<OperationModel> preference = warmUpPreference(verifiedSimpleMethods);
63+
64+
return model.getOperations().values().stream()
65+
.filter(WarmUpOperationSelector::passesHardGates)
66+
.min(preference);
67+
}
68+
69+
/**
70+
* Preference order: returns output (so the unmarshaller is primed too), verified simple method, accepts an
71+
* empty request, fewest required input members, read-only verb, then operation name as the deterministic
72+
* tie-break.
73+
*/
74+
private static Comparator<OperationModel> warmUpPreference(List<String> verifiedSimpleMethods) {
75+
Comparator<OperationModel> byVerifiedSimpleFirst =
76+
Comparator.comparing(op -> !verifiedSimpleMethods.contains(op.getMethodName()));
77+
78+
return BY_HAS_OUTPUT_FIRST
79+
.thenComparing(byVerifiedSimpleFirst)
80+
.thenComparing(BY_EMPTY_REQUEST_FIRST)
81+
.thenComparing(BY_FEWEST_REQUIRED_INPUTS)
82+
.thenComparing(BY_PREFERRED_VERB)
83+
.thenComparing(BY_NAME_ALPHABETICAL);
84+
}
85+
86+
private static boolean passesHardGates(OperationModel operation) {
87+
return !isStreamingOrEventStream(operation)
88+
&& !operation.isDeprecated();
89+
}
90+
91+
private static boolean isStreamingOrEventStream(OperationModel operation) {
92+
return operation.isStreaming() || operation.hasEventStreamInput() || operation.hasEventStreamOutput();
93+
}
94+
95+
private static boolean acceptsEmptyRequest(OperationModel operation) {
96+
return requiredInputMemberCount(operation) == 0;
97+
}
98+
99+
private static boolean hasOutput(OperationModel operation) {
100+
return operation.getOutputShape() != null;
101+
}
102+
103+
private static int requiredInputMemberCount(OperationModel operation) {
104+
return NumericUtils.saturatedCast(inputMembers(operation).stream().filter(MemberModel::isRequired).count());
105+
}
106+
107+
private static List<MemberModel> inputMembers(OperationModel operation) {
108+
ShapeModel inputShape = operation.getInputShape();
109+
if (inputShape == null || CollectionUtils.isNullOrEmpty(inputShape.getMembers())) {
110+
return Collections.emptyList();
111+
}
112+
return inputShape.getMembers();
113+
}
114+
115+
private static int verbRank(OperationModel operation) {
116+
String operationName = operation.getOperationName();
117+
for (int i = 0; i < PREFERRED_VERBS.size(); i++) {
118+
if (operationName.startsWith(PREFERRED_VERBS.get(i))) {
119+
return i;
120+
}
121+
}
122+
return Integer.MAX_VALUE;
123+
}
124+
}

0 commit comments

Comments
 (0)