Skip to content

Various performance improvements. #3178

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions build-tools/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
</configuration>
</plugin>
</plugins>

</build>

<dependencies>
Expand All @@ -68,6 +69,11 @@
<artifactId>checkstyle</artifactId>
<version>8.42</version>
</dependency>
<dependency>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs</artifactId>
<version>4.2.3</version>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package software.amazon.awssdk.buildtools.findbugs;

import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.BugReporter;
import edu.umd.cs.findbugs.ba.SignatureParser;
import edu.umd.cs.findbugs.bcel.OpcodeStackDetector;
import edu.umd.cs.findbugs.classfile.MethodDescriptor;
import java.util.AbstractMap.SimpleEntry;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.bcel.Const;

/**
* Blocks usage of disallowed methods in the SDK.
*/
public class DisallowMethodCall extends OpcodeStackDetector {
private static final Set<Entry<String, String>> PROHIBITED_METHODS = new HashSet<>();
private final BugReporter bugReporter;

static {
PROHIBITED_METHODS.add(new SimpleEntry<>("software/amazon/awssdk/http/SdkHttpHeaders", "headers"));
PROHIBITED_METHODS.add(new SimpleEntry<>("software/amazon/awssdk/http/SdkHttpResponse", "headers"));
PROHIBITED_METHODS.add(new SimpleEntry<>("software/amazon/awssdk/http/SdkHttpRequest", "headers"));
PROHIBITED_METHODS.add(new SimpleEntry<>("software/amazon/awssdk/http/SdkHttpFullRequest", "headers"));
PROHIBITED_METHODS.add(new SimpleEntry<>("software/amazon/awssdk/http/SdkHttpFullResponse", "headers"));
PROHIBITED_METHODS.add(new SimpleEntry<>("software/amazon/awssdk/http/SdkHttpFullRequest$Builder", "headers"));
PROHIBITED_METHODS.add(new SimpleEntry<>("software/amazon/awssdk/http/SdkHttpFullResponse$Builder", "headers"));
PROHIBITED_METHODS.add(new SimpleEntry<>("software/amazon/awssdk/http/SdkHttpRequest", "rawQueryParameters"));
PROHIBITED_METHODS.add(new SimpleEntry<>("software/amazon/awssdk/http/SdkHttpFullRequest", "rawQueryParameters"));
PROHIBITED_METHODS.add(new SimpleEntry<>("software/amazon/awssdk/http/SdkHttpFullRequest$Builder", "rawQueryParameters"));
}

public DisallowMethodCall(BugReporter bugReporter) {
this.bugReporter = bugReporter;
}

@Override
public void sawOpcode(int code) {
switch (code) {
case Const.INVOKEVIRTUAL:
case Const.INVOKESPECIAL:
case Const.INVOKESTATIC:
case Const.INVOKEINTERFACE:
handleMethodCall(code);
return;
default:
// Ignore - not a method call.
}
}

private void handleMethodCall(int code) {
MethodDescriptor method = getMethodDescriptorOperand();
SignatureParser signature = new SignatureParser(method.getSignature());
Entry<String, String> calledMethod = new SimpleEntry<>(method.getSlashedClassName(), method.getName());
if (PROHIBITED_METHODS.contains(calledMethod) && signature.getNumParameters() == 0) {
bugReporter.reportBug(new BugInstance(this, "SDK_BAD_METHOD_CALL", NORMAL_PRIORITY)
.addClassAndMethod(this)
.addSourceLine(this, getPC()));
}
}
}
19 changes: 19 additions & 0 deletions build-tools/src/main/resources/findbugs.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!--
~ Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
~
~ Licensed under the Apache License, Version 2.0 (the "License").
~ You may not use this file except in compliance with the License.
~ A copy of the License is located at
~
~ http://aws.amazon.com/apache2.0
~
~ or in the "license" file accompanying this file. This file is distributed
~ on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
~ express or implied. See the License for the specific language governing
~ permissions and limitations under the License.
-->

<FindbugsPlugin>
<Detector class="software.amazon.awssdk.buildtools.findbugs.DisallowMethodCall" speed="fast" />
<BugPattern abbrev="BM" type="SDK_BAD_METHOD_CALL" category="PERFORMANCE" />
</FindbugsPlugin>
46 changes: 46 additions & 0 deletions build-tools/src/main/resources/messages.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!--
~ Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
~
~ Licensed under the Apache License, Version 2.0 (the "License").
~ You may not use this file except in compliance with the License.
~ A copy of the License is located at
~
~ http://aws.amazon.com/apache2.0
~
~ or in the "license" file accompanying this file. This file is distributed
~ on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
~ express or implied. See the License for the specific language governing
~ permissions and limitations under the License.
-->

<MessageCollection>

<Detector class="software.amazon.awssdk.buildtools.findbugs.DisallowMethodCall" >
<Details>This detector checks for method calls that are not allowed for use.</Details>
</Detector>

<BugPattern type="SDK_BAD_METHOD_CALL">
<ShortDescription>Bad method call</ShortDescription>

<LongDescription>
<![CDATA[
{1} uses a method that is prohibited.
The headers() and rawQueryParameters() methods create a deep copy of the data, which can result in
significant memory pressure. Instead of retrieving a copy of the headers to look at it, use methods like
hasHeaders(), firstMatchingHeader(...) or forEachHeader(..) which may be optimized in the type to avoid
copying the data.
]]>
</LongDescription>

<Details>
<![CDATA[
The headers() and rawQueryParameters() methods create a deep copy of the data, which can result in
significant memory pressure. Instead of retrieving a copy of the headers to look at it, use methods like
hasHeaders(), firstMatchingHeader(...) or forEachHeader(..) which may be optimized in the type to avoid
copying the data.
]]>
</Details>
</BugPattern>

<BugCode abbrev="BM">Bad method</BugCode>
</MessageCollection>
Original file line number Diff line number Diff line change
Expand Up @@ -230,4 +230,13 @@
<Match>
<Bug pattern="DMI_RANDOM_USED_ONLY_ONCE" />
</Match>

<!-- Uses these methods legitimately. -->
<Match>
<Or>
<Class name="software.amazon.awssdk.http.SdkHttpHeaders"/>
<Class name="software.amazon.awssdk.http.SdkHttpRequest"/>
</Or>
<Bug pattern="SDK_BAD_METHOD_CALL"/>
</Match>
</FindBugsFilter>
5 changes: 5 additions & 0 deletions codegen-lite-maven-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@
<groupId>software.amazon.awssdk</groupId>
<version>${awsjavasdk.version}</version>
</dependency>
<dependency>
<artifactId>utils</artifactId>
<groupId>software.amazon.awssdk</groupId>
<version>${awsjavasdk.version}</version>
</dependency>
<dependency>
<artifactId>maven-plugin-api</artifactId>
<groupId>org.apache.maven</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import software.amazon.awssdk.codegen.lite.defaultsmode.DefaultsLoader;
import software.amazon.awssdk.codegen.lite.defaultsmode.DefaultsModeConfigurationGenerator;
import software.amazon.awssdk.codegen.lite.defaultsmode.DefaultsModeGenerator;
import software.amazon.awssdk.utils.StringUtils;

/**
* The Maven mojo to generate defaults mode related classes.
Expand Down Expand Up @@ -61,12 +62,12 @@ public void execute() {
}

public void generateDefaultsModeClass(Path baseSourcesDirectory, DefaultConfiguration configuration) {
Path sourcesDirectory = baseSourcesDirectory.resolve(DEFAULTS_MODE_BASE.replace(".", "/"));
Path sourcesDirectory = baseSourcesDirectory.resolve(StringUtils.replace(DEFAULTS_MODE_BASE, ".", "/"));
new CodeGenerator(sourcesDirectory.toString(), new DefaultsModeGenerator(DEFAULTS_MODE_BASE, configuration)).generate();
}

public void generateDefaultsModeConfiguartionClass(Path baseSourcesDirectory, DefaultConfiguration configuration) {
Path sourcesDirectory = baseSourcesDirectory.resolve(DEFAULTS_MODE_CONFIGURATION_BASE.replace(".", "/"));
Path sourcesDirectory = baseSourcesDirectory.resolve(StringUtils.replace(DEFAULTS_MODE_CONFIGURATION_BASE, ".", "/"));
new CodeGenerator(sourcesDirectory.toString(), new DefaultsModeConfigurationGenerator(DEFAULTS_MODE_CONFIGURATION_BASE,
DEFAULTS_MODE_BASE,
configuration)).generate();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import software.amazon.awssdk.codegen.lite.regions.ServiceMetadataGenerator;
import software.amazon.awssdk.codegen.lite.regions.ServiceMetadataProviderGenerator;
import software.amazon.awssdk.codegen.lite.regions.model.Partitions;
import software.amazon.awssdk.utils.StringUtils;

/**
* The Maven mojo to generate Java client code using software.amazon.awssdk:codegen module.
Expand Down Expand Up @@ -79,7 +80,7 @@ public void execute() throws MojoExecutionException {
}

public void generatePartitionMetadataClass(Path baseSourcesDirectory, Partitions partitions) {
Path sourcesDirectory = baseSourcesDirectory.resolve(PARTITION_METADATA_BASE.replace(".", "/"));
Path sourcesDirectory = baseSourcesDirectory.resolve(StringUtils.replace(PARTITION_METADATA_BASE, ".", "/"));
partitions.getPartitions()
.forEach(p -> new CodeGenerator(sourcesDirectory.toString(),
new PartitionMetadataGenerator(p,
Expand All @@ -88,12 +89,12 @@ public void generatePartitionMetadataClass(Path baseSourcesDirectory, Partitions
}

public void generateRegionClass(Path baseSourcesDirectory, Partitions partitions) {
Path sourcesDirectory = baseSourcesDirectory.resolve(REGION_BASE.replace(".", "/"));
Path sourcesDirectory = baseSourcesDirectory.resolve(StringUtils.replace(REGION_BASE, ".", "/"));
new CodeGenerator(sourcesDirectory.toString(), new RegionGenerator(partitions, REGION_BASE)).generate();
}

public void generateServiceMetadata(Path baseSourcesDirectory, Partitions partitions) {
Path sourcesDirectory = baseSourcesDirectory.resolve(SERVICE_METADATA_BASE.replace(".", "/"));
Path sourcesDirectory = baseSourcesDirectory.resolve(StringUtils.replace(SERVICE_METADATA_BASE, ".", "/"));
Set<String> services = new HashSet<>();
partitions.getPartitions().forEach(p -> services.addAll(p.getServices().keySet()));

Expand All @@ -105,7 +106,7 @@ public void generateServiceMetadata(Path baseSourcesDirectory, Partitions partit
}

public void generateRegions(Path baseSourcesDirectory, Partitions partitions) {
Path sourcesDirectory = baseSourcesDirectory.resolve(REGION_METADATA_BASE.replace(".", "/"));
Path sourcesDirectory = baseSourcesDirectory.resolve(StringUtils.replace(REGION_METADATA_BASE, ".", "/"));
partitions.getPartitions()
.forEach(p -> p.getRegions().forEach((k, v) ->
new CodeGenerator(sourcesDirectory.toString(),
Expand All @@ -118,31 +119,31 @@ public void generateRegions(Path baseSourcesDirectory, Partitions partitions) {
}

public void generatePartitionProvider(Path baseSourcesDirectory, Partitions partitions) {
Path sourcesDirectory = baseSourcesDirectory.resolve(REGION_BASE.replace(".", "/"));
Path sourcesDirectory = baseSourcesDirectory.resolve(StringUtils.replace(REGION_BASE, ".", "/"));
new CodeGenerator(sourcesDirectory.toString(), new PartitionMetadataProviderGenerator(partitions,
PARTITION_METADATA_BASE,
REGION_BASE))
.generate();
}

public void generateRegionProvider(Path baseSourcesDirectory, Partitions partitions) {
Path sourcesDirectory = baseSourcesDirectory.resolve(REGION_BASE.replace(".", "/"));
Path sourcesDirectory = baseSourcesDirectory.resolve(StringUtils.replace(REGION_BASE, ".", "/"));
new CodeGenerator(sourcesDirectory.toString(), new RegionMetadataProviderGenerator(partitions,
REGION_METADATA_BASE,
REGION_BASE))
.generate();
}

public void generateServiceProvider(Path baseSourcesDirectory, Partitions partitions) {
Path sourcesDirectory = baseSourcesDirectory.resolve(REGION_BASE.replace(".", "/"));
Path sourcesDirectory = baseSourcesDirectory.resolve(StringUtils.replace(REGION_BASE, ".", "/"));
new CodeGenerator(sourcesDirectory.toString(), new ServiceMetadataProviderGenerator(partitions,
SERVICE_METADATA_BASE,
REGION_BASE))
.generate();
}

public void generateEndpointTags(Path baseSourcesDirectory, Partitions partitions) {
Path sourcesDirectory = baseSourcesDirectory.resolve(REGION_BASE.replace(".", "/"));
Path sourcesDirectory = baseSourcesDirectory.resolve(StringUtils.replace(REGION_BASE, ".", "/"));
new CodeGenerator(sourcesDirectory.toString(), new EndpointTagGenerator(partitions, REGION_BASE)).generate();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package software.amazon.awssdk.authcrt.signer.internal;

import static java.lang.Math.min;
import static software.amazon.awssdk.utils.CollectionUtils.isNullOrEmpty;

import java.io.ByteArrayInputStream;
import java.io.IOException;
Expand All @@ -26,7 +25,6 @@
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.crt.auth.signing.AwsSigningResult;
Expand All @@ -52,9 +50,7 @@ public HttpRequest requestToCrt(SdkHttpFullRequest inputRequest) {
String method = inputRequest.method().name();
String encodedPath = encodedPathToCrtFormat(inputRequest.encodedPath());

String encodedQueryString = SdkHttpUtils.encodeAndFlattenQueryParameters(inputRequest.rawQueryParameters())
.map(value -> "?" + value)
.orElse("");
String encodedQueryString = inputRequest.encodedQueryParameters().map(value -> "?" + value).orElse("");

HttpHeader[] crtHeaderArray = createHttpHeaderArray(inputRequest);

Expand Down Expand Up @@ -129,20 +125,20 @@ public HttpRequestBodyStream toCrtStream(byte[] data) {
}

private HttpHeader[] createHttpHeaderArray(SdkHttpFullRequest request) {
List<HttpHeader> crtHeaderList = new ArrayList<>(request.headers().size() + 2);
List<HttpHeader> crtHeaderList = new ArrayList<>(request.numHeaders() + 2);

// Set Host Header if needed
if (isNullOrEmpty(request.headers().get(HOST_HEADER))) {
if (!request.firstMatchingHeader(HOST_HEADER).isPresent()) {
crtHeaderList.add(new HttpHeader(HOST_HEADER, request.host()));
}

// Add the rest of the Headers
for (Map.Entry<String, List<String>> headerList: request.headers().entrySet()) {
for (String val: headerList.getValue()) {
HttpHeader h = new HttpHeader(headerList.getKey(), val);
request.forEachHeader((name, values) -> {
for (String val : values) {
HttpHeader h = new HttpHeader(name, val);
crtHeaderList.add(h);
}
}
});

return crtHeaderList.toArray(new HttpHeader[0]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
import java.nio.charset.StandardCharsets;
import java.time.Clock;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
Expand Down Expand Up @@ -116,11 +114,11 @@ public static SdkHttpFullRequest sanitizeSdkRequestForCrtSigning(SdkHttpFullRequ
builder.clearHeaders();

// Filter headers that will cause signing to fail
for (Map.Entry<String, List<String>> header: request.headers().entrySet()) {
if (!FORBIDDEN_HEADERS.contains(header.getKey())) {
builder.putHeader(header.getKey(), header.getValue());
request.forEachHeader((name, value) -> {
if (!FORBIDDEN_HEADERS.contains(name)) {
builder.putHeader(name, value);
}
}
});

// Add host, which must be signed. We ignore any pre-existing Host header to match the behavior of the SigV4 signer.
String hostHeader = SdkHttpUtils.isUsingStandardPort(request.protocol(), request.port())
Expand All @@ -131,12 +129,11 @@ public static SdkHttpFullRequest sanitizeSdkRequestForCrtSigning(SdkHttpFullRequ
builder.clearQueryParameters();

// Filter query parameters that will cause signing to fail
Map<String, List<String>> params = request.rawQueryParameters();
for (Map.Entry<String, List<String>> param: params.entrySet()) {
if (!FORBIDDEN_PARAMS.contains(param.getKey())) {
builder.putRawQueryParameter(param.getKey(), param.getValue());
request.forEachRawQueryParameter((key, value) -> {
if (!FORBIDDEN_PARAMS.contains(key)) {
builder.putRawQueryParameter(key, value);
}
}
});

return builder.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public CompletableFuture<SdkHttpFullRequest> signWithBody(SdkHttpFullRequest req
Aws4SignerRequestParams requestParams = new Aws4SignerRequestParams(signingParams);

SdkHttpFullRequest.Builder builder = doSign(request, requestParams, signingParams,
new ContentChecksum(digestHex, sdkChecksum));
new ContentChecksum(digestHex, sdkChecksum));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the indent change here intended? Or an IDE fail?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not intended, but more of an IDE success. The indent is an improvement, imo.


return builder.build();
});
Expand Down
Loading