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.marshaller.dynamodb; 17 18 import java.io.ByteArrayInputStream; 19 import java.io.ByteArrayOutputStream; 20 import java.io.IOException; 21 import java.io.InputStream; 22 import java.io.UncheckedIOException; 23 import java.util.Map; 24 import org.openjdk.jmh.annotations.Benchmark; 25 import org.openjdk.jmh.annotations.Param; 26 import org.openjdk.jmh.annotations.Scope; 27 import org.openjdk.jmh.annotations.Setup; 28 import org.openjdk.jmh.annotations.State; 29 import software.amazon.awssdk.core.http.HttpResponseHandler; 30 import software.amazon.awssdk.core.interceptor.ExecutionAttributes; 31 import software.amazon.awssdk.http.AbortableInputStream; 32 import software.amazon.awssdk.http.SdkHttpFullRequest; 33 import software.amazon.awssdk.http.SdkHttpFullResponse; 34 import software.amazon.awssdk.protocols.core.ExceptionMetadata; 35 import software.amazon.awssdk.protocols.json.AwsJsonProtocol; 36 import software.amazon.awssdk.protocols.json.AwsJsonProtocolFactory; 37 import software.amazon.awssdk.protocols.json.JsonOperationMetadata; 38 import software.amazon.awssdk.services.dynamodb.model.AttributeValue; 39 import software.amazon.awssdk.services.dynamodb.model.BackupInUseException; 40 import software.amazon.awssdk.services.dynamodb.model.BackupNotFoundException; 41 import software.amazon.awssdk.services.dynamodb.model.ConditionalCheckFailedException; 42 import software.amazon.awssdk.services.dynamodb.model.ContinuousBackupsUnavailableException; 43 import software.amazon.awssdk.services.dynamodb.model.DynamoDbException; 44 import software.amazon.awssdk.services.dynamodb.model.GetItemResponse; 45 import software.amazon.awssdk.services.dynamodb.model.GlobalTableAlreadyExistsException; 46 import software.amazon.awssdk.services.dynamodb.model.GlobalTableNotFoundException; 47 import software.amazon.awssdk.services.dynamodb.model.IndexNotFoundException; 48 import software.amazon.awssdk.services.dynamodb.model.InternalServerErrorException; 49 import software.amazon.awssdk.services.dynamodb.model.InvalidRestoreTimeException; 50 import software.amazon.awssdk.services.dynamodb.model.ItemCollectionSizeLimitExceededException; 51 import software.amazon.awssdk.services.dynamodb.model.LimitExceededException; 52 import software.amazon.awssdk.services.dynamodb.model.PointInTimeRecoveryUnavailableException; 53 import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughputExceededException; 54 import software.amazon.awssdk.services.dynamodb.model.PutItemRequest; 55 import software.amazon.awssdk.services.dynamodb.model.ReplicaAlreadyExistsException; 56 import software.amazon.awssdk.services.dynamodb.model.ReplicaNotFoundException; 57 import software.amazon.awssdk.services.dynamodb.model.ResourceInUseException; 58 import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException; 59 import software.amazon.awssdk.services.dynamodb.model.TableAlreadyExistsException; 60 import software.amazon.awssdk.services.dynamodb.model.TableInUseException; 61 import software.amazon.awssdk.services.dynamodb.model.TableNotFoundException; 62 import software.amazon.awssdk.services.dynamodb.transform.PutItemRequestMarshaller; 63 64 65 public class V2DynamoDbAttributeValue { 66 67 private static final AwsJsonProtocolFactory JSON_PROTOCOL_FACTORY = AwsJsonProtocolFactory 68 .builder() 69 .defaultServiceExceptionSupplier(DynamoDbException::builder) 70 .protocol(AwsJsonProtocol.AWS_JSON) 71 .protocolVersion("1.0") 72 .registerModeledException( 73 ExceptionMetadata.builder().errorCode("ResourceInUseException") 74 .exceptionBuilderSupplier(ResourceInUseException::builder).build()) 75 .registerModeledException( 76 ExceptionMetadata.builder().errorCode("TableAlreadyExistsException") 77 .exceptionBuilderSupplier(TableAlreadyExistsException::builder).build()) 78 .registerModeledException( 79 ExceptionMetadata.builder().errorCode("GlobalTableAlreadyExistsException") 80 .exceptionBuilderSupplier(GlobalTableAlreadyExistsException::builder).build()) 81 .registerModeledException( 82 ExceptionMetadata.builder().errorCode("InvalidRestoreTimeException") 83 .exceptionBuilderSupplier(InvalidRestoreTimeException::builder).build()) 84 .registerModeledException( 85 ExceptionMetadata.builder().errorCode("ReplicaAlreadyExistsException") 86 .exceptionBuilderSupplier(ReplicaAlreadyExistsException::builder).build()) 87 .registerModeledException( 88 ExceptionMetadata.builder().errorCode("ConditionalCheckFailedException") 89 .exceptionBuilderSupplier(ConditionalCheckFailedException::builder).build()) 90 .registerModeledException( 91 ExceptionMetadata.builder().errorCode("BackupNotFoundException") 92 .exceptionBuilderSupplier(BackupNotFoundException::builder).build()) 93 .registerModeledException( 94 ExceptionMetadata.builder().errorCode("IndexNotFoundException") 95 .exceptionBuilderSupplier(IndexNotFoundException::builder).build()) 96 .registerModeledException( 97 ExceptionMetadata.builder().errorCode("LimitExceededException") 98 .exceptionBuilderSupplier(LimitExceededException::builder).build()) 99 .registerModeledException( 100 ExceptionMetadata.builder().errorCode("GlobalTableNotFoundException") 101 .exceptionBuilderSupplier(GlobalTableNotFoundException::builder).build()) 102 .registerModeledException( 103 ExceptionMetadata.builder().errorCode("ItemCollectionSizeLimitExceededException") 104 .exceptionBuilderSupplier(ItemCollectionSizeLimitExceededException::builder).build()) 105 .registerModeledException( 106 ExceptionMetadata.builder().errorCode("ReplicaNotFoundException") 107 .exceptionBuilderSupplier(ReplicaNotFoundException::builder).build()) 108 .registerModeledException( 109 ExceptionMetadata.builder().errorCode("TableNotFoundException") 110 .exceptionBuilderSupplier(TableNotFoundException::builder).build()) 111 .registerModeledException( 112 ExceptionMetadata.builder().errorCode("BackupInUseException") 113 .exceptionBuilderSupplier(BackupInUseException::builder).build()) 114 .registerModeledException( 115 ExceptionMetadata.builder().errorCode("ResourceNotFoundException") 116 .exceptionBuilderSupplier(ResourceNotFoundException::builder).build()) 117 .registerModeledException( 118 ExceptionMetadata.builder().errorCode("ContinuousBackupsUnavailableException") 119 .exceptionBuilderSupplier(ContinuousBackupsUnavailableException::builder).build()) 120 .registerModeledException( 121 ExceptionMetadata.builder().errorCode("TableInUseException") 122 .exceptionBuilderSupplier(TableInUseException::builder).build()) 123 .registerModeledException( 124 ExceptionMetadata.builder().errorCode("ProvisionedThroughputExceededException") 125 .exceptionBuilderSupplier(ProvisionedThroughputExceededException::builder).build()) 126 .registerModeledException( 127 ExceptionMetadata.builder().errorCode("PointInTimeRecoveryUnavailableException") 128 .exceptionBuilderSupplier(PointInTimeRecoveryUnavailableException::builder).build()) 129 .registerModeledException( 130 ExceptionMetadata.builder().errorCode("InternalServerError") 131 .exceptionBuilderSupplier(InternalServerErrorException::builder).build()) 132 .build(); 133 134 private static final PutItemRequestMarshaller PUT_ITEM_REQUEST_MARSHALLER 135 = new PutItemRequestMarshaller(getJsonProtocolFactory()); 136 getItemResponseJsonResponseHandler()137 private static HttpResponseHandler<GetItemResponse> getItemResponseJsonResponseHandler() { 138 return JSON_PROTOCOL_FACTORY.createResponseHandler(JsonOperationMetadata.builder() 139 .isPayloadJson(true) 140 .hasStreamingSuccessResponse(false) 141 .build(), 142 GetItemResponse::builder); 143 } 144 145 @Benchmark putItem(PutItemState s)146 public Object putItem(PutItemState s) { 147 return putItemRequestMarshaller().marshall(s.getReq()); 148 } 149 150 @Benchmark getItem(GetItemState s)151 public Object getItem(GetItemState s) throws Exception { 152 SdkHttpFullResponse resp = fullResponse(s.testItem); 153 return getItemResponseJsonResponseHandler().handle(resp, new ExecutionAttributes()); 154 } 155 156 @State(Scope.Benchmark) 157 public static class PutItemState { 158 @Param({"TINY", "SMALL", "HUGE"}) 159 private TestItem testItem; 160 161 private PutItemRequest req; 162 163 @Setup setup()164 public void setup() { 165 req = PutItemRequest.builder().item(testItem.getValue()).build(); 166 } 167 getReq()168 public PutItemRequest getReq() { 169 return req; 170 } 171 } 172 173 @State(Scope.Benchmark) 174 public static class GetItemState { 175 @Param({"TINY", "SMALL", "HUGE"}) 176 private TestItemUnmarshalling testItem; 177 } 178 179 public enum TestItem { 180 TINY, 181 SMALL, 182 HUGE; 183 184 private static final AbstractItemFactory<AttributeValue> FACTORY = new V2ItemFactory(); 185 186 private Map<String, AttributeValue> av; 187 188 static { 189 TINY.av = FACTORY.tiny(); 190 SMALL.av = FACTORY.small(); 191 HUGE.av = FACTORY.huge(); 192 } 193 getValue()194 public Map<String, AttributeValue> getValue() { 195 return av; 196 } 197 } 198 199 public enum TestItemUnmarshalling { 200 TINY, 201 SMALL, 202 HUGE; 203 204 private byte[] utf8; 205 206 static { 207 TINY.utf8 = toUtf8ByteArray(TestItem.TINY.av); 208 SMALL.utf8 = toUtf8ByteArray(TestItem.SMALL.av); 209 HUGE.utf8 = toUtf8ByteArray(TestItem.HUGE.av); 210 } 211 utf8()212 public byte[] utf8() { 213 return utf8; 214 } 215 } 216 fullResponse(TestItemUnmarshalling item)217 private SdkHttpFullResponse fullResponse(TestItemUnmarshalling item) { 218 AbortableInputStream abortableInputStream = AbortableInputStream.create(new ByteArrayInputStream(item.utf8())); 219 return SdkHttpFullResponse.builder() 220 .statusCode(200) 221 .content(abortableInputStream) 222 .build(); 223 } 224 toUtf8ByteArray(Map<String, AttributeValue> item)225 private static byte[] toUtf8ByteArray(Map<String, AttributeValue> item) { 226 SdkHttpFullRequest marshalled = putItemRequestMarshaller().marshall(PutItemRequest.builder().item(item).build()); 227 InputStream content = marshalled.contentStreamProvider().get().newStream(); 228 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 229 byte[] buff = new byte[8192]; 230 int read; 231 try { 232 while ((read = content.read(buff)) != -1) { 233 baos.write(buff, 0, read); 234 } 235 } catch (IOException ioe) { 236 throw new UncheckedIOException(ioe); 237 } 238 return baos.toByteArray(); 239 } 240 putItemRequestMarshaller()241 private static PutItemRequestMarshaller putItemRequestMarshaller() { 242 return PUT_ITEM_REQUEST_MARSHALLER; 243 } 244 getJsonProtocolFactory()245 private static AwsJsonProtocolFactory getJsonProtocolFactory() { 246 return JSON_PROTOCOL_FACTORY; 247 } 248 } 249