com.scalar.db.transaction.consensuscommit.ConsensusCommitAdmin Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scalardb Show documentation
Show all versions of scalardb Show documentation
A universal transaction manager that achieves database-agnostic transactions and distributed transactions that span multiple databases
package com.scalar.db.transaction.consensuscommit;
import static com.scalar.db.transaction.consensuscommit.ConsensusCommitUtils.buildTransactionTableMetadata;
import static com.scalar.db.transaction.consensuscommit.ConsensusCommitUtils.getBeforeImageColumnName;
import static com.scalar.db.transaction.consensuscommit.ConsensusCommitUtils.getNonPrimaryKeyColumns;
import static com.scalar.db.transaction.consensuscommit.ConsensusCommitUtils.removeTransactionMetaColumns;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Inject;
import com.scalar.db.api.DistributedStorageAdmin;
import com.scalar.db.api.DistributedTransactionAdmin;
import com.scalar.db.api.TableMetadata;
import com.scalar.db.config.DatabaseConfig;
import com.scalar.db.exception.storage.ExecutionException;
import com.scalar.db.io.DataType;
import com.scalar.db.service.StorageFactory;
import com.scalar.db.util.ScalarDbUtils;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.annotation.concurrent.ThreadSafe;
@ThreadSafe
public class ConsensusCommitAdmin implements DistributedTransactionAdmin {
private final DistributedStorageAdmin admin;
private final String coordinatorNamespace;
private final boolean isIncludeMetadataEnabled;
@SuppressFBWarnings("EI_EXPOSE_REP2")
@Inject
public ConsensusCommitAdmin(DistributedStorageAdmin admin, DatabaseConfig databaseConfig) {
this.admin = admin;
ConsensusCommitConfig config = new ConsensusCommitConfig(databaseConfig);
coordinatorNamespace = config.getCoordinatorNamespace().orElse(Coordinator.NAMESPACE);
isIncludeMetadataEnabled = config.isIncludeMetadataEnabled();
}
public ConsensusCommitAdmin(DatabaseConfig databaseConfig) {
StorageFactory storageFactory = StorageFactory.create(databaseConfig.getProperties());
admin = storageFactory.getStorageAdmin();
ConsensusCommitConfig config = new ConsensusCommitConfig(databaseConfig);
coordinatorNamespace = config.getCoordinatorNamespace().orElse(Coordinator.NAMESPACE);
isIncludeMetadataEnabled = config.isIncludeMetadataEnabled();
}
@VisibleForTesting
ConsensusCommitAdmin(
DistributedStorageAdmin admin,
ConsensusCommitConfig config,
boolean isIncludeMetadataEnabled) {
this.admin = admin;
coordinatorNamespace = config.getCoordinatorNamespace().orElse(Coordinator.NAMESPACE);
this.isIncludeMetadataEnabled = isIncludeMetadataEnabled;
}
@Override
public void createCoordinatorTables(Map options) throws ExecutionException {
if (coordinatorTablesExist()) {
throw new IllegalArgumentException("coordinator tables already exist");
}
admin.createNamespace(coordinatorNamespace, options);
admin.createTable(coordinatorNamespace, Coordinator.TABLE, Coordinator.TABLE_METADATA, options);
}
@Override
public void dropCoordinatorTables() throws ExecutionException {
if (!coordinatorTablesExist()) {
throw new IllegalArgumentException("coordinator tables do not exist");
}
admin.dropTable(coordinatorNamespace, Coordinator.TABLE);
admin.dropNamespace(coordinatorNamespace);
}
@Override
public void truncateCoordinatorTables() throws ExecutionException {
if (!coordinatorTablesExist()) {
throw new IllegalArgumentException("coordinator tables do not exist");
}
admin.truncateTable(coordinatorNamespace, Coordinator.TABLE);
}
@Override
public boolean coordinatorTablesExist() throws ExecutionException {
return admin.tableExists(coordinatorNamespace, Coordinator.TABLE);
}
@Override
public void createNamespace(String namespace, Map options)
throws ExecutionException {
admin.createNamespace(namespace, options);
}
@Override
public void createTable(
String namespace, String table, TableMetadata metadata, Map options)
throws ExecutionException {
admin.createTable(namespace, table, buildTransactionTableMetadata(metadata), options);
}
@Override
public void dropTable(String namespace, String table) throws ExecutionException {
admin.dropTable(namespace, table);
}
@Override
public void dropNamespace(String namespace) throws ExecutionException {
admin.dropNamespace(namespace);
}
@Override
public void truncateTable(String namespace, String table) throws ExecutionException {
admin.truncateTable(namespace, table);
}
@Override
public void createIndex(
String namespace, String table, String columnName, Map options)
throws ExecutionException {
admin.createIndex(namespace, table, columnName, options);
}
@Override
public void dropIndex(String namespace, String table, String columnName)
throws ExecutionException {
admin.dropIndex(namespace, table, columnName);
}
@Override
public TableMetadata getTableMetadata(String namespace, String table) throws ExecutionException {
TableMetadata metadata = admin.getTableMetadata(namespace, table);
if (metadata == null) {
return null;
}
if (!ConsensusCommitUtils.isTransactionTableMetadata(metadata)) {
return null;
}
if (isIncludeMetadataEnabled) {
return metadata;
}
return removeTransactionMetaColumns(metadata);
}
@Override
public Set getNamespaceTableNames(String namespace) throws ExecutionException {
Set tables = new HashSet<>();
for (String table : admin.getNamespaceTableNames(namespace)) {
// Remove non transaction table
if (getTableMetadata(namespace, table) != null) {
tables.add(table);
}
}
return tables;
}
@Override
public boolean namespaceExists(String namespace) throws ExecutionException {
return admin.namespaceExists(namespace);
}
@Override
public void repairTable(
String namespace, String table, TableMetadata metadata, Map options)
throws ExecutionException {
admin.repairTable(namespace, table, buildTransactionTableMetadata(metadata), options);
}
@Override
public void repairCoordinatorTables(Map options) throws ExecutionException {
admin.repairTable(coordinatorNamespace, Coordinator.TABLE, Coordinator.TABLE_METADATA, options);
}
@Override
public void addNewColumnToTable(
String namespace, String table, String columnName, DataType columnType)
throws ExecutionException {
TableMetadata tableMetadata = getTableMetadata(namespace, table);
if (tableMetadata == null) {
throw new IllegalArgumentException(
"Table does not exist: " + ScalarDbUtils.getFullTableName(namespace, table));
}
String beforeColumnName = getBeforeImageColumnName(columnName, tableMetadata);
admin.addNewColumnToTable(namespace, table, columnName, columnType);
admin.addNewColumnToTable(namespace, table, beforeColumnName, columnType);
}
@Override
public void importTable(String namespace, String table) throws ExecutionException {
TableMetadata tableMetadata = getTableMetadata(namespace, table);
if (tableMetadata != null) {
throw new IllegalArgumentException(
"Table already exists: " + ScalarDbUtils.getFullTableName(namespace, table));
}
tableMetadata = admin.getImportTableMetadata(namespace, table);
// add transaction metadata columns
for (Map.Entry entry :
ConsensusCommitUtils.getTransactionMetaColumns().entrySet()) {
admin.addRawColumnToTable(namespace, table, entry.getKey(), entry.getValue());
}
// add before image columns
Set nonPrimaryKeyColumns = getNonPrimaryKeyColumns(tableMetadata);
for (String columnName : nonPrimaryKeyColumns) {
String beforeColumnName = getBeforeImageColumnName(columnName, tableMetadata);
DataType columnType = tableMetadata.getColumnDataType(columnName);
admin.addRawColumnToTable(namespace, table, beforeColumnName, columnType);
}
// add ScalarDB metadata
admin.repairTable(
namespace, table, buildTransactionTableMetadata(tableMetadata), ImmutableMap.of());
}
@Override
public void close() {
admin.close();
}
}