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

com.scalar.db.storage.cosmos.MutateStatementHandler Maven / Gradle / Ivy

Go to download

A universal transaction manager that achieves database-agnostic transactions and distributed transactions that span multiple databases

The newest version!
package com.scalar.db.storage.cosmos;

import com.azure.cosmos.CosmosClient;
import com.azure.cosmos.CosmosException;
import com.scalar.db.api.Mutation;
import com.scalar.db.api.TableMetadata;
import com.scalar.db.common.TableMetadataManager;
import com.scalar.db.common.error.CoreError;
import com.scalar.db.exception.storage.ExecutionException;
import com.scalar.db.exception.storage.NoMutationException;
import com.scalar.db.exception.storage.RetriableExecutionException;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.concurrent.ThreadSafe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** An abstraction for handler classes for mutate statements */
@ThreadSafe
public abstract class MutateStatementHandler extends StatementHandler {
  private static final Logger logger = LoggerFactory.getLogger(MutateStatementHandler.class);
  private static final String MUTATION_STORED_PROCEDURE = "mutate.js";

  public MutateStatementHandler(CosmosClient client, TableMetadataManager metadataManager) {
    super(client, metadataManager);
  }

  /**
   * Executes the specified {@code Mutation}
   *
   * @param mutation a {@code Mutation} to execute
   * @throws ExecutionException if the execution fails
   */
  public void handle(Mutation mutation) throws ExecutionException {
    try {
      execute(mutation);
    } catch (CosmosException e) {
      throwException(e);
    } catch (RuntimeException e) {
      throw new ExecutionException(
          CoreError.COSMOS_ERROR_OCCURRED_IN_MUTATION.buildMessage(e.getMessage()), e);
    }
  }

  abstract void execute(Mutation mutation) throws CosmosException, ExecutionException;

  protected void executeStoredProcedure(Mutation mutation, TableMetadata tableMetadata)
      throws CosmosException {
    CosmosMutation cosmosMutation = new CosmosMutation(mutation, tableMetadata);
    List args = new ArrayList<>();
    args.add(1);
    args.add(cosmosMutation.getMutationType().ordinal());
    args.add(cosmosMutation.makeRecord());
    args.add(cosmosMutation.makeConditionalQuery());

    getContainer(mutation)
        .getScripts()
        .getStoredProcedure(MUTATION_STORED_PROCEDURE)
        .execute(args, cosmosMutation.getStoredProcedureOptions());
  }

  private void throwException(CosmosException exception) throws ExecutionException {
    logger.error(exception.getMessage());
    int statusCode = exception.getSubStatusCode();

    if (statusCode == CosmosErrorCode.PRECONDITION_FAILED.get()) {
      throw new NoMutationException(CoreError.NO_MUTATION_APPLIED.buildMessage(), exception);
    } else if (statusCode == CosmosErrorCode.RETRY_WITH.get()) {
      throw new RetriableExecutionException(
          CoreError.COSMOS_RETRY_WITH_ERROR_OCCURRED_IN_MUTATION.buildMessage(
              exception.getMessage()),
          exception);
    }

    throw new ExecutionException(
        CoreError.COSMOS_ERROR_OCCURRED_IN_MUTATION.buildMessage(exception.getMessage()),
        exception);
  }
}