All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.hudi.aws.utils.DynamoTableUtils Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License 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 org.apache.hudi.aws.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.core.exception.SdkClientException;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest;
import software.amazon.awssdk.services.dynamodb.model.DeleteTableRequest;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest;
import software.amazon.awssdk.services.dynamodb.model.ResourceInUseException;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;
import software.amazon.awssdk.services.dynamodb.model.TableDescription;
import software.amazon.awssdk.services.dynamodb.model.TableStatus;

/**
 * Reused code from https://github.com/aws/aws-sdk-java-v2/blob/master/services/dynamodb/src/test/java/utils/test/util/TableUtils.java
 *
 * Utility methods for working with DynamoDB tables.
 *
 * 
 * // ... create DynamoDB table ...
 * try {
 *     waitUntilActive(dynamoDB, myTableName());
 * } catch (SdkClientException e) {
 *     // table didn't become active
 * }
 * // ... start making calls to table ...
 * 
*/ public class DynamoTableUtils { private static final int DEFAULT_WAIT_TIMEOUT = 20 * 60 * 1000; private static final int DEFAULT_WAIT_INTERVAL = 10 * 1000; /** * The logging utility. */ private static final Logger LOGGER = LoggerFactory.getLogger(DynamoTableUtils.class); /** * Waits up to 10 minutes for a specified DynamoDB table to resolve, * indicating that it exists. If the table doesn't return a result after * this time, a SdkClientException is thrown. * * @param dynamo * The DynamoDB client to use to make requests. * @param tableName * The name of the table being resolved. * * @throws SdkClientException * If the specified table does not resolve before this method * times out and stops polling. * @throws InterruptedException * If the thread is interrupted while waiting for the table to * resolve. */ public static void waitUntilExists(final DynamoDbClient dynamo, final String tableName) throws InterruptedException { waitUntilExists(dynamo, tableName, DEFAULT_WAIT_TIMEOUT, DEFAULT_WAIT_INTERVAL); } /** * Waits up to a specified amount of time for a specified DynamoDB table to * resolve, indicating that it exists. If the table doesn't return a result * after this time, a SdkClientException is thrown. * * @param dynamo * The DynamoDB client to use to make requests. * @param tableName * The name of the table being resolved. * @param timeout * The maximum number of milliseconds to wait. * @param interval * The poll interval in milliseconds. * * @throws SdkClientException * If the specified table does not resolve before this method * times out and stops polling. * @throws InterruptedException * If the thread is interrupted while waiting for the table to * resolve. */ public static void waitUntilExists(final DynamoDbClient dynamo, final String tableName, final int timeout, final int interval) throws InterruptedException { TableDescription table = waitForTableDescription(dynamo, tableName, null, timeout, interval); if (table == null) { throw SdkClientException.builder().message("Table " + tableName + " never returned a result").build(); } } /** * Waits up to 10 minutes for a specified DynamoDB table to move into the * ACTIVE state. If the table does not exist or does not * transition to the ACTIVE state after this time, then * SdkClientException is thrown. * * @param dynamo * The DynamoDB client to use to make requests. * @param tableName * The name of the table whose status is being checked. * * @throws TableNeverTransitionedToStateException * If the specified table does not exist or does not transition * into the ACTIVE state before this method times * out and stops polling. * @throws InterruptedException * If the thread is interrupted while waiting for the table to * transition into the ACTIVE state. */ public static void waitUntilActive(final DynamoDbClient dynamo, final String tableName) throws InterruptedException, TableNeverTransitionedToStateException { waitUntilActive(dynamo, tableName, DEFAULT_WAIT_TIMEOUT, DEFAULT_WAIT_INTERVAL); } /** * Waits up to a specified amount of time for a specified DynamoDB table to * move into the ACTIVE state. If the table does not exist or * does not transition to the ACTIVE state after this time, * then a SdkClientException is thrown. * * @param dynamo * The DynamoDB client to use to make requests. * @param tableName * The name of the table whose status is being checked. * @param timeout * The maximum number of milliseconds to wait. * @param interval * The poll interval in milliseconds. * * @throws TableNeverTransitionedToStateException * If the specified table does not exist or does not transition * into the ACTIVE state before this method times * out and stops polling. * @throws InterruptedException * If the thread is interrupted while waiting for the table to * transition into the ACTIVE state. */ public static void waitUntilActive(final DynamoDbClient dynamo, final String tableName, final int timeout, final int interval) throws InterruptedException, TableNeverTransitionedToStateException { TableDescription table = waitForTableDescription(dynamo, tableName, TableStatus.ACTIVE, timeout, interval); if (table == null || !table.tableStatus().equals(TableStatus.ACTIVE)) { throw new TableNeverTransitionedToStateException(tableName, TableStatus.ACTIVE); } } /** * Wait for the table to reach the desired status and returns the table * description * * @param dynamo * Dynamo client to use * @param tableName * Table name to poll status of * @param desiredStatus * Desired {@link TableStatus} to wait for. If null this method * simply waits until DescribeTable returns something non-null * (i.e. any status) * @param timeout * Timeout in milliseconds to continue to poll for desired status * @param interval * Time to wait in milliseconds between poll attempts * @return Null if DescribeTables never returns a result, otherwise the * result of the last poll attempt (which may or may not have the * desired state) * @throws {@link * IllegalArgumentException} If timeout or interval is invalid */ private static TableDescription waitForTableDescription(final DynamoDbClient dynamo, final String tableName, TableStatus desiredStatus, final int timeout, final int interval) throws InterruptedException, IllegalArgumentException { if (timeout < 0) { throw new IllegalArgumentException("Timeout must be >= 0"); } if (interval <= 0 || interval >= timeout) { throw new IllegalArgumentException("Interval must be > 0 and < timeout"); } long startTime = System.currentTimeMillis(); long endTime = startTime + timeout; TableDescription table = null; while (System.currentTimeMillis() < endTime) { try { table = dynamo.describeTable(DescribeTableRequest.builder().tableName(tableName).build()).table(); if (desiredStatus == null || table.tableStatus().equals(desiredStatus)) { return table; } } catch (ResourceNotFoundException rnfe) { // ResourceNotFound means the table doesn't exist yet, // so ignore this error and just keep polling. } Thread.sleep(interval); } return table; } /** * Creates the table and ignores any errors if it already exists. * @param dynamo The Dynamo client to use. * @param createTableRequest The create table request. * @return True if created, false otherwise. */ public static boolean createTableIfNotExists(final DynamoDbClient dynamo, final CreateTableRequest createTableRequest) { try { dynamo.createTable(createTableRequest); return true; } catch (final ResourceInUseException e) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Table " + createTableRequest.tableName() + " already exists", e); } } return false; } /** * Deletes the table and ignores any errors if it doesn't exist. * @param dynamo The Dynamo client to use. * @param deleteTableRequest The delete table request. * @return True if deleted, false otherwise. */ public static boolean deleteTableIfExists(final DynamoDbClient dynamo, final DeleteTableRequest deleteTableRequest) { try { dynamo.deleteTable(deleteTableRequest); return true; } catch (final ResourceNotFoundException e) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Table " + deleteTableRequest.tableName() + " does not exist", e); } } return false; } /** * Thrown by {@link DynamoTableUtils} when a table never reaches a desired state */ public static class TableNeverTransitionedToStateException extends SdkClientException { private static final long serialVersionUID = 8920567021104846647L; public TableNeverTransitionedToStateException(String tableName, TableStatus desiredStatus) { super(SdkClientException.builder() .message("Table " + tableName + " never transitioned to desired state of " + desiredStatus.toString())); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy