/* * Copyright 2014-2015 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 com.amazonaws.codesamples.lowlevel; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import com.amazonaws.AmazonServiceException; import com.amazonaws.auth.profile.ProfileCredentialsProvider; import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient; import com.amazonaws.services.dynamodbv2.model.AttributeDefinition; import com.amazonaws.services.dynamodbv2.model.AttributeValue; import com.amazonaws.services.dynamodbv2.model.CreateTableRequest; import com.amazonaws.services.dynamodbv2.model.DeleteTableRequest; import com.amazonaws.services.dynamodbv2.model.DescribeTableRequest; import com.amazonaws.services.dynamodbv2.model.KeySchemaElement; import com.amazonaws.services.dynamodbv2.model.KeyType; import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput; import com.amazonaws.services.dynamodbv2.model.PutItemRequest; import com.amazonaws.services.dynamodbv2.model.ResourceNotFoundException; import com.amazonaws.services.dynamodbv2.model.ScanRequest; import com.amazonaws.services.dynamodbv2.model.ScanResult; import com.amazonaws.services.dynamodbv2.model.TableDescription; import com.amazonaws.services.dynamodbv2.model.TableStatus; public class LowLevelParallelScan { // total number of sample items static int scanItemCount = 300; // number of items each scan request should return static int scanItemLimit = 10; // number of logical segments for parallel scan static int parallelScanThreads = 16; // table that will be used for scanning static String productCatalogTableName = "ProductCatalog"; static AmazonDynamoDBClient client = new AmazonDynamoDBClient(new ProfileCredentialsProvider()); public static void main(String[] args) throws Exception { try { // Clean up the table deleteTable(productCatalogTableName); waitForTableToBeDeleted(productCatalogTableName); createTable(productCatalogTableName, 10L, 5L, "Id", "N"); waitForTableToBecomeAvailable(productCatalogTableName); // Upload sample data for scan uploadSampleProducts(productCatalogTableName, scanItemCount); // Scan the table using multiple threads parallelScan(productCatalogTableName, scanItemLimit, parallelScanThreads); } catch (AmazonServiceException ase) { System.err.println(ase.getMessage()); } } private static void parallelScan(String tableName, int itemLimit, int numberOfThreads) { System.out.println("Scanning " + tableName + " using " + numberOfThreads + " threads " + itemLimit + " items at a time"); ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads); // Divide DynamoDB table into logical segments // Create one task for scanning each segment // Each thread will be scanning one segment int totalSegments = numberOfThreads; for (int segment = 0; segment < totalSegments; segment++) { // Runnable task that will only scan one segment ScanSegmentTask task = new ScanSegmentTask(tableName, itemLimit, totalSegments, segment); // Execute the task executor.execute(task); } shutDownExecutorService(executor); } // Runnable task for scanning a single segment of a DynamoDB table private static class ScanSegmentTask implements Runnable { // DynamoDB table to scan private String tableName; // number of items each scan request should return private int itemLimit; // Total number of segments // Equals to total number of threads scanning the table in parallel private int totalSegments; // Segment that will be scanned with by this task private int segment; public ScanSegmentTask(String tableName, int itemLimit, int totalSegments, int segment) { this.tableName = tableName; this.itemLimit = itemLimit; this.totalSegments = totalSegments; this.segment = segment; } @Override public void run() { System.out.println("Scanning " + tableName + " segment " + segment + " out of " + totalSegments + " segments " + itemLimit + " items at a time..."); Map<String, AttributeValue> exclusiveStartKey = null; int totalScannedItemCount = 0; int totalScanRequestCount = 0; try { while(true) { ScanRequest scanRequest = new ScanRequest() .withTableName(tableName) .withLimit(itemLimit) .withExclusiveStartKey(exclusiveStartKey) .withTotalSegments(totalSegments) .withSegment(segment); ScanResult result = client.scan(scanRequest); totalScanRequestCount++; totalScannedItemCount += result.getScannedCount(); // print items returned from scan request processScanResult(segment, result); exclusiveStartKey = result.getLastEvaluatedKey(); if (exclusiveStartKey == null) { break; } } } catch (AmazonServiceException ase) { System.err.println(ase.getMessage()); } finally { System.out.println("Scanned " + totalScannedItemCount + " items from segment " + segment + " out of " + totalSegments + " of " + tableName + " with " + totalScanRequestCount + " scan requests"); } } } private static void processScanResult(int segment, ScanResult result) { for (Map<String, AttributeValue> item : result.getItems()) { printItem(segment, item); } } private static void uploadSampleProducts(String tableName, int itemCount) { System.out.println("Uploading " + itemCount + " sample items to " + tableName); for (int productIndex = 0; productIndex < itemCount; productIndex++) { uploadProduct(tableName, String.valueOf(productIndex)); } } private static void uploadProduct(String tableName, String productIndex) { try { // Add a book. Map<String, AttributeValue> item = new HashMap<String, AttributeValue>(); item.put("Id", new AttributeValue().withN(productIndex)); item.put("Title", new AttributeValue().withS("Book " + productIndex + " Title")); item.put("ISBN", new AttributeValue().withS("111-1111111111")); item.put("Authors", new AttributeValue().withSS(Arrays.asList("Author1"))); item.put("Price", new AttributeValue().withN("2")); item.put("Dimensions", new AttributeValue().withS("8.5 x 11.0 x 0.5")); item.put("PageCount", new AttributeValue().withN("500")); item.put("InPublication", new AttributeValue().withBOOL(true)); item.put("ProductCategory", new AttributeValue().withS("Book")); PutItemRequest itemRequest = new PutItemRequest().withTableName(tableName).withItem(item); client.putItem(itemRequest); item.clear(); } catch (AmazonServiceException ase) { System.err.println("Failed to create item " + productIndex + " in " + tableName); } } private static void deleteTable(String tableName){ try { DeleteTableRequest request = new DeleteTableRequest() .withTableName(tableName); client.deleteTable(request); } catch (AmazonServiceException ase) { System.err.println("Failed to delete table " + tableName + " " + ase); } } private static void createTable(String tableName, long readCapacityUnits, long writeCapacityUnits, String hashKeyName, String hashKeyType) { createTable(tableName, readCapacityUnits, writeCapacityUnits, hashKeyName, hashKeyType, null, null); } private static void createTable(String tableName, long readCapacityUnits, long writeCapacityUnits, String hashKeyName, String hashKeyType, String rangeKeyName, String rangeKeyType) { try { System.out.println("Creating table " + tableName); ArrayList<KeySchemaElement> ks = new ArrayList<KeySchemaElement>(); ArrayList<AttributeDefinition> attributeDefinitions = new ArrayList<AttributeDefinition>(); ks.add(new KeySchemaElement().withAttributeName( hashKeyName).withKeyType(KeyType.HASH)); attributeDefinitions.add(new AttributeDefinition().withAttributeName( hashKeyName).withAttributeType(hashKeyType)); if (rangeKeyName != null){ ks.add(new KeySchemaElement().withAttributeName( rangeKeyName).withKeyType(KeyType.RANGE)); attributeDefinitions.add(new AttributeDefinition().withAttributeName( rangeKeyName).withAttributeType(rangeKeyType)); } // Provide initial provisioned throughput values as Java long data types ProvisionedThroughput provisionedthroughput = new ProvisionedThroughput() .withReadCapacityUnits(readCapacityUnits) .withWriteCapacityUnits(writeCapacityUnits); CreateTableRequest request = new CreateTableRequest() .withTableName(tableName) .withKeySchema(ks) .withProvisionedThroughput(provisionedthroughput) .withAttributeDefinitions(attributeDefinitions); client.createTable(request); } catch (AmazonServiceException ase) { System.err.println("Failed to create table " + tableName + " " + ase); } } private static void waitForTableToBecomeAvailable(String tableName) { System.out.println("Waiting for " + tableName + " to become ACTIVE..."); long startTime = System.currentTimeMillis(); long endTime = startTime + (10 * 60 * 1000); while (System.currentTimeMillis() < endTime) { DescribeTableRequest request = new DescribeTableRequest() .withTableName(tableName); TableDescription tableDescription = client.describeTable( request).getTable(); String tableStatus = tableDescription.getTableStatus(); System.out.println(" - current state: " + tableStatus); if (tableStatus.equals(TableStatus.ACTIVE.toString())) return; try { Thread.sleep(1000 * 20); } catch (Exception e) { } } throw new RuntimeException("Table " + tableName + " never went active"); } private static void waitForTableToBeDeleted(String tableName) { System.out.println("Waiting for " + tableName + " while status DELETING..."); long startTime = System.currentTimeMillis(); long endTime = startTime + (10 * 60 * 1000); while (System.currentTimeMillis() < endTime) { try { DescribeTableRequest request = new DescribeTableRequest().withTableName(tableName); TableDescription tableDescription = client.describeTable(request).getTable(); String tableStatus = tableDescription.getTableStatus(); System.out.println(" - current state: " + tableStatus); if (tableStatus.equals(TableStatus.ACTIVE.toString())) return; } catch (ResourceNotFoundException e) { System.out.println("Table " + tableName + " is not found. It was deleted."); return; } try {Thread.sleep(1000 * 20);} catch (Exception e) {} } throw new RuntimeException("Table " + tableName + " was never deleted"); } private static void printItem(int segment, Map<String, AttributeValue> attributeList) { System.out.print("Segment " + segment + ", "); for (Map.Entry<String, AttributeValue> item : attributeList.entrySet()) { String attributeName = item.getKey(); AttributeValue value = item.getValue(); System.out.print(attributeName + " " + (value.getS() == null ? "" : "S=[" + value.getS() + "]") + (value.getN() == null ? "" : "N=[" + value.getN() + "]") + (value.getB() == null ? "" : "B=[" + value.getB() + "]") + (value.getSS() == null ? "" : "SS=[" + value.getSS() + "]") + (value.getNS() == null ? "" : "NS=[" + value.getNS() + "]") + (value.getBS() == null ? "" : "BS=[" + value.getBS() + "]") + ", "); } // Move to next line System.out.println(); } private static void shutDownExecutorService(ExecutorService executor) { executor.shutdown(); try { if (!executor.awaitTermination(10, TimeUnit.SECONDS)) { executor.shutdownNow(); } } catch (InterruptedException e) { executor.shutdownNow(); // Preserve interrupt status Thread.currentThread().interrupt(); } } }