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.benchmark.enhanced.dynamodb; 17 18 import static software.amazon.awssdk.core.client.config.SdkClientOption.ENDPOINT; 19 20 import java.io.IOException; 21 import java.io.UncheckedIOException; 22 import java.net.URI; 23 import java.util.Map; 24 import org.openjdk.jmh.annotations.Benchmark; 25 import org.openjdk.jmh.annotations.BenchmarkMode; 26 import org.openjdk.jmh.annotations.Fork; 27 import org.openjdk.jmh.annotations.Measurement; 28 import org.openjdk.jmh.annotations.Mode; 29 import org.openjdk.jmh.annotations.Param; 30 import org.openjdk.jmh.annotations.Scope; 31 import org.openjdk.jmh.annotations.Setup; 32 import org.openjdk.jmh.annotations.State; 33 import org.openjdk.jmh.annotations.Warmup; 34 import org.openjdk.jmh.infra.Blackhole; 35 import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; 36 import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; 37 import software.amazon.awssdk.benchmark.utils.MockHttpClient; 38 import software.amazon.awssdk.core.client.config.SdkClientConfiguration; 39 import software.amazon.awssdk.core.interceptor.Context; 40 import software.amazon.awssdk.core.interceptor.ExecutionAttributes; 41 import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; 42 import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient; 43 import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable; 44 import software.amazon.awssdk.enhanced.dynamodb.Key; 45 import software.amazon.awssdk.enhanced.dynamodb.TableSchema; 46 import software.amazon.awssdk.protocols.json.AwsJsonProtocol; 47 import software.amazon.awssdk.protocols.json.AwsJsonProtocolFactory; 48 import software.amazon.awssdk.services.dynamodb.DynamoDbClient; 49 import software.amazon.awssdk.services.dynamodb.model.AttributeValue; 50 import software.amazon.awssdk.services.dynamodb.model.DynamoDbException; 51 import software.amazon.awssdk.services.dynamodb.model.GetItemRequest; 52 import software.amazon.awssdk.services.dynamodb.model.PutItemRequest; 53 import software.amazon.awssdk.services.dynamodb.transform.PutItemRequestMarshaller; 54 import software.amazon.awssdk.utils.IoUtils; 55 56 @BenchmarkMode(Mode.Throughput) 57 @Warmup(iterations = 5) 58 @Measurement(iterations = 5) 59 @Fork(2) 60 @State(Scope.Benchmark) 61 public class EnhancedClientGetOverheadBenchmark { 62 private static final AwsJsonProtocolFactory JSON_PROTOCOL_FACTORY = AwsJsonProtocolFactory 63 .builder() 64 .clientConfiguration(SdkClientConfiguration.builder() 65 .option(ENDPOINT, URI.create("https://dynamodb.amazonaws.com")) 66 .build()) 67 .defaultServiceExceptionSupplier(DynamoDbException::builder) 68 .protocol(AwsJsonProtocol.AWS_JSON) 69 .protocolVersion("1.0") 70 .build(); 71 72 private static final PutItemRequestMarshaller PUT_ITEM_REQUEST_MARSHALLER = 73 new PutItemRequestMarshaller(JSON_PROTOCOL_FACTORY); 74 75 private static final V2ItemFactory ITEM_FACTORY = new V2ItemFactory(); 76 77 private final Key testKey = Key.builder().partitionValue("key").build(); 78 79 80 @Benchmark lowLevelGet(TestState s)81 public Object lowLevelGet(TestState s) { 82 return s.dynamoDb.getItem(GetItemRequest.builder().build()); 83 } 84 85 @Benchmark enhanceGet(TestState s)86 public Object enhanceGet(TestState s) { 87 return s.table.getItem(testKey); 88 } 89 90 @State(Scope.Benchmark) 91 public static class TestState { 92 private DynamoDbClient dynamoDb; 93 94 @Param({"TINY", "SMALL", "HUGE", "HUGE_FLAT"}) 95 private TestItem testItem; 96 97 private DynamoDbTable table; 98 99 @Setup setup(Blackhole bh)100 public void setup(Blackhole bh) { 101 dynamoDb = DynamoDbClient.builder() 102 .credentialsProvider(StaticCredentialsProvider.create( 103 AwsBasicCredentials.create("akid", "skid"))) 104 .httpClient(new MockHttpClient(testItem.responseContent, "{}")) 105 .overrideConfiguration(o -> o.addExecutionInterceptor(new ExecutionInterceptor() { 106 @Override 107 public void afterUnmarshalling(Context.AfterUnmarshalling context, 108 ExecutionAttributes executionAttributes) { 109 bh.consume(context); 110 bh.consume(executionAttributes); 111 } 112 })) 113 .build(); 114 115 DynamoDbEnhancedClient ddbEnh = DynamoDbEnhancedClient.builder() 116 .dynamoDbClient(dynamoDb) 117 .build(); 118 119 table = ddbEnh.table(testItem.name(), testItem.tableSchema); 120 } 121 } 122 123 public enum TestItem { 124 TINY(marshall(ITEM_FACTORY.tiny()), V2ItemFactory.TINY_BEAN_TABLE_SCHEMA), 125 SMALL(marshall(ITEM_FACTORY.small()), V2ItemFactory.SMALL_BEAN_TABLE_SCHEMA), 126 HUGE(marshall(ITEM_FACTORY.huge()), V2ItemFactory.HUGE_BEAN_TABLE_SCHEMA), 127 HUGE_FLAT(marshall(ITEM_FACTORY.hugeFlat()), V2ItemFactory.HUGE_BEAN_FLAT_TABLE_SCHEMA) 128 ; 129 130 private String responseContent; 131 private TableSchema tableSchema; 132 TestItem(String responseContent, TableSchema tableSchema)133 TestItem(String responseContent, TableSchema tableSchema) { 134 this.responseContent = responseContent; 135 this.tableSchema = tableSchema; 136 } 137 } 138 marshall(Map<String, AttributeValue> item)139 private static String marshall(Map<String, AttributeValue> item) { 140 return PUT_ITEM_REQUEST_MARSHALLER.marshall(PutItemRequest.builder().item(item).build()) 141 .contentStreamProvider().map(cs -> { 142 try { 143 return IoUtils.toUtf8String(cs.newStream()); 144 } catch (IOException e) { 145 throw new UncheckedIOException(e); 146 } 147 }).orElse(null); 148 } 149 } 150