diff --git a/core/src/integration-test/java/com/scalar/db/storage/cassandra/CassandraMutationAtomicityUnitIntegrationTest.java b/core/src/integration-test/java/com/scalar/db/storage/cassandra/CassandraAtomicityUnitIntegrationTest.java similarity index 64% rename from core/src/integration-test/java/com/scalar/db/storage/cassandra/CassandraMutationAtomicityUnitIntegrationTest.java rename to core/src/integration-test/java/com/scalar/db/storage/cassandra/CassandraAtomicityUnitIntegrationTest.java index 1a9af7ebf0..eef4e9569a 100644 --- a/core/src/integration-test/java/com/scalar/db/storage/cassandra/CassandraMutationAtomicityUnitIntegrationTest.java +++ b/core/src/integration-test/java/com/scalar/db/storage/cassandra/CassandraAtomicityUnitIntegrationTest.java @@ -1,12 +1,12 @@ package com.scalar.db.storage.cassandra; -import com.scalar.db.api.DistributedStorageMutationAtomicityUnitIntegrationTestBase; +import com.scalar.db.api.DistributedStorageAtomicityUnitIntegrationTestBase; import java.util.Collections; import java.util.Map; import java.util.Properties; -public class CassandraMutationAtomicityUnitIntegrationTest - extends DistributedStorageMutationAtomicityUnitIntegrationTestBase { +public class CassandraAtomicityUnitIntegrationTest + extends DistributedStorageAtomicityUnitIntegrationTestBase { @Override protected Properties getProperties(String testName) { diff --git a/core/src/integration-test/java/com/scalar/db/storage/cosmos/CosmosMutationAtomicityUnitIntegrationTest.java b/core/src/integration-test/java/com/scalar/db/storage/cosmos/CosmosAtomicityUnitIntegrationTest.java similarity index 57% rename from core/src/integration-test/java/com/scalar/db/storage/cosmos/CosmosMutationAtomicityUnitIntegrationTest.java rename to core/src/integration-test/java/com/scalar/db/storage/cosmos/CosmosAtomicityUnitIntegrationTest.java index 7cb3dc8913..a47e8acf30 100644 --- a/core/src/integration-test/java/com/scalar/db/storage/cosmos/CosmosMutationAtomicityUnitIntegrationTest.java +++ b/core/src/integration-test/java/com/scalar/db/storage/cosmos/CosmosAtomicityUnitIntegrationTest.java @@ -1,12 +1,12 @@ package com.scalar.db.storage.cosmos; -import com.scalar.db.api.DistributedStorageMutationAtomicityUnitIntegrationTestBase; +import com.scalar.db.api.DistributedStorageAtomicityUnitIntegrationTestBase; import java.util.Map; import java.util.Properties; import org.junit.jupiter.api.Disabled; -public class CosmosMutationAtomicityUnitIntegrationTest - extends DistributedStorageMutationAtomicityUnitIntegrationTestBase { +public class CosmosAtomicityUnitIntegrationTest + extends DistributedStorageAtomicityUnitIntegrationTestBase { @Override protected Properties getProperties(String testName) { @@ -20,6 +20,5 @@ protected Map getCreationOptions() { @Disabled("This test fails. It might be a bug") @Override - public void - mutate_MutationsWithinRecordGiven_ShouldBehaveCorrectlyBaseOnMutationAtomicityUnit() {} + public void mutate_MutationsWithinRecordGiven_ShouldBehaveCorrectlyBaseOnAtomicityUnit() {} } diff --git a/core/src/integration-test/java/com/scalar/db/storage/dynamo/DynamoMutationAtomicityUnitIntegrationTest.java b/core/src/integration-test/java/com/scalar/db/storage/dynamo/DynamoAtomicityUnitIntegrationTest.java similarity index 59% rename from core/src/integration-test/java/com/scalar/db/storage/dynamo/DynamoMutationAtomicityUnitIntegrationTest.java rename to core/src/integration-test/java/com/scalar/db/storage/dynamo/DynamoAtomicityUnitIntegrationTest.java index b16a33a982..b16997c22c 100644 --- a/core/src/integration-test/java/com/scalar/db/storage/dynamo/DynamoMutationAtomicityUnitIntegrationTest.java +++ b/core/src/integration-test/java/com/scalar/db/storage/dynamo/DynamoAtomicityUnitIntegrationTest.java @@ -1,12 +1,12 @@ package com.scalar.db.storage.dynamo; -import com.scalar.db.api.DistributedStorageMutationAtomicityUnitIntegrationTestBase; +import com.scalar.db.api.DistributedStorageAtomicityUnitIntegrationTestBase; import java.util.Map; import java.util.Properties; import org.junit.jupiter.api.Disabled; -public class DynamoMutationAtomicityUnitIntegrationTest - extends DistributedStorageMutationAtomicityUnitIntegrationTestBase { +public class DynamoAtomicityUnitIntegrationTest + extends DistributedStorageAtomicityUnitIntegrationTestBase { @Override protected Properties getProperties(String testName) { @@ -20,6 +20,5 @@ protected Map getCreationOptions() { @Disabled("Transaction request cannot include multiple operations on one item in DynamoDB") @Override - public void - mutate_MutationsWithinRecordGiven_ShouldBehaveCorrectlyBaseOnMutationAtomicityUnit() {} + public void mutate_MutationsWithinRecordGiven_ShouldBehaveCorrectlyBaseOnAtomicityUnit() {} } diff --git a/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcDatabaseAtomicityUnitIntegrationTest.java b/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcDatabaseAtomicityUnitIntegrationTest.java new file mode 100644 index 0000000000..b7e6815755 --- /dev/null +++ b/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcDatabaseAtomicityUnitIntegrationTest.java @@ -0,0 +1,13 @@ +package com.scalar.db.storage.jdbc; + +import com.scalar.db.api.DistributedStorageAtomicityUnitIntegrationTestBase; +import java.util.Properties; + +public class JdbcDatabaseAtomicityUnitIntegrationTest + extends DistributedStorageAtomicityUnitIntegrationTestBase { + + @Override + protected Properties getProperties(String testName) { + return JdbcEnv.getProperties(testName); + } +} diff --git a/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcDatabaseMutationAtomicityUnitIntegrationTest.java b/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcDatabaseMutationAtomicityUnitIntegrationTest.java deleted file mode 100644 index eb01cb4ab8..0000000000 --- a/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcDatabaseMutationAtomicityUnitIntegrationTest.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.scalar.db.storage.jdbc; - -import com.scalar.db.api.DistributedStorageMutationAtomicityUnitIntegrationTestBase; -import java.util.Properties; - -public class JdbcDatabaseMutationAtomicityUnitIntegrationTest - extends DistributedStorageMutationAtomicityUnitIntegrationTestBase { - - @Override - protected Properties getProperties(String testName) { - return JdbcEnv.getProperties(testName); - } -} diff --git a/core/src/integration-test/java/com/scalar/db/storage/multistorage/MultiStorageMutationAtomicityUnitIntegrationTest.java b/core/src/integration-test/java/com/scalar/db/storage/multistorage/MultiStorageAtomicityUnitIntegrationTest.java similarity index 92% rename from core/src/integration-test/java/com/scalar/db/storage/multistorage/MultiStorageMutationAtomicityUnitIntegrationTest.java rename to core/src/integration-test/java/com/scalar/db/storage/multistorage/MultiStorageAtomicityUnitIntegrationTest.java index 321080d983..887cd79e85 100644 --- a/core/src/integration-test/java/com/scalar/db/storage/multistorage/MultiStorageMutationAtomicityUnitIntegrationTest.java +++ b/core/src/integration-test/java/com/scalar/db/storage/multistorage/MultiStorageAtomicityUnitIntegrationTest.java @@ -2,7 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; -import com.scalar.db.api.DistributedStorageMutationAtomicityUnitIntegrationTestBase; +import com.scalar.db.api.DistributedStorageAtomicityUnitIntegrationTestBase; import com.scalar.db.api.Put; import com.scalar.db.config.DatabaseConfig; import com.scalar.db.exception.storage.ExecutionException; @@ -12,8 +12,8 @@ import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; -public class MultiStorageMutationAtomicityUnitIntegrationTest - extends DistributedStorageMutationAtomicityUnitIntegrationTestBase { +public class MultiStorageAtomicityUnitIntegrationTest + extends DistributedStorageAtomicityUnitIntegrationTestBase { @Override public Properties getProperties(String testName) { @@ -61,7 +61,7 @@ public Properties getProperties(String testName) { } @Test - public void mutate_MutationsAcrossStorageGiven_ShouldBehaveCorrectlyBaseOnMutationAtomicityUnit() + public void mutate_MutationsAcrossStorageGiven_ShouldBehaveCorrectlyBaseOnAtomicityUnit() throws ExecutionException { // Arrange Put put1 = diff --git a/core/src/integration-test/java/com/scalar/db/storage/objectstorage/ObjectStorageMutationAtomicityUnitIntegrationTest.java b/core/src/integration-test/java/com/scalar/db/storage/objectstorage/ObjectStorageAtomicityUnitIntegrationTest.java similarity index 61% rename from core/src/integration-test/java/com/scalar/db/storage/objectstorage/ObjectStorageMutationAtomicityUnitIntegrationTest.java rename to core/src/integration-test/java/com/scalar/db/storage/objectstorage/ObjectStorageAtomicityUnitIntegrationTest.java index 98c4ea857f..68e27e93ed 100644 --- a/core/src/integration-test/java/com/scalar/db/storage/objectstorage/ObjectStorageMutationAtomicityUnitIntegrationTest.java +++ b/core/src/integration-test/java/com/scalar/db/storage/objectstorage/ObjectStorageAtomicityUnitIntegrationTest.java @@ -1,11 +1,11 @@ package com.scalar.db.storage.objectstorage; -import com.scalar.db.api.DistributedStorageMutationAtomicityUnitIntegrationTestBase; +import com.scalar.db.api.DistributedStorageAtomicityUnitIntegrationTestBase; import java.util.Map; import java.util.Properties; -public class ObjectStorageMutationAtomicityUnitIntegrationTest - extends DistributedStorageMutationAtomicityUnitIntegrationTestBase { +public class ObjectStorageAtomicityUnitIntegrationTest + extends DistributedStorageAtomicityUnitIntegrationTestBase { @Override protected Properties getProperties(String testName) { diff --git a/core/src/main/java/com/scalar/db/api/DistributedStorage.java b/core/src/main/java/com/scalar/db/api/DistributedStorage.java index 36ca679075..278c22410a 100644 --- a/core/src/main/java/com/scalar/db/api/DistributedStorage.java +++ b/core/src/main/java/com/scalar/db/api/DistributedStorage.java @@ -182,10 +182,10 @@ public interface DistributedStorage extends AutoCloseable { * Mutates entries of the underlying storage with the specified list of {@link Mutation} commands. * *

Note that this method only supports mutations within the atomicity unit specified by {@link - * StorageInfo#getMutationAtomicityUnit()}. For example, if the atomicity unit of the storage is - * {@link StorageInfo.MutationAtomicityUnit#PARTITION}, the mutations must occur within the same - * partition. Also note that the maximum number of mutations that can be performed atomically is - * defined by {@link StorageInfo#getMaxAtomicMutationsCount()}. + * StorageInfo#getAtomicityUnit()}. For example, if the atomicity unit of the storage is {@link + * StorageInfo.AtomicityUnit#PARTITION}, the mutations must occur within the same partition. Also + * note that the maximum number of mutations that can be performed atomically is defined by {@link + * StorageInfo#getMaxAtomicMutationsCount()}. * *

To retrieve storage information, use {@link DistributedStorageAdmin#getStorageInfo(String)}. * diff --git a/core/src/main/java/com/scalar/db/api/DistributedStorageAdmin.java b/core/src/main/java/com/scalar/db/api/DistributedStorageAdmin.java index bcc16eb30c..a45c69e317 100644 --- a/core/src/main/java/com/scalar/db/api/DistributedStorageAdmin.java +++ b/core/src/main/java/com/scalar/db/api/DistributedStorageAdmin.java @@ -47,6 +47,9 @@ public interface DistributedStorageAdmin extends Admin, AutoCloseable { /** * Returns the storage information. * + *

Note: This feature is primarily for internal use. Breaking changes can and will be + * introduced to it. Users should not depend on it. + * * @param namespace the namespace to get the storage information for * @return the storage information * @throws ExecutionException if the operation fails diff --git a/core/src/main/java/com/scalar/db/api/StorageInfo.java b/core/src/main/java/com/scalar/db/api/StorageInfo.java index 507f974318..bf93868d8d 100644 --- a/core/src/main/java/com/scalar/db/api/StorageInfo.java +++ b/core/src/main/java/com/scalar/db/api/StorageInfo.java @@ -1,5 +1,6 @@ package com.scalar.db.api; +/** Represents storage information. */ public interface StorageInfo { /** * Returns the storage name. @@ -9,11 +10,11 @@ public interface StorageInfo { String getStorageName(); /** - * Returns the mutation atomicity unit of the storage. + * Returns the atomicity unit of the storage. * - * @return the mutation atomicity unit of the storage + * @return the atomicity unit of the storage */ - MutationAtomicityUnit getMutationAtomicityUnit(); + AtomicityUnit getAtomicityUnit(); /** * Returns the maximum number of mutations that can be performed atomically in the storage. @@ -23,38 +24,45 @@ public interface StorageInfo { int getMaxAtomicMutationsCount(); /** - * The mutation atomicity unit of the storage. + * Returns whether the storage guarantees consistent reads within its atomicity unit. * - *

This enum defines the atomicity unit for mutations in the storage. It determines the scope - * of atomicity for mutations such as put and delete. + * @return true if the storage guarantees consistent reads within its atomicity unit, false + * otherwise */ - enum MutationAtomicityUnit { + boolean isConsistentReadGuaranteed(); + + /** + * The atomicity unit of the storage. + * + *

This enum defines the atomicity unit for operations in the storage. + */ + enum AtomicityUnit { /** - * The atomicity unit is at the record level, meaning that mutations are performed atomically + * The atomicity unit is at the record level, meaning that operations are performed atomically * for each record. */ RECORD, /** - * The atomicity unit is at the partition level, meaning that mutations are performed atomically - * for each partition. + * The atomicity unit is at the partition level, meaning that operations are performed + * atomically for each partition. */ PARTITION, /** - * The atomicity unit is at the table level, meaning that mutations are performed atomically for - * each table. + * The atomicity unit is at the table level, meaning that operations are performed atomically + * for each table. */ TABLE, /** - * The atomicity unit is at the namespace level, meaning that mutations are performed atomically - * for each namespace. + * The atomicity unit is at the namespace level, meaning that operations are performed + * atomically for each namespace. */ NAMESPACE, /** - * The atomicity unit is at the storage level, meaning that mutations are performed atomically + * The atomicity unit is at the storage level, meaning that operations are performed atomically * for the entire storage. */ STORAGE diff --git a/core/src/main/java/com/scalar/db/common/CommonDistributedStorageAdmin.java b/core/src/main/java/com/scalar/db/common/CommonDistributedStorageAdmin.java index 27f7060c8c..54a5fa9c7c 100644 --- a/core/src/main/java/com/scalar/db/common/CommonDistributedStorageAdmin.java +++ b/core/src/main/java/com/scalar/db/common/CommonDistributedStorageAdmin.java @@ -513,7 +513,7 @@ public void createVirtualTable( Map options) throws ExecutionException { StorageInfo storageInfo = getStorageInfo(leftSourceNamespace); - switch (storageInfo.getMutationAtomicityUnit()) { + switch (storageInfo.getAtomicityUnit()) { case STORAGE: break; case NAMESPACE: @@ -521,7 +521,7 @@ public void createVirtualTable( throw new IllegalArgumentException( CoreError.VIRTUAL_TABLE_SOURCE_TABLES_OUTSIDE_OF_ATOMICITY_UNIT.buildMessage( storageInfo.getStorageName(), - storageInfo.getMutationAtomicityUnit(), + storageInfo.getAtomicityUnit(), ScalarDbUtils.getFullTableName(leftSourceNamespace, leftSourceTable), ScalarDbUtils.getFullTableName(rightSourceNamespace, rightSourceTable))); } @@ -529,7 +529,7 @@ public void createVirtualTable( default: throw new UnsupportedOperationException( CoreError.VIRTUAL_TABLE_NOT_SUPPORTED_IN_STORAGE.buildMessage( - storageInfo.getStorageName(), storageInfo.getMutationAtomicityUnit())); + storageInfo.getStorageName(), storageInfo.getAtomicityUnit())); } if (!namespaceExists(namespace)) { diff --git a/core/src/main/java/com/scalar/db/common/StorageInfoImpl.java b/core/src/main/java/com/scalar/db/common/StorageInfoImpl.java index 2f3fc48a1e..a05cdf752c 100644 --- a/core/src/main/java/com/scalar/db/common/StorageInfoImpl.java +++ b/core/src/main/java/com/scalar/db/common/StorageInfoImpl.java @@ -9,16 +9,19 @@ public class StorageInfoImpl implements StorageInfo { private final String storageName; - private final MutationAtomicityUnit mutationAtomicityUnit; + private final AtomicityUnit atomicityUnit; private final int maxAtomicMutationsCount; + private final boolean consistentReadGuaranteed; public StorageInfoImpl( String storageName, - MutationAtomicityUnit mutationAtomicityUnit, - int maxAtomicMutationsCount) { + AtomicityUnit atomicityUnit, + int maxAtomicMutationsCount, + boolean consistentReadGuaranteed) { this.storageName = storageName; - this.mutationAtomicityUnit = mutationAtomicityUnit; + this.atomicityUnit = atomicityUnit; this.maxAtomicMutationsCount = maxAtomicMutationsCount; + this.consistentReadGuaranteed = consistentReadGuaranteed; } @Override @@ -27,8 +30,8 @@ public String getStorageName() { } @Override - public MutationAtomicityUnit getMutationAtomicityUnit() { - return mutationAtomicityUnit; + public AtomicityUnit getAtomicityUnit() { + return atomicityUnit; } @Override @@ -36,6 +39,11 @@ public int getMaxAtomicMutationsCount() { return maxAtomicMutationsCount; } + @Override + public boolean isConsistentReadGuaranteed() { + return consistentReadGuaranteed; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -47,20 +55,26 @@ public boolean equals(Object o) { StorageInfoImpl that = (StorageInfoImpl) o; return getMaxAtomicMutationsCount() == that.getMaxAtomicMutationsCount() && Objects.equals(getStorageName(), that.getStorageName()) - && getMutationAtomicityUnit() == that.getMutationAtomicityUnit(); + && getAtomicityUnit() == that.getAtomicityUnit() + && isConsistentReadGuaranteed() == that.isConsistentReadGuaranteed(); } @Override public int hashCode() { - return Objects.hash(getStorageName(), getMutationAtomicityUnit(), getMaxAtomicMutationsCount()); + return Objects.hash( + getStorageName(), + getAtomicityUnit(), + getMaxAtomicMutationsCount(), + isConsistentReadGuaranteed()); } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("storageName", storageName) - .add("mutationAtomicityUnit", mutationAtomicityUnit) + .add("atomicityUnit", atomicityUnit) .add("maxAtomicMutationsCount", maxAtomicMutationsCount) + .add("consistentReadGuaranteed", consistentReadGuaranteed) .toString(); } } diff --git a/core/src/main/java/com/scalar/db/common/checker/OperationChecker.java b/core/src/main/java/com/scalar/db/common/checker/OperationChecker.java index 0cc122656d..181082a335 100644 --- a/core/src/main/java/com/scalar/db/common/checker/OperationChecker.java +++ b/core/src/main/java/com/scalar/db/common/checker/OperationChecker.java @@ -373,7 +373,7 @@ private boolean isOutOfAtomicityUnit( && mutation2.forNamespace().isPresent() && mutation2.forTable().isPresent(); - switch (storageInfo1.getMutationAtomicityUnit()) { + switch (storageInfo1.getAtomicityUnit()) { case RECORD: if (!mutation1.getClusteringKey().equals(mutation2.getClusteringKey())) { return true; // Different clustering keys @@ -402,8 +402,7 @@ private boolean isOutOfAtomicityUnit( } break; default: - throw new AssertionError( - "Unknown mutation atomicity unit: " + storageInfo1.getMutationAtomicityUnit()); + throw new AssertionError("Unknown atomicity unit: " + storageInfo1.getAtomicityUnit()); } return false; @@ -411,7 +410,7 @@ private boolean isOutOfAtomicityUnit( private String getErrorMessageForOutOfAtomicityUnit( StorageInfo storageInfo, List mutations) { - switch (storageInfo.getMutationAtomicityUnit()) { + switch (storageInfo.getAtomicityUnit()) { case RECORD: return CoreError.OPERATION_CHECK_ERROR_MULTI_RECORD_MUTATION.buildMessage( storageInfo.getStorageName(), mutations); @@ -427,8 +426,7 @@ private String getErrorMessageForOutOfAtomicityUnit( case STORAGE: return CoreError.OPERATION_CHECK_ERROR_MULTI_STORAGE_MUTATION.buildMessage(mutations); default: - throw new AssertionError( - "Unknown mutation atomicity unit: " + storageInfo.getMutationAtomicityUnit()); + throw new AssertionError("Unknown atomicity unit: " + storageInfo.getAtomicityUnit()); } } diff --git a/core/src/main/java/com/scalar/db/storage/cassandra/CassandraAdmin.java b/core/src/main/java/com/scalar/db/storage/cassandra/CassandraAdmin.java index 9a60eb15b9..002299a60d 100644 --- a/core/src/main/java/com/scalar/db/storage/cassandra/CassandraAdmin.java +++ b/core/src/main/java/com/scalar/db/storage/cassandra/CassandraAdmin.java @@ -55,9 +55,10 @@ public class CassandraAdmin implements DistributedStorageAdmin { private static final StorageInfo STORAGE_INFO = new StorageInfoImpl( "cassandra", - StorageInfo.MutationAtomicityUnit.PARTITION, + StorageInfo.AtomicityUnit.PARTITION, // No limit on the number of mutations - Integer.MAX_VALUE); + Integer.MAX_VALUE, + true); private final ClusterManager clusterManager; private final String metadataKeyspace; diff --git a/core/src/main/java/com/scalar/db/storage/cosmos/CosmosAdmin.java b/core/src/main/java/com/scalar/db/storage/cosmos/CosmosAdmin.java index 3836b06443..e23586dd75 100644 --- a/core/src/main/java/com/scalar/db/storage/cosmos/CosmosAdmin.java +++ b/core/src/main/java/com/scalar/db/storage/cosmos/CosmosAdmin.java @@ -72,9 +72,10 @@ public class CosmosAdmin implements DistributedStorageAdmin { private static final StorageInfo STORAGE_INFO = new StorageInfoImpl( "cosmos", - StorageInfo.MutationAtomicityUnit.PARTITION, + StorageInfo.AtomicityUnit.PARTITION, // No limit on the number of mutations - Integer.MAX_VALUE); + Integer.MAX_VALUE, + true); private final CosmosClient client; private final String metadataDatabase; diff --git a/core/src/main/java/com/scalar/db/storage/dynamo/DynamoAdmin.java b/core/src/main/java/com/scalar/db/storage/dynamo/DynamoAdmin.java index fc420242db..b6ca2cd324 100644 --- a/core/src/main/java/com/scalar/db/storage/dynamo/DynamoAdmin.java +++ b/core/src/main/java/com/scalar/db/storage/dynamo/DynamoAdmin.java @@ -163,9 +163,11 @@ public class DynamoAdmin implements DistributedStorageAdmin { private static final StorageInfo STORAGE_INFO = new StorageInfoImpl( "dynamo", - StorageInfo.MutationAtomicityUnit.STORAGE, + StorageInfo.AtomicityUnit.STORAGE, // DynamoDB has a limit of 100 items per transactional batch write operation - 100); + 100, + // TODO false for now as DynamoDB's Scan and Query support READ_COMMITTED isolation level + false); private final DynamoDbClient client; private final ApplicationAutoScalingClient applicationAutoScalingClient; diff --git a/core/src/main/java/com/scalar/db/storage/jdbc/JdbcAdmin.java b/core/src/main/java/com/scalar/db/storage/jdbc/JdbcAdmin.java index 4a1d505f4d..aa0f62e935 100644 --- a/core/src/main/java/com/scalar/db/storage/jdbc/JdbcAdmin.java +++ b/core/src/main/java/com/scalar/db/storage/jdbc/JdbcAdmin.java @@ -53,12 +53,6 @@ public class JdbcAdmin implements DistributedStorageAdmin { @VisibleForTesting static final String JDBC_COL_DECIMAL_DIGITS = "DECIMAL_DIGITS"; private static final String INDEX_NAME_PREFIX = "index"; - private static final StorageInfo STORAGE_INFO = - new StorageInfoImpl( - "jdbc", - StorageInfo.MutationAtomicityUnit.STORAGE, - // No limit on the number of mutations - Integer.MAX_VALUE); private final RdbEngineStrategy rdbEngine; private final BasicDataSource dataSource; @@ -1011,8 +1005,22 @@ public void upgrade(Map options) throws ExecutionException { } @Override - public StorageInfo getStorageInfo(String namespace) { - return STORAGE_INFO; + public StorageInfo getStorageInfo(String namespace) throws ExecutionException { + boolean consistentReadGuaranteed; + try (Connection connection = dataSource.getConnection()) { + int isolationLevel = connection.getTransactionIsolation(); + consistentReadGuaranteed = + isolationLevel >= rdbEngine.getMinimumIsolationLevelForConsistencyRead(); + } catch (SQLException e) { + throw new ExecutionException("Getting the transaction isolation level failed", e); + } + + return new StorageInfoImpl( + "jdbc", + StorageInfo.AtomicityUnit.STORAGE, + // No limit on the number of mutations + Integer.MAX_VALUE, + consistentReadGuaranteed); } @Override diff --git a/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineDb2.java b/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineDb2.java index 3eb0ac10f7..fba17bbed8 100644 --- a/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineDb2.java +++ b/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineDb2.java @@ -20,6 +20,7 @@ import com.scalar.db.storage.jdbc.query.SelectQuery; import com.scalar.db.storage.jdbc.query.SelectWithLimitQuery; import com.scalar.db.storage.jdbc.query.UpsertQuery; +import java.sql.Connection; import java.sql.Driver; import java.sql.JDBCType; import java.sql.ResultSet; @@ -588,4 +589,10 @@ public void throwIfCrossPartitionScanOrderingOnBlobColumnNotSupported( public String getTableNamesInNamespaceSql() { return "SELECT TABNAME FROM SYSCAT.TABLES WHERE TABSCHEMA = ? AND TYPE = 'T'"; } + + @Override + public int getMinimumIsolationLevelForConsistencyRead() { + // In Db2, REPEATABLE READ and SERIALIZABLE isolation levels guarantee consistent reads + return Connection.TRANSACTION_REPEATABLE_READ; + } } diff --git a/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineMysql.java b/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineMysql.java index 2e96583c1b..e04ca904be 100644 --- a/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineMysql.java +++ b/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineMysql.java @@ -509,4 +509,10 @@ public void setConnectionToReadOnly(Connection connection, boolean readOnly) thr public String getTableNamesInNamespaceSql() { return "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = ?"; } + + @Override + public int getMinimumIsolationLevelForConsistencyRead() { + // In MySQL, REPEATABLE READ and SERIALIZABLE isolation levels guarantee consistent reads. + return Connection.TRANSACTION_REPEATABLE_READ; + } } diff --git a/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineOracle.java b/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineOracle.java index ba8e00060c..eefa209486 100644 --- a/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineOracle.java +++ b/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineOracle.java @@ -18,6 +18,7 @@ import com.scalar.db.storage.jdbc.query.UpsertQuery; import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.sql.Connection; import java.sql.Driver; import java.sql.JDBCType; import java.sql.PreparedStatement; @@ -540,4 +541,10 @@ public void bindBlobColumnToPreparedStatement( public String getTableNamesInNamespaceSql() { return "SELECT TABLE_NAME FROM ALL_TABLES WHERE OWNER = ?"; } + + @Override + public int getMinimumIsolationLevelForConsistencyRead() { + // In Oracle, only the SERIALIZABLE isolation level guarantees consistent reads + return Connection.TRANSACTION_SERIALIZABLE; + } } diff --git a/core/src/main/java/com/scalar/db/storage/jdbc/RdbEnginePostgresql.java b/core/src/main/java/com/scalar/db/storage/jdbc/RdbEnginePostgresql.java index 33ba3bed7c..7ee7e0c3b7 100644 --- a/core/src/main/java/com/scalar/db/storage/jdbc/RdbEnginePostgresql.java +++ b/core/src/main/java/com/scalar/db/storage/jdbc/RdbEnginePostgresql.java @@ -10,6 +10,7 @@ import com.scalar.db.storage.jdbc.query.SelectQuery; import com.scalar.db.storage.jdbc.query.SelectWithLimitQuery; import com.scalar.db.storage.jdbc.query.UpsertQuery; +import java.sql.Connection; import java.sql.Driver; import java.sql.JDBCType; import java.sql.SQLException; @@ -400,4 +401,10 @@ public String tryAddIfNotExistsToCreateIndexSql(String createIndexSql) { public String getTableNamesInNamespaceSql() { return "SELECT table_name FROM information_schema.tables WHERE table_schema = ?"; } + + @Override + public int getMinimumIsolationLevelForConsistencyRead() { + // In PostgreSQL, REPEATABLE READ and SERIALIZABLE isolation levels guarantee consistent reads + return Connection.TRANSACTION_REPEATABLE_READ; + } } diff --git a/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineSqlServer.java b/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineSqlServer.java index 4a38abeca1..43daf11c1c 100644 --- a/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineSqlServer.java +++ b/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineSqlServer.java @@ -10,6 +10,7 @@ import com.scalar.db.storage.jdbc.query.SelectQuery; import com.scalar.db.storage.jdbc.query.SelectWithTop; import com.scalar.db.storage.jdbc.query.UpsertQuery; +import java.sql.Connection; import java.sql.Driver; import java.sql.JDBCType; import java.sql.SQLException; @@ -436,4 +437,10 @@ public Map getConnectionProperties(JdbcConfig config) { public String getTableNamesInNamespaceSql() { return "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = ?"; } + + @Override + public int getMinimumIsolationLevelForConsistencyRead() { + // In SQL Server, REPEATABLE READ or higher isolation level guarantees consistent reads + return Connection.TRANSACTION_REPEATABLE_READ; + } } diff --git a/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineSqlite.java b/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineSqlite.java index 8800d88aba..416723667b 100644 --- a/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineSqlite.java +++ b/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineSqlite.java @@ -389,4 +389,10 @@ public String getTableNamesInNamespaceSql() { // Do nothing. Namespace is just a table prefix in the SQLite implementation. return null; } + + @Override + public int getMinimumIsolationLevelForConsistencyRead() { + // In SQLite, READ COMMITTED and higher isolation levels guarantee consistent reads + return Connection.TRANSACTION_READ_COMMITTED; + } } diff --git a/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineStrategy.java b/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineStrategy.java index 8d7992f529..9b7e655599 100644 --- a/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineStrategy.java +++ b/core/src/main/java/com/scalar/db/storage/jdbc/RdbEngineStrategy.java @@ -325,4 +325,6 @@ default void throwIfConjunctionsColumnNotSupported( Set conjunctions, TableMetadata metadata) {} String getTableNamesInNamespaceSql(); + + int getMinimumIsolationLevelForConsistencyRead(); } diff --git a/core/src/main/java/com/scalar/db/storage/multistorage/MultiStorageAdmin.java b/core/src/main/java/com/scalar/db/storage/multistorage/MultiStorageAdmin.java index 0d19989f63..6015c606db 100644 --- a/core/src/main/java/com/scalar/db/storage/multistorage/MultiStorageAdmin.java +++ b/core/src/main/java/com/scalar/db/storage/multistorage/MultiStorageAdmin.java @@ -304,8 +304,9 @@ public StorageInfo getStorageInfo(String namespace) throws ExecutionException { StorageInfo storageInfo = holder.admin.getStorageInfo(namespace); return new StorageInfoImpl( holder.storageName, - storageInfo.getMutationAtomicityUnit(), - storageInfo.getMaxAtomicMutationsCount()); + storageInfo.getAtomicityUnit(), + storageInfo.getMaxAtomicMutationsCount(), + storageInfo.isConsistentReadGuaranteed()); } catch (RuntimeException e) { if (e.getCause() instanceof ExecutionException) { throw (ExecutionException) e.getCause(); diff --git a/core/src/main/java/com/scalar/db/storage/objectstorage/ObjectStorageAdmin.java b/core/src/main/java/com/scalar/db/storage/objectstorage/ObjectStorageAdmin.java index 681e6fcf2a..99834a56cc 100644 --- a/core/src/main/java/com/scalar/db/storage/objectstorage/ObjectStorageAdmin.java +++ b/core/src/main/java/com/scalar/db/storage/objectstorage/ObjectStorageAdmin.java @@ -35,9 +35,10 @@ public class ObjectStorageAdmin implements DistributedStorageAdmin { private static final StorageInfo STORAGE_INFO = new StorageInfoImpl( "object_storage", - StorageInfo.MutationAtomicityUnit.PARTITION, + StorageInfo.AtomicityUnit.PARTITION, // No limit on the number of mutations - Integer.MAX_VALUE); + Integer.MAX_VALUE, + true); private final ObjectStorageWrapper wrapper; private final String metadataNamespace; diff --git a/core/src/main/java/com/scalar/db/storage/objectstorage/ObjectStorageWrapper.java b/core/src/main/java/com/scalar/db/storage/objectstorage/ObjectStorageWrapper.java index 96e4117c41..8a5c2803d1 100644 --- a/core/src/main/java/com/scalar/db/storage/objectstorage/ObjectStorageWrapper.java +++ b/core/src/main/java/com/scalar/db/storage/objectstorage/ObjectStorageWrapper.java @@ -76,6 +76,10 @@ public interface ObjectStorageWrapper { */ void deleteByPrefix(String prefix) throws ObjectStorageWrapperException; - /** Close the storage wrapper. */ + /** + * Close the storage wrapper. + * + * @throws ObjectStorageWrapperException if an error occurs + */ void close() throws ObjectStorageWrapperException; } diff --git a/core/src/main/java/com/scalar/db/transaction/consensuscommit/MutationsGrouper.java b/core/src/main/java/com/scalar/db/transaction/consensuscommit/MutationsGrouper.java index 787650749f..0a826593eb 100644 --- a/core/src/main/java/com/scalar/db/transaction/consensuscommit/MutationsGrouper.java +++ b/core/src/main/java/com/scalar/db/transaction/consensuscommit/MutationsGrouper.java @@ -96,7 +96,7 @@ private static class MutationGroup { private MutationGroup(Mutation mutation, StorageInfo storageInfo) { assert mutation.forNamespace().isPresent() && mutation.forTable().isPresent(); - switch (storageInfo.getMutationAtomicityUnit()) { + switch (storageInfo.getAtomicityUnit()) { case RECORD: this.clusteringKey = mutation.getClusteringKey(); this.partitionKey = mutation.getPartitionKey(); @@ -133,8 +133,7 @@ private MutationGroup(Mutation mutation, StorageInfo storageInfo) { this.storageInfo = storageInfo; break; default: - throw new AssertionError( - "Unknown mutation atomicity unit: " + storageInfo.getMutationAtomicityUnit()); + throw new AssertionError("Unknown atomicity unit: " + storageInfo.getAtomicityUnit()); } } diff --git a/core/src/test/java/com/scalar/db/common/CommonDistributedStorageAdminTest.java b/core/src/test/java/com/scalar/db/common/CommonDistributedStorageAdminTest.java index 222cde8a5a..ba4cad90b3 100644 --- a/core/src/test/java/com/scalar/db/common/CommonDistributedStorageAdminTest.java +++ b/core/src/test/java/com/scalar/db/common/CommonDistributedStorageAdminTest.java @@ -181,8 +181,7 @@ public void createVirtualTable_ProperArgumentsGiven_ShouldCallAdminProperly() StorageInfo storageInfo = mock(StorageInfo.class); when(storageInfo.getStorageName()).thenReturn("test-storage"); - when(storageInfo.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.NAMESPACE); + when(storageInfo.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.NAMESPACE); when(admin.getStorageInfo(leftSourceNamespace)).thenReturn(storageInfo); when(admin.namespaceExists(namespace)).thenReturn(true); @@ -258,8 +257,7 @@ public void createVirtualTable_ProperArgumentsGiven_ShouldCallAdminProperly() Map options = Collections.emptyMap(); StorageInfo storageInfo = mock(StorageInfo.class); - when(storageInfo.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.NAMESPACE); + when(storageInfo.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.NAMESPACE); when(admin.getStorageInfo(leftSourceNamespace)).thenReturn(storageInfo); when(admin.namespaceExists(namespace)).thenReturn(true); when(admin.tableExists(namespace, table)).thenReturn(false); @@ -313,8 +311,7 @@ public void createVirtualTable_ProperArgumentsGiven_ShouldCallAdminProperly() Map options = Collections.emptyMap(); StorageInfo storageInfo = mock(StorageInfo.class); - when(storageInfo.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.NAMESPACE); + when(storageInfo.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.NAMESPACE); when(admin.getStorageInfo(leftSourceNamespace)).thenReturn(storageInfo); when(admin.namespaceExists(namespace)).thenReturn(true); when(admin.tableExists(namespace, table)).thenReturn(false); @@ -368,8 +365,7 @@ public void createVirtualTable_ProperArgumentsGiven_ShouldCallAdminProperly() Map options = Collections.emptyMap(); StorageInfo storageInfo = mock(StorageInfo.class); - when(storageInfo.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.NAMESPACE); + when(storageInfo.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.NAMESPACE); when(admin.getStorageInfo(leftSourceNamespace)).thenReturn(storageInfo); when(admin.namespaceExists(namespace)).thenReturn(true); @@ -426,8 +422,7 @@ public void createVirtualTable_VirtualTableUsedAsSource_ShouldThrowIllegalArgume Map options = Collections.emptyMap(); StorageInfo storageInfo = mock(StorageInfo.class); - when(storageInfo.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.NAMESPACE); + when(storageInfo.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.NAMESPACE); when(admin.getStorageInfo(leftSourceNamespace)).thenReturn(storageInfo); when(admin.namespaceExists(namespace)).thenReturn(true); diff --git a/core/src/test/java/com/scalar/db/common/checker/OperationCheckerTest.java b/core/src/test/java/com/scalar/db/common/checker/OperationCheckerTest.java index 9e6fd87310..3a527e4725 100644 --- a/core/src/test/java/com/scalar/db/common/checker/OperationCheckerTest.java +++ b/core/src/test/java/com/scalar/db/common/checker/OperationCheckerTest.java @@ -53,7 +53,7 @@ public class OperationCheckerTest { private static final String COL3 = "v3"; private static final StorageInfo STORAGE_INFO = new StorageInfoImpl( - "cassandra", StorageInfo.MutationAtomicityUnit.PARTITION, Integer.MAX_VALUE); + "cassandra", StorageInfo.AtomicityUnit.PARTITION, Integer.MAX_VALUE, true); @Mock private DatabaseConfig databaseConfig; @Mock private TableMetadataManager metadataManager; @@ -2045,9 +2045,9 @@ public void whenCheckingScanAllOperationWithAllValidArguments_shouldNotThrowAnyE } @ParameterizedTest - @EnumSource(StorageInfo.MutationAtomicityUnit.class) + @EnumSource(StorageInfo.AtomicityUnit.class) public void check_MutationsGiven_ForAtomicityUnit_ShouldBehaveCorrectly( - StorageInfo.MutationAtomicityUnit mutationAtomicityUnit) throws ExecutionException { + StorageInfo.AtomicityUnit atomicityUnit) throws ExecutionException { // Arrange when(metadataManager.getTableMetadata(any())) .thenReturn( @@ -2059,9 +2059,9 @@ public void check_MutationsGiven_ForAtomicityUnit_ShouldBehaveCorrectly( .addClusteringKey(CKEY1) .build()); - StorageInfo storageInfo1 = new StorageInfoImpl("s1", mutationAtomicityUnit, Integer.MAX_VALUE); + StorageInfo storageInfo1 = new StorageInfoImpl("s1", atomicityUnit, Integer.MAX_VALUE, true); StorageInfo storageInfo2 = - new StorageInfoImpl("s2", StorageInfo.MutationAtomicityUnit.STORAGE, Integer.MAX_VALUE); + new StorageInfoImpl("s2", StorageInfo.AtomicityUnit.STORAGE, Integer.MAX_VALUE, true); when(storageInfoProvider.getStorageInfo("ns")).thenReturn(storageInfo1); when(storageInfoProvider.getStorageInfo("ns2")).thenReturn(storageInfo1); when(storageInfoProvider.getStorageInfo("other_ns")).thenReturn(storageInfo2); @@ -2172,7 +2172,7 @@ public void check_MutationsGiven_ForAtomicityUnit_ShouldBehaveCorrectly( catchException(() -> operationChecker.check(mutationsAcrossStorages)); // Assert - switch (mutationAtomicityUnit) { + switch (atomicityUnit) { case RECORD: assertThat(exceptionForMutationsWithinRecord).doesNotThrowAnyException(); assertThat(exceptionForMutationsWithinPartition) diff --git a/core/src/test/java/com/scalar/db/storage/cosmos/CosmosOperationCheckerTest.java b/core/src/test/java/com/scalar/db/storage/cosmos/CosmosOperationCheckerTest.java index b11dcfb782..af9442158d 100644 --- a/core/src/test/java/com/scalar/db/storage/cosmos/CosmosOperationCheckerTest.java +++ b/core/src/test/java/com/scalar/db/storage/cosmos/CosmosOperationCheckerTest.java @@ -41,7 +41,7 @@ public class CosmosOperationCheckerTest { private static final String COL1 = "v1"; private static final String COL2 = "v2"; private static final StorageInfo STORAGE_INFO = - new StorageInfoImpl("cosmos", StorageInfo.MutationAtomicityUnit.PARTITION, Integer.MAX_VALUE); + new StorageInfoImpl("cosmos", StorageInfo.AtomicityUnit.PARTITION, Integer.MAX_VALUE, true); private static final TableMetadata TABLE_METADATA1 = TableMetadata.newBuilder() diff --git a/core/src/test/java/com/scalar/db/storage/dynamo/DynamoOperationCheckerTest.java b/core/src/test/java/com/scalar/db/storage/dynamo/DynamoOperationCheckerTest.java index 59e2fbad47..a51c448797 100644 --- a/core/src/test/java/com/scalar/db/storage/dynamo/DynamoOperationCheckerTest.java +++ b/core/src/test/java/com/scalar/db/storage/dynamo/DynamoOperationCheckerTest.java @@ -39,7 +39,7 @@ public class DynamoOperationCheckerTest { private static final String COL3 = "v3"; private static final String COL4 = "v4"; private static final StorageInfo STORAGE_INFO = - new StorageInfoImpl("dynamo", StorageInfo.MutationAtomicityUnit.STORAGE, 100); + new StorageInfoImpl("dynamo", StorageInfo.AtomicityUnit.STORAGE, 100, true); @Mock private DatabaseConfig databaseConfig; @Mock private TableMetadataManager metadataManager; diff --git a/core/src/test/java/com/scalar/db/storage/jdbc/JdbcAdminTest.java b/core/src/test/java/com/scalar/db/storage/jdbc/JdbcAdminTest.java index db08667898..2590e5632f 100644 --- a/core/src/test/java/com/scalar/db/storage/jdbc/JdbcAdminTest.java +++ b/core/src/test/java/com/scalar/db/storage/jdbc/JdbcAdminTest.java @@ -35,6 +35,7 @@ import com.google.common.collect.ImmutableSet; import com.mysql.cj.jdbc.exceptions.CommunicationsException; import com.scalar.db.api.Scan.Ordering.Order; +import com.scalar.db.api.StorageInfo; import com.scalar.db.api.TableMetadata; import com.scalar.db.api.VirtualTableInfo; import com.scalar.db.api.VirtualTableJoinType; @@ -6199,6 +6200,97 @@ public void getVirtualTableInfo_SQLExceptionThrown_ShouldThrowExecutionException .hasCause(sqlException); } + @ParameterizedTest + @EnumSource(RdbEngine.class) + void getStorageInfo_WithRepeatableReadIsolationLevel_ShouldReturnCorrectInfo(RdbEngine rdbEngine) + throws Exception { + // Arrange + int isolationLevel = Connection.TRANSACTION_REPEATABLE_READ; + JdbcAdmin admin = createJdbcAdminFor(rdbEngine); + when(dataSource.getConnection()).thenReturn(connection); + when(connection.getTransactionIsolation()).thenReturn(isolationLevel); + + // Act + StorageInfo storageInfo = admin.getStorageInfo("namespace"); + + // Assert + assertThat(storageInfo.getStorageName()).isEqualTo("jdbc"); + assertThat(storageInfo.getAtomicityUnit()).isEqualTo(StorageInfo.AtomicityUnit.STORAGE); + assertThat(storageInfo.getMaxAtomicMutationsCount()).isEqualTo(Integer.MAX_VALUE); + + // Check consistent read guarantee based on RDB engine + RdbEngineStrategy strategy = getRdbEngineStrategy(rdbEngine); + boolean expectedConsistentRead = + isolationLevel >= strategy.getMinimumIsolationLevelForConsistencyRead(); + assertThat(storageInfo.isConsistentReadGuaranteed()).isEqualTo(expectedConsistentRead); + } + + @ParameterizedTest + @EnumSource(RdbEngine.class) + void getStorageInfo_WithReadCommittedIsolationLevel_ShouldReturnCorrectInfo(RdbEngine rdbEngine) + throws Exception { + // Arrange + int isolationLevel = Connection.TRANSACTION_READ_COMMITTED; + JdbcAdmin admin = createJdbcAdminFor(rdbEngine); + when(dataSource.getConnection()).thenReturn(connection); + when(connection.getTransactionIsolation()).thenReturn(isolationLevel); + + // Act + StorageInfo storageInfo = admin.getStorageInfo("namespace"); + + // Assert + assertThat(storageInfo.getStorageName()).isEqualTo("jdbc"); + assertThat(storageInfo.getAtomicityUnit()).isEqualTo(StorageInfo.AtomicityUnit.STORAGE); + assertThat(storageInfo.getMaxAtomicMutationsCount()).isEqualTo(Integer.MAX_VALUE); + + // Check consistent read guarantee based on RDB engine + RdbEngineStrategy strategy = getRdbEngineStrategy(rdbEngine); + boolean expectedConsistentRead = + isolationLevel >= strategy.getMinimumIsolationLevelForConsistencyRead(); + assertThat(storageInfo.isConsistentReadGuaranteed()).isEqualTo(expectedConsistentRead); + } + + @ParameterizedTest + @EnumSource(RdbEngine.class) + void getStorageInfo_WithSerializableIsolationLevel_ShouldReturnCorrectInfo(RdbEngine rdbEngine) + throws Exception { + // Arrange + int isolationLevel = Connection.TRANSACTION_SERIALIZABLE; + JdbcAdmin admin = createJdbcAdminFor(rdbEngine); + when(dataSource.getConnection()).thenReturn(connection); + when(connection.getTransactionIsolation()).thenReturn(isolationLevel); + + // Act + StorageInfo storageInfo = admin.getStorageInfo("namespace"); + + // Assert + assertThat(storageInfo.getStorageName()).isEqualTo("jdbc"); + assertThat(storageInfo.getAtomicityUnit()).isEqualTo(StorageInfo.AtomicityUnit.STORAGE); + assertThat(storageInfo.getMaxAtomicMutationsCount()).isEqualTo(Integer.MAX_VALUE); + + // Check consistent read guarantee based on RDB engine + RdbEngineStrategy strategy = getRdbEngineStrategy(rdbEngine); + boolean expectedConsistentRead = + isolationLevel >= strategy.getMinimumIsolationLevelForConsistencyRead(); + assertThat(storageInfo.isConsistentReadGuaranteed()).isEqualTo(expectedConsistentRead); + } + + @ParameterizedTest + @EnumSource(RdbEngine.class) + void getStorageInfo_SQLExceptionThrown_ShouldThrowExecutionException(RdbEngine rdbEngine) + throws Exception { + // Arrange + JdbcAdmin admin = createJdbcAdminFor(rdbEngine); + when(dataSource.getConnection()).thenReturn(connection); + when(connection.getTransactionIsolation()).thenThrow(new SQLException("Connection error")); + + // Act Assert + assertThatThrownBy(() -> admin.getStorageInfo("namespace")) + .isInstanceOf(ExecutionException.class) + .hasMessageContaining("Getting the transaction isolation level failed") + .hasCauseInstanceOf(SQLException.class); + } + // Utility class used to mock ResultSet for a "select * from" query on the metadata table static class SelectAllFromMetadataTableResultSetMocker implements org.mockito.stubbing.Answer { diff --git a/core/src/test/java/com/scalar/db/storage/multistorage/MultiStorageAdminTest.java b/core/src/test/java/com/scalar/db/storage/multistorage/MultiStorageAdminTest.java index 1e5f5733d2..088b03377d 100644 --- a/core/src/test/java/com/scalar/db/storage/multistorage/MultiStorageAdminTest.java +++ b/core/src/test/java/com/scalar/db/storage/multistorage/MultiStorageAdminTest.java @@ -915,25 +915,24 @@ public void getStorageInfo_ShouldReturnProperStorageInfo() throws ExecutionExcep when(admin1.getStorageInfo(anyString())) .thenReturn( new StorageInfoImpl( - "cassandra", StorageInfo.MutationAtomicityUnit.PARTITION, Integer.MAX_VALUE)); + "cassandra", StorageInfo.AtomicityUnit.PARTITION, Integer.MAX_VALUE, true)); when(admin2.getStorageInfo(anyString())) - .thenReturn(new StorageInfoImpl("dynamo", StorageInfo.MutationAtomicityUnit.STORAGE, 100)); + .thenReturn(new StorageInfoImpl("dynamo", StorageInfo.AtomicityUnit.STORAGE, 100, true)); when(admin3.getStorageInfo(anyString())) .thenReturn( new StorageInfoImpl( - "jdbc", StorageInfo.MutationAtomicityUnit.STORAGE, Integer.MAX_VALUE)); + "jdbc", StorageInfo.AtomicityUnit.STORAGE, Integer.MAX_VALUE, true)); // Act Assert assertThat(multiStorageAdmin.getStorageInfo("ns1")) .isEqualTo( new StorageInfoImpl( - "s1", StorageInfo.MutationAtomicityUnit.PARTITION, Integer.MAX_VALUE)); + "s1", StorageInfo.AtomicityUnit.PARTITION, Integer.MAX_VALUE, true)); assertThat(multiStorageAdmin.getStorageInfo("ns2")) - .isEqualTo(new StorageInfoImpl("s2", StorageInfo.MutationAtomicityUnit.STORAGE, 100)); + .isEqualTo(new StorageInfoImpl("s2", StorageInfo.AtomicityUnit.STORAGE, 100, true)); assertThat(multiStorageAdmin.getStorageInfo("ns3")) .isEqualTo( - new StorageInfoImpl( - "s3", StorageInfo.MutationAtomicityUnit.STORAGE, Integer.MAX_VALUE)); + new StorageInfoImpl("s3", StorageInfo.AtomicityUnit.STORAGE, Integer.MAX_VALUE, true)); verify(admin1).getStorageInfo("ns1"); verify(admin2).getStorageInfo("ns2"); @@ -955,7 +954,7 @@ public void createVirtualTable_ProperArgumentsGiven_ShouldCallAdminProperly() // Mock getStorageInfo to return the same storage for all namespaces StorageInfo storageInfo = - new StorageInfoImpl("s2", StorageInfo.MutationAtomicityUnit.NAMESPACE, Integer.MAX_VALUE); + new StorageInfoImpl("s2", StorageInfo.AtomicityUnit.NAMESPACE, Integer.MAX_VALUE, true); when(admin2.getStorageInfo(namespace)).thenReturn(storageInfo); when(admin2.getStorageInfo(leftSourceNamespace)).thenReturn(storageInfo); when(admin2.getStorageInfo(rightSourceNamespace)).thenReturn(storageInfo); @@ -1000,9 +999,9 @@ public void createVirtualTable_ProperArgumentsGiven_ShouldCallAdminProperly() // Mock getStorageInfo - virtual table in s3, both sources in s2 StorageInfo storageInfoForNamespace = - new StorageInfoImpl("s3", StorageInfo.MutationAtomicityUnit.NAMESPACE, Integer.MAX_VALUE); + new StorageInfoImpl("s3", StorageInfo.AtomicityUnit.NAMESPACE, Integer.MAX_VALUE, true); StorageInfo storageInfoForSources = - new StorageInfoImpl("s2", StorageInfo.MutationAtomicityUnit.NAMESPACE, Integer.MAX_VALUE); + new StorageInfoImpl("s2", StorageInfo.AtomicityUnit.NAMESPACE, Integer.MAX_VALUE, true); when(admin3.getStorageInfo(namespace)).thenReturn(storageInfoForNamespace); when(admin2.getStorageInfo(leftSourceNamespace)).thenReturn(storageInfoForSources); when(admin2.getStorageInfo(rightSourceNamespace)).thenReturn(storageInfoForSources); @@ -1039,9 +1038,9 @@ public void createVirtualTable_ProperArgumentsGiven_ShouldCallAdminProperly() // Mock getStorageInfo to return different storages for left and right sources StorageInfo storageInfo1 = - new StorageInfoImpl("s2", StorageInfo.MutationAtomicityUnit.NAMESPACE, Integer.MAX_VALUE); + new StorageInfoImpl("s2", StorageInfo.AtomicityUnit.NAMESPACE, Integer.MAX_VALUE, true); StorageInfo storageInfo2 = - new StorageInfoImpl("s3", StorageInfo.MutationAtomicityUnit.NAMESPACE, Integer.MAX_VALUE); + new StorageInfoImpl("s3", StorageInfo.AtomicityUnit.NAMESPACE, Integer.MAX_VALUE, true); when(admin2.getStorageInfo(namespace)).thenReturn(storageInfo1); when(admin2.getStorageInfo(leftSourceNamespace)).thenReturn(storageInfo1); when(admin3.getStorageInfo(rightSourceNamespace)).thenReturn(storageInfo2); diff --git a/core/src/test/java/com/scalar/db/storage/objectstorage/ObjectStorageOperationCheckerTest.java b/core/src/test/java/com/scalar/db/storage/objectstorage/ObjectStorageOperationCheckerTest.java index b68f4c56be..a7b3885927 100644 --- a/core/src/test/java/com/scalar/db/storage/objectstorage/ObjectStorageOperationCheckerTest.java +++ b/core/src/test/java/com/scalar/db/storage/objectstorage/ObjectStorageOperationCheckerTest.java @@ -41,7 +41,7 @@ public class ObjectStorageOperationCheckerTest { private static final String COL3 = "v3"; private static final String COL4 = "v4"; private static final StorageInfo STORAGE_INFO = - new StorageInfoImpl("ObjectStorage", StorageInfo.MutationAtomicityUnit.STORAGE, 100); + new StorageInfoImpl("ObjectStorage", StorageInfo.AtomicityUnit.STORAGE, 100, true); private static final TableMetadata TABLE_METADATA1 = TableMetadata.newBuilder() diff --git a/core/src/test/java/com/scalar/db/transaction/consensuscommit/CommitHandlerTest.java b/core/src/test/java/com/scalar/db/transaction/consensuscommit/CommitHandlerTest.java index 0591d65e49..8e340fec30 100644 --- a/core/src/test/java/com/scalar/db/transaction/consensuscommit/CommitHandlerTest.java +++ b/core/src/test/java/com/scalar/db/transaction/consensuscommit/CommitHandlerTest.java @@ -108,7 +108,7 @@ void setUp() throws Exception { when(storageInfoProvider.getStorageInfo(ANY_NAMESPACE_NAME)) .thenReturn( new StorageInfoImpl( - "storage1", StorageInfo.MutationAtomicityUnit.PARTITION, Integer.MAX_VALUE)); + "storage1", StorageInfo.AtomicityUnit.PARTITION, Integer.MAX_VALUE, true)); } @AfterEach diff --git a/core/src/test/java/com/scalar/db/transaction/consensuscommit/MutationsGrouperTest.java b/core/src/test/java/com/scalar/db/transaction/consensuscommit/MutationsGrouperTest.java index 1ca89b2f05..e501d6cdf1 100644 --- a/core/src/test/java/com/scalar/db/transaction/consensuscommit/MutationsGrouperTest.java +++ b/core/src/test/java/com/scalar/db/transaction/consensuscommit/MutationsGrouperTest.java @@ -48,8 +48,7 @@ public void groupMutations_WithRecordAtomicity_ShouldGroupCorrectly() throws Exe String namespace = "ns"; String table = "table"; StorageInfo storageInfo = mock(StorageInfo.class); - when(storageInfo.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.RECORD); + when(storageInfo.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.RECORD); when(storageInfo.getMaxAtomicMutationsCount()).thenReturn(100); when(storageInfo.getStorageName()).thenReturn("storage1"); when(storageInfoProvider.getStorageInfo(namespace)).thenReturn(storageInfo); @@ -94,8 +93,7 @@ public void groupMutations_WithPartitionAtomicity_ShouldGroupCorrectly() String namespace = "ns"; String table = "table"; StorageInfo storageInfo = mock(StorageInfo.class); - when(storageInfo.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.PARTITION); + when(storageInfo.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.PARTITION); when(storageInfo.getMaxAtomicMutationsCount()).thenReturn(100); when(storageInfo.getStorageName()).thenReturn("storage1"); when(storageInfoProvider.getStorageInfo(namespace)).thenReturn(storageInfo); @@ -133,8 +131,7 @@ public void groupMutations_WithTableAtomicity_ShouldGroupCorrectly() throws Exec String table1 = "table1"; String table2 = "table2"; StorageInfo storageInfo = mock(StorageInfo.class); - when(storageInfo.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.TABLE); + when(storageInfo.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.TABLE); when(storageInfo.getMaxAtomicMutationsCount()).thenReturn(100); when(storageInfo.getStorageName()).thenReturn("storage1"); when(storageInfoProvider.getStorageInfo(namespace1)).thenReturn(storageInfo); @@ -170,8 +167,7 @@ public void groupMutations_WithBatchSizeLimit_ShouldCreateMultipleBatches() String namespace = "ns"; String table = "table"; StorageInfo storageInfo = mock(StorageInfo.class); - when(storageInfo.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.TABLE); + when(storageInfo.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.TABLE); when(storageInfo.getMaxAtomicMutationsCount()).thenReturn(2); // Max 2 mutations per batch when(storageInfo.getStorageName()).thenReturn("storage1"); when(storageInfoProvider.getStorageInfo(namespace)).thenReturn(storageInfo); @@ -203,8 +199,7 @@ public void groupMutations_WithNamespaceAtomicity_ShouldGroupCorrectly() String table2 = "table2"; StorageInfo storageInfo = mock(StorageInfo.class); - when(storageInfo.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.NAMESPACE); + when(storageInfo.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.NAMESPACE); when(storageInfo.getMaxAtomicMutationsCount()).thenReturn(100); when(storageInfo.getStorageName()).thenReturn("storage1"); when(storageInfoProvider.getStorageInfo(namespace1)).thenReturn(storageInfo); @@ -241,14 +236,12 @@ public void groupMutations_WithStorageAtomicity_ShouldGroupCorrectly() throws Ex String table2 = "table2"; StorageInfo storageInfo1 = mock(StorageInfo.class); - when(storageInfo1.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.STORAGE); + when(storageInfo1.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.STORAGE); when(storageInfo1.getMaxAtomicMutationsCount()).thenReturn(100); when(storageInfo1.getStorageName()).thenReturn("storage1"); StorageInfo storageInfo2 = mock(StorageInfo.class); - when(storageInfo2.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.STORAGE); + when(storageInfo2.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.STORAGE); when(storageInfo2.getMaxAtomicMutationsCount()).thenReturn(100); when(storageInfo2.getStorageName()).thenReturn("storage2"); @@ -294,14 +287,12 @@ public void groupMutations_WithStorageAtomicityAndBatchSizeLimit_ShouldGroupCorr String table2 = "table2"; StorageInfo storageInfo1 = mock(StorageInfo.class); - when(storageInfo1.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.STORAGE); + when(storageInfo1.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.STORAGE); when(storageInfo1.getMaxAtomicMutationsCount()).thenReturn(2); // Max 2 mutations per batch when(storageInfo1.getStorageName()).thenReturn("storage1"); StorageInfo storageInfo2 = mock(StorageInfo.class); - when(storageInfo2.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.STORAGE); + when(storageInfo2.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.STORAGE); when(storageInfo2.getMaxAtomicMutationsCount()).thenReturn(100); when(storageInfo2.getStorageName()).thenReturn("storage2"); @@ -354,8 +345,7 @@ public void canBeGroupedAltogether_WithEmptyCollection_ShouldReturnTrue() String namespace = "ns"; String table = "table"; StorageInfo storageInfo = mock(StorageInfo.class); - when(storageInfo.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.RECORD); + when(storageInfo.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.RECORD); when(storageInfo.getMaxAtomicMutationsCount()).thenReturn(100); when(storageInfo.getStorageName()).thenReturn("storage1"); when(storageInfoProvider.getStorageInfo(namespace)).thenReturn(storageInfo); @@ -383,8 +373,7 @@ public void canBeGroupedAltogether_WithEmptyCollection_ShouldReturnTrue() String namespace = "ns"; String table = "table"; StorageInfo storageInfo = mock(StorageInfo.class); - when(storageInfo.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.PARTITION); + when(storageInfo.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.PARTITION); when(storageInfo.getMaxAtomicMutationsCount()).thenReturn(100); when(storageInfo.getStorageName()).thenReturn("storage1"); when(storageInfoProvider.getStorageInfo(namespace)).thenReturn(storageInfo); @@ -412,8 +401,7 @@ public void canBeGroupedAltogether_WithAllMutationsInSameGroupForTableAtomicity_ String namespace = "ns"; String table = "table"; StorageInfo storageInfo = mock(StorageInfo.class); - when(storageInfo.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.TABLE); + when(storageInfo.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.TABLE); when(storageInfo.getMaxAtomicMutationsCount()).thenReturn(100); when(storageInfo.getStorageName()).thenReturn("storage1"); when(storageInfoProvider.getStorageInfo(namespace)).thenReturn(storageInfo); @@ -440,8 +428,7 @@ public void canBeGroupedAltogether_WithAllMutationsInSameGroupForTableAtomicity_ String table1 = "table1"; String table2 = "table2"; StorageInfo storageInfo = mock(StorageInfo.class); - when(storageInfo.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.NAMESPACE); + when(storageInfo.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.NAMESPACE); when(storageInfo.getMaxAtomicMutationsCount()).thenReturn(100); when(storageInfo.getStorageName()).thenReturn("storage1"); when(storageInfoProvider.getStorageInfo(namespace)).thenReturn(storageInfo); @@ -470,8 +457,7 @@ public void canBeGroupedAltogether_WithAllMutationsInSameGroupForTableAtomicity_ String table2 = "table2"; StorageInfo storageInfo = mock(StorageInfo.class); - when(storageInfo.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.STORAGE); + when(storageInfo.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.STORAGE); when(storageInfo.getMaxAtomicMutationsCount()).thenReturn(100); when(storageInfo.getStorageName()).thenReturn("storage1"); when(storageInfoProvider.getStorageInfo(namespace1)).thenReturn(storageInfo); @@ -500,15 +486,13 @@ public void canBeGroupedAltogether_WithMutationsInDifferentGroups_ShouldReturnFa String table2 = "table2"; StorageInfo storageInfo1 = mock(StorageInfo.class); - when(storageInfo1.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.TABLE); + when(storageInfo1.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.TABLE); when(storageInfo1.getMaxAtomicMutationsCount()).thenReturn(100); when(storageInfo1.getStorageName()).thenReturn("storage1"); when(storageInfoProvider.getStorageInfo(namespace1)).thenReturn(storageInfo1); StorageInfo storageInfo2 = mock(StorageInfo.class); - when(storageInfo2.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.TABLE); + when(storageInfo2.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.TABLE); when(storageInfo2.getMaxAtomicMutationsCount()).thenReturn(100); when(storageInfo2.getStorageName()).thenReturn("storage2"); when(storageInfoProvider.getStorageInfo(namespace2)).thenReturn(storageInfo2); @@ -536,8 +520,7 @@ public void canBeGroupedAltogether_WithMutationsInDifferentGroups_ShouldReturnFa String table2 = "table2"; StorageInfo storageInfo = mock(StorageInfo.class); - when(storageInfo.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.TABLE); + when(storageInfo.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.TABLE); when(storageInfo.getMaxAtomicMutationsCount()).thenReturn(100); when(storageInfo.getStorageName()).thenReturn("storage1"); when(storageInfoProvider.getStorageInfo(namespace)).thenReturn(storageInfo); @@ -564,8 +547,7 @@ public void canBeGroupedAltogether_WithMutationsInDifferentGroups_ShouldReturnFa String table = "table"; StorageInfo storageInfo = mock(StorageInfo.class); - when(storageInfo.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.PARTITION); + when(storageInfo.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.PARTITION); when(storageInfo.getMaxAtomicMutationsCount()).thenReturn(100); when(storageInfo.getStorageName()).thenReturn("storage1"); when(storageInfoProvider.getStorageInfo(namespace)).thenReturn(storageInfo); @@ -590,8 +572,7 @@ public void canBeGroupedAltogether_WithOverMaxCount_ShouldReturnFalse() String namespace = "ns"; String table = "table"; StorageInfo storageInfo = mock(StorageInfo.class); - when(storageInfo.getMutationAtomicityUnit()) - .thenReturn(StorageInfo.MutationAtomicityUnit.TABLE); + when(storageInfo.getAtomicityUnit()).thenReturn(StorageInfo.AtomicityUnit.TABLE); when(storageInfo.getMaxAtomicMutationsCount()).thenReturn(3); // Max 3 mutations allowed when(storageInfo.getStorageName()).thenReturn("storage1"); when(storageInfoProvider.getStorageInfo(namespace)).thenReturn(storageInfo); diff --git a/integration-test/src/main/java/com/scalar/db/api/DistributedStorageMutationAtomicityUnitIntegrationTestBase.java b/integration-test/src/main/java/com/scalar/db/api/DistributedStorageAtomicityUnitIntegrationTestBase.java similarity index 95% rename from integration-test/src/main/java/com/scalar/db/api/DistributedStorageMutationAtomicityUnitIntegrationTestBase.java rename to integration-test/src/main/java/com/scalar/db/api/DistributedStorageAtomicityUnitIntegrationTestBase.java index 9b17902e7d..1c61ef38be 100644 --- a/integration-test/src/main/java/com/scalar/db/api/DistributedStorageMutationAtomicityUnitIntegrationTestBase.java +++ b/integration-test/src/main/java/com/scalar/db/api/DistributedStorageAtomicityUnitIntegrationTestBase.java @@ -21,9 +21,9 @@ import org.slf4j.LoggerFactory; @TestInstance(TestInstance.Lifecycle.PER_CLASS) -public abstract class DistributedStorageMutationAtomicityUnitIntegrationTestBase { +public abstract class DistributedStorageAtomicityUnitIntegrationTestBase { protected static final Logger logger = - LoggerFactory.getLogger(DistributedStorageMutationAtomicityUnitIntegrationTestBase.class); + LoggerFactory.getLogger(DistributedStorageAtomicityUnitIntegrationTestBase.class); protected static final String TEST_NAME = "storage_mau"; protected static final String NAMESPACE1 = "int_test_" + TEST_NAME + "1"; @@ -142,7 +142,7 @@ protected void dropTable() throws ExecutionException { } @Test - public void mutate_MutationsWithinRecordGiven_ShouldBehaveCorrectlyBaseOnMutationAtomicityUnit() + public void mutate_MutationsWithinRecordGiven_ShouldBehaveCorrectlyBaseOnAtomicityUnit() throws ExecutionException { // Arrange Put put1 = @@ -185,9 +185,8 @@ public void mutate_MutationsWithinRecordGiven_ShouldBehaveCorrectlyBaseOnMutatio } @Test - public void - mutate_MutationsWithinPartitionGiven_ShouldBehaveCorrectlyBaseOnMutationAtomicityUnit() - throws ExecutionException { + public void mutate_MutationsWithinPartitionGiven_ShouldBehaveCorrectlyBaseOnAtomicityUnit() + throws ExecutionException { // Arrange storage.put( Put.newBuilder() @@ -228,7 +227,7 @@ public void mutate_MutationsWithinRecordGiven_ShouldBehaveCorrectlyBaseOnMutatio // Assert StorageInfo storageInfo = admin.getStorageInfo(namespace1); - switch (storageInfo.getMutationAtomicityUnit()) { + switch (storageInfo.getAtomicityUnit()) { case RECORD: assertThat(exception).isInstanceOf(IllegalArgumentException.class); break; @@ -280,7 +279,7 @@ public void mutate_MutationsWithinRecordGiven_ShouldBehaveCorrectlyBaseOnMutatio } @Test - public void mutate_MutationsWithinTableGiven_ShouldBehaveCorrectlyBaseOnMutationAtomicityUnit() + public void mutate_MutationsWithinTableGiven_ShouldBehaveCorrectlyBaseOnAtomicityUnit() throws ExecutionException { // Arrange storage.put( @@ -322,7 +321,7 @@ public void mutate_MutationsWithinTableGiven_ShouldBehaveCorrectlyBaseOnMutation // Assert StorageInfo storageInfo = admin.getStorageInfo(namespace1); - switch (storageInfo.getMutationAtomicityUnit()) { + switch (storageInfo.getAtomicityUnit()) { case RECORD: case PARTITION: assertThat(exception).isInstanceOf(IllegalArgumentException.class); @@ -374,9 +373,8 @@ public void mutate_MutationsWithinTableGiven_ShouldBehaveCorrectlyBaseOnMutation } @Test - public void - mutate_MutationsWithinNamespaceGiven_ShouldBehaveCorrectlyBaseOnMutationAtomicityUnit() - throws ExecutionException { + public void mutate_MutationsWithinNamespaceGiven_ShouldBehaveCorrectlyBaseOnAtomicityUnit() + throws ExecutionException { // Arrange storage.put( Put.newBuilder() @@ -417,7 +415,7 @@ public void mutate_MutationsWithinTableGiven_ShouldBehaveCorrectlyBaseOnMutation // Assert StorageInfo storageInfo = admin.getStorageInfo(namespace1); - switch (storageInfo.getMutationAtomicityUnit()) { + switch (storageInfo.getAtomicityUnit()) { case RECORD: case PARTITION: case TABLE: @@ -469,7 +467,7 @@ public void mutate_MutationsWithinTableGiven_ShouldBehaveCorrectlyBaseOnMutation } @Test - public void mutate_MutationsWithinStorageGiven_ShouldBehaveCorrectlyBaseOnMutationAtomicityUnit() + public void mutate_MutationsWithinStorageGiven_ShouldBehaveCorrectlyBaseOnAtomicityUnit() throws ExecutionException { // Arrange storage.put( @@ -511,7 +509,7 @@ public void mutate_MutationsWithinStorageGiven_ShouldBehaveCorrectlyBaseOnMutati // Assert StorageInfo storageInfo = admin.getStorageInfo(namespace1); - switch (storageInfo.getMutationAtomicityUnit()) { + switch (storageInfo.getAtomicityUnit()) { case RECORD: case PARTITION: case TABLE: diff --git a/integration-test/src/main/java/com/scalar/db/transaction/consensuscommit/ConsensusCommitSpecificIntegrationTestBase.java b/integration-test/src/main/java/com/scalar/db/transaction/consensuscommit/ConsensusCommitSpecificIntegrationTestBase.java index 716533854d..3f85928a39 100644 --- a/integration-test/src/main/java/com/scalar/db/transaction/consensuscommit/ConsensusCommitSpecificIntegrationTestBase.java +++ b/integration-test/src/main/java/com/scalar/db/transaction/consensuscommit/ConsensusCommitSpecificIntegrationTestBase.java @@ -7016,7 +7016,7 @@ void manager_mutate_ShouldMutateRecords(Isolation isolation) throws TransactionE @ParameterizedTest @MethodSource("isolationAndOnePhaseCommitEnabled") public void - insertAndCommit_SinglePartitionMutationsGiven_ShouldBehaveCorrectlyBasedOnStorageMutationAtomicityUnit( + insertAndCommit_SinglePartitionMutationsGiven_ShouldBehaveCorrectlyBasedOnStorageAtomicityUnit( Isolation isolation, boolean onePhaseCommitEnabled) throws TransactionException, ExecutionException, CoordinatorException { if (isGroupCommitEnabled() && onePhaseCommitEnabled) { @@ -7049,7 +7049,7 @@ void manager_mutate_ShouldMutateRecords(Isolation isolation) throws TransactionE // Assert StorageInfo storageInfo = admin.getStorageInfo(namespace1); - switch (storageInfo.getMutationAtomicityUnit()) { + switch (storageInfo.getAtomicityUnit()) { case RECORD: // twice for prepare, twice for commit verify(storage, times(4)).mutate(anyList()); @@ -7121,7 +7121,7 @@ void manager_mutate_ShouldMutateRecords(Isolation isolation) throws TransactionE @ParameterizedTest @MethodSource("isolationAndOnePhaseCommitEnabled") public void - insertAndCommit_TwoPartitionsMutationsGiven_ShouldBehaveCorrectlyBasedOnStorageMutationAtomicityUnit( + insertAndCommit_TwoPartitionsMutationsGiven_ShouldBehaveCorrectlyBasedOnStorageAtomicityUnit( Isolation isolation, boolean onePhaseCommitEnabled) throws TransactionException, ExecutionException, CoordinatorException { if (isGroupCommitEnabled() && onePhaseCommitEnabled) { @@ -7154,7 +7154,7 @@ void manager_mutate_ShouldMutateRecords(Isolation isolation) throws TransactionE // Assert StorageInfo storageInfo = admin.getStorageInfo(namespace1); - switch (storageInfo.getMutationAtomicityUnit()) { + switch (storageInfo.getAtomicityUnit()) { case RECORD: case PARTITION: // twice for prepare, twice for commit @@ -7226,7 +7226,7 @@ void manager_mutate_ShouldMutateRecords(Isolation isolation) throws TransactionE @ParameterizedTest @MethodSource("isolationAndOnePhaseCommitEnabled") public void - insertAndCommit_TwoNamespacesMutationsGiven_ShouldBehaveCorrectlyBasedOnStorageMutationAtomicityUnit( + insertAndCommit_TwoNamespacesMutationsGiven_ShouldBehaveCorrectlyBasedOnStorageAtomicityUnit( Isolation isolation, boolean onePhaseCommitEnabled) throws TransactionException, ExecutionException, CoordinatorException { if (isGroupCommitEnabled() && onePhaseCommitEnabled) { @@ -7275,7 +7275,7 @@ void manager_mutate_ShouldMutateRecords(Isolation isolation) throws TransactionE } } else { // same storage - switch (storageInfo1.getMutationAtomicityUnit()) { + switch (storageInfo1.getAtomicityUnit()) { case RECORD: case PARTITION: case TABLE: