diff --git a/core/src/main/java/com/scalar/db/api/OperationBuilder.java b/core/src/main/java/com/scalar/db/api/OperationBuilder.java index a9fcb7d247..83b9a6bc75 100644 --- a/core/src/main/java/com/scalar/db/api/OperationBuilder.java +++ b/core/src/main/java/com/scalar/db/api/OperationBuilder.java @@ -108,7 +108,7 @@ interface Projection { interface ClearProjections { /** - * Clear the list of projections + * Clears the list of projections. * * @return the operation builder */ @@ -127,7 +127,7 @@ interface Condition { interface ClearCondition { /** - * Remove the condition + * Removes the condition. * * @return the operation builder */ @@ -266,14 +266,14 @@ interface Values { interface ClearValues { /** - * Clear the list of values + * Clears the list of values. * * @return the operation builder */ T clearValues(); /** - * Clear the value for the given column + * Clears the value for the given column. * * @param columnName a column name * @return the operation builder @@ -283,12 +283,19 @@ interface ClearValues { interface ImplicitPreReadEnabled { /** - * Disable implicit pre-read for this put operation. + * Disables implicit pre-read for this put operation. * * @return the operation builder */ T disableImplicitPreRead(); + /** + * Enables implicit pre-read for this put operation. + * + * @return the operation builder + */ + T enableImplicitPreRead(); + /** * Sets whether implicit pre-read is enabled or not for this put operation. * @@ -338,7 +345,7 @@ interface Ordering { interface ClearOrderings { /** - * Clear the list of orderings + * Clears the list of orderings. * * @return the scan operation builder */ @@ -387,14 +394,14 @@ default T end(Key clusteringKey) { interface ClearBoundaries { /** - * Remove the scan starting boundary + * Removes the scan starting boundary. * * @return the scan operation builder */ T clearStart(); /** - * Remove the scan ending boundary + * Removes the scan ending boundary. * * @return the scan operation builder */ @@ -403,7 +410,7 @@ interface ClearBoundaries { interface All { /** - * Specify the Scan operation will retrieve all the entries of the database + * Specifies the Scan operation will retrieve all the entries of the database. * * @return the scan operation builder */ @@ -504,7 +511,7 @@ interface Or { interface ClearConditions { /** - * Clear all conditions + * Clears all conditions. * * @return the scan operation builder */ diff --git a/core/src/main/java/com/scalar/db/api/Put.java b/core/src/main/java/com/scalar/db/api/Put.java index 431a505df0..2dd5e9ad53 100644 --- a/core/src/main/java/com/scalar/db/api/Put.java +++ b/core/src/main/java/com/scalar/db/api/Put.java @@ -39,7 +39,7 @@ public class Put extends Mutation { private final Map> columns; - private boolean implicitPreReadEnabled = true; + private boolean implicitPreReadEnabled; /** * Constructs a {@code Put} with the specified partition {@link Key}. diff --git a/core/src/main/java/com/scalar/db/api/PutBuilder.java b/core/src/main/java/com/scalar/db/api/PutBuilder.java index ee3c2bcfb4..f08df19f93 100644 --- a/core/src/main/java/com/scalar/db/api/PutBuilder.java +++ b/core/src/main/java/com/scalar/db/api/PutBuilder.java @@ -83,7 +83,7 @@ public static class Buildable extends OperationBuilder.Buildable @Nullable Key clusteringKey; @Nullable com.scalar.db.api.Consistency consistency; @Nullable MutationCondition condition; - boolean implicitPreReadEnabled = true; + boolean implicitPreReadEnabled; private Buildable(@Nullable String namespace, String table, Key partitionKey) { super(namespace, table, partitionKey); @@ -208,6 +208,12 @@ public Buildable disableImplicitPreRead() { return this; } + @Override + public Buildable enableImplicitPreRead() { + implicitPreReadEnabled = true; + return this; + } + @Override public Buildable implicitPreReadEnabled(boolean implicitPreReadEnabled) { this.implicitPreReadEnabled = implicitPreReadEnabled; @@ -410,13 +416,19 @@ public BuildableFromExisting clearNamespace() { } @Override - public Buildable disableImplicitPreRead() { + public BuildableFromExisting disableImplicitPreRead() { super.disableImplicitPreRead(); return this; } @Override - public Buildable implicitPreReadEnabled(boolean implicitPreReadEnabled) { + public BuildableFromExisting enableImplicitPreRead() { + super.enableImplicitPreRead(); + return this; + } + + @Override + public BuildableFromExisting implicitPreReadEnabled(boolean implicitPreReadEnabled) { super.implicitPreReadEnabled(implicitPreReadEnabled); return this; } diff --git a/core/src/main/java/com/scalar/db/transaction/consensuscommit/CrudHandler.java b/core/src/main/java/com/scalar/db/transaction/consensuscommit/CrudHandler.java index b6af569547..0326313cd2 100644 --- a/core/src/main/java/com/scalar/db/transaction/consensuscommit/CrudHandler.java +++ b/core/src/main/java/com/scalar/db/transaction/consensuscommit/CrudHandler.java @@ -171,15 +171,20 @@ private List createScanResults(Scan scan, List projections, List } public void put(Put put) throws CrudException { - if (put.getCondition().isPresent() && !put.isImplicitPreReadEnabled()) { + Snapshot.Key key = new Snapshot.Key(put); + + if (put.getCondition().isPresent() + && (!put.isImplicitPreReadEnabled() && !snapshot.containsKeyInReadSet(key))) { throw new IllegalArgumentException( - "Put cannot have a condition when implicit pre-read is disabled: " + put); + "Put cannot have a condition when the target record is unread and implicit pre-read is disabled." + + " Please read the target record beforehand or enable implicit pre-read: " + + put); } - Snapshot.Key key = new Snapshot.Key(put); - if (put.getCondition().isPresent()) { - readUnread(key, createGet(key)); + if (put.isImplicitPreReadEnabled()) { + readUnread(key, createGet(key)); + } mutationConditionsValidator.checkIfConditionIsSatisfied( put, snapshot.getFromReadSet(key).orElse(null)); } diff --git a/core/src/test/java/com/scalar/db/api/PutBuilderTest.java b/core/src/test/java/com/scalar/db/api/PutBuilderTest.java index cc7b25d948..e09d866fbc 100644 --- a/core/src/test/java/com/scalar/db/api/PutBuilderTest.java +++ b/core/src/test/java/com/scalar/db/api/PutBuilderTest.java @@ -186,7 +186,7 @@ public void build_FromExistingWithoutChange_ShouldCopy() { .withIntValue("int2", Integer.valueOf(Integer.MAX_VALUE)) .withTextValue("text", "a_value") .withCondition(condition1) - .setImplicitPreReadEnabled(false); + .setImplicitPreReadEnabled(true); // Act Put newPut = Put.newBuilder(existingPut).build(); @@ -243,7 +243,7 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildPutWithUpdatedPa .textValue("text", "another_value") .value(TextColumn.of("text2", "foo")) .condition(condition2) - .implicitPreReadEnabled(false) + .enableImplicitPreRead() .build(); // Assert @@ -268,7 +268,7 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildPutWithUpdatedPa .withTextValue("text", "another_value") .withTextValue("text2", "foo") .withCondition(condition2) - .setImplicitPreReadEnabled(false)); + .setImplicitPreReadEnabled(true)); } @Test diff --git a/core/src/test/java/com/scalar/db/transaction/consensuscommit/CrudHandlerTest.java b/core/src/test/java/com/scalar/db/transaction/consensuscommit/CrudHandlerTest.java index 079828e2cc..00f37b5d6f 100644 --- a/core/src/test/java/com/scalar/db/transaction/consensuscommit/CrudHandlerTest.java +++ b/core/src/test/java/com/scalar/db/transaction/consensuscommit/CrudHandlerTest.java @@ -503,8 +503,9 @@ public void put_PutWithoutConditionGiven_ShouldCallAppropriateMethods() throws C } @Test - public void put_PutWithConditionGiven_WithResultInReadSet_ShouldCallAppropriateMethods() - throws CrudException { + public void + put_PutWithConditionAndImplicitPreReadEnabledGiven_WithResultInReadSet_ShouldCallAppropriateMethods() + throws CrudException { // Arrange Put put = Put.newBuilder() @@ -512,6 +513,7 @@ public void put_PutWithConditionGiven_WithResultInReadSet_ShouldCallAppropriateM .table("tbl") .partitionKey(Key.ofText("c1", "foo")) .condition(ConditionBuilder.putIfExists()) + .enableImplicitPreRead() .build(); Snapshot.Key key = new Snapshot.Key(put); when(snapshot.containsKeyInReadSet(any())).thenReturn(true); @@ -539,8 +541,9 @@ public void put_PutWithConditionGiven_WithResultInReadSet_ShouldCallAppropriateM } @Test - public void put_PutWithConditionGiven_WithoutResultInReadSet_ShouldCallAppropriateMethods() - throws CrudException { + public void + put_PutWithConditionAndImplicitPreReadEnabledGiven_WithoutResultInReadSet_ShouldCallAppropriateMethods() + throws CrudException { // Arrange Put put = Put.newBuilder() @@ -548,10 +551,13 @@ public void put_PutWithConditionGiven_WithoutResultInReadSet_ShouldCallAppropria .table("tbl") .partitionKey(Key.ofText("c1", "foo")) .condition(ConditionBuilder.putIfExists()) + .enableImplicitPreRead() .build(); Snapshot.Key key = new Snapshot.Key(put); when(snapshot.containsKeyInReadSet(any())).thenReturn(false); - when(snapshot.getFromReadSet(any())).thenReturn(Optional.empty()); + TransactionResult result = mock(TransactionResult.class); + when(result.isCommitted()).thenReturn(true); + when(snapshot.getFromReadSet(any())).thenReturn(Optional.of(result)); Get getForKey = Get.newBuilder() @@ -569,13 +575,50 @@ public void put_PutWithConditionGiven_WithoutResultInReadSet_ShouldCallAppropria // Assert verify(spied).readUnread(key, getForKey); verify(snapshot).getFromReadSet(key); - verify(mutationConditionsValidator).checkIfConditionIsSatisfied(put, null); + verify(mutationConditionsValidator).checkIfConditionIsSatisfied(put, result); + verify(snapshot).put(key, put); + } + + @Test + public void + put_PutWithConditionAndImplicitPreReadDisabledGiven_WithResultInReadSet_ShouldCallAppropriateMethods() + throws CrudException { + // Arrange + Put put = + Put.newBuilder() + .namespace("ns") + .table("tbl") + .partitionKey(Key.ofText("c1", "foo")) + .condition(ConditionBuilder.putIfExists()) + .build(); + Snapshot.Key key = new Snapshot.Key(put); + when(snapshot.containsKeyInReadSet(any())).thenReturn(true); + TransactionResult result = mock(TransactionResult.class); + when(result.isCommitted()).thenReturn(true); + when(snapshot.getFromReadSet(any())).thenReturn(Optional.of(result)); + + Get getForKey = + Get.newBuilder() + .namespace(key.getNamespace()) + .table(key.getTable()) + .partitionKey(key.getPartitionKey()) + .build(); + + CrudHandler spied = spy(handler); + + // Act + spied.put(put); + + // Assert + verify(spied, never()).readUnread(key, getForKey); + verify(snapshot).getFromReadSet(key); + verify(mutationConditionsValidator).checkIfConditionIsSatisfied(put, result); verify(snapshot).put(key, put); } @Test public void - put_PutWithImplicitPreReadDisabledAndConditionGiven_ShouldThrowIllegalArgumentException() { + put_PutWithConditionAndImplicitPreReadDisabledGiven_WithoutResultInReadSet_ShouldThrowIllegalArgumentException() { // Arrange Put put = Put.newBuilder() diff --git a/core/src/test/java/com/scalar/db/util/ProtoUtilsTest.java b/core/src/test/java/com/scalar/db/util/ProtoUtilsTest.java index c20a74cfaf..46d045bf53 100644 --- a/core/src/test/java/com/scalar/db/util/ProtoUtilsTest.java +++ b/core/src/test/java/com/scalar/db/util/ProtoUtilsTest.java @@ -911,7 +911,7 @@ public void toMutation_ProtoPutGiven_ShouldConvertProperly() { .build()) .build()) .setConsistency(com.scalar.db.rpc.Consistency.CONSISTENCY_EVENTUAL) - .setImplicitPreReadEnabled(false) + .setImplicitPreReadEnabled(true) .setNamespace("ns") .setTable("tbl") .build(); @@ -945,7 +945,7 @@ public void toMutation_ProtoPutGiven_ShouldConvertProperly() { .and(ConditionBuilder.column("col7").isNotNullBlob()) .build()) .consistency(Consistency.EVENTUAL) - .disableImplicitPreRead() + .enableImplicitPreRead() .build()); } @@ -1016,7 +1016,7 @@ public void toMutation_PutWithNullValuesGiven_ShouldConvertProperly() { .setType(com.scalar.db.rpc.MutateCondition.Type.PUT_IF_NOT_EXISTS)) .setNamespace("ns") .setTable("tbl") - .setImplicitPreReadEnabled(true) + .setImplicitPreReadEnabled(false) .build()); } @@ -1057,7 +1057,7 @@ public void toMutation_ProtoPutWithNullValuesGiven_ShouldConvertProperly() { MutateCondition.newBuilder() .setType(com.scalar.db.rpc.MutateCondition.Type.PUT_IF_NOT_EXISTS)) .setConsistency(com.scalar.db.rpc.Consistency.CONSISTENCY_EVENTUAL) - .setImplicitPreReadEnabled(true) + .setImplicitPreReadEnabled(false) .setNamespace("ns") .setTable("tbl") .build(); @@ -1082,7 +1082,7 @@ public void toMutation_ProtoPutWithNullValuesGiven_ShouldConvertProperly() { .blobValue("col7", (byte[]) null) .condition(ConditionBuilder.putIfNotExists()) .consistency(Consistency.EVENTUAL) - .implicitPreReadEnabled(true) + .disableImplicitPreRead() .build()); } @@ -1317,7 +1317,7 @@ public void toMutation_ProtoPutWithNullValuesFromOldClientGiven_ShouldConvertPro .and(ConditionBuilder.column("col5").isLessThanOrEqualToDouble(4.56)) .build()) .consistency(Consistency.EVENTUAL) - .implicitPreReadEnabled(true) + .enableImplicitPreRead() .build()); } diff --git a/docs/api-guide.md b/docs/api-guide.md index 145532f910..7460f1b2db 100644 --- a/docs/api-guide.md +++ b/docs/api-guide.md @@ -750,6 +750,14 @@ For more details about available conditions and condition sets, see the `Conditi `Put` is an operation to put a record specified by a primary key. The operation behaves as an upsert operation for a record, in which the operation updates the record if the record exists or inserts the record if the record does not exist. +{% capture notice--info %} +**Note** + +When you update an existing record, you need to read the record by using `Get` or `Scan` before using a `Put` operation. Otherwise, the operation will fail due to a conflict. This occurs because of the specification of ScalarDB to manage transactions properly. Instead of reading the record explicitly, you can enable implicit pre-read. For details, see [Enable implicit pre-read for `Put` operations](#enable-implicit-pre-read-for-put-operations). +{% endcapture %} + +
{{ notice--info | markdownify }}
+ You need to create a `Put` object first, and then you can execute the object by using the `transaction.put()` method as follows: ```java @@ -785,13 +793,11 @@ Put put = .build(); ``` -##### Disable implicit pre-read for `Put` operations - -In Consensus Commit, an application must read a record before mutating the record with `Put` and `Delete` operations to obtain the latest states of the record if the record exists. If an application does not read the record explicitly in a transaction, ScalarDB will read the record on behalf of the application before committing the transaction. We call this feature *implicit pre-read*. +##### Enable implicit pre-read for `Put` operations -If you are certain that a record you are trying to mutate does not exist, you can disable implicit pre-read for the `Put` operation for better performance. For example, if you load initial data, you can and should disable implicit pre-read. A `Put` operation without implicit pre-read is faster than a regular `Put` operation because the operation skips an unnecessary read. However, if the record exists, the operation will fail due to a conflict. This occurs because ScalarDB assumes that another transaction wrote the record. +In Consensus Commit, an application must read a record before mutating the record with `Put` and `Delete` operations to obtain the latest states of the record if the record exists. Instead of reading the record explicitly, you can enable *implicit pre-read*. By enabling implicit pre-read, if an application does not read the record explicitly in a transaction, ScalarDB will read the record on behalf of the application before committing the transaction. -You can disable implicit pre-read for a `Put` operation by specifying `disableImplicitPreRead()` in the `Put` operation builder as follows: +You can enable implicit pre-read for a `Put` operation by specifying `enableImplicitPreRead()` in the `Put` operation builder as follows: ```java Put put = @@ -802,14 +808,30 @@ Put put = .clusteringKey(clusteringKey) .floatValue("c4", 1.23F) .doubleValue("c5", 4.56) - .disableImplicitPreRead() + .enableImplicitPreRead() .build(); ``` +{% capture notice--info %} +**Note** + +If you are certain that a record you are trying to mutate does not exist, you should not enable implicit pre-read for the `Put` operation for better performance. For example, if you load initial data, you should not enable implicit pre-read. A `Put` operation without implicit pre-read is faster than `Put` operation with implicit pre-read because the operation skips an unnecessary read. +{% endcapture %} + +
{{ notice--info | markdownify }}
+ #### `Delete` operation `Delete` is an operation to delete a record specified by a primary key. +{% capture notice--info %} +**Note** + +When you delete a record, you don't have to read the record beforehand because implicit pre-read is always enabled for `Delete` operations. +{% endcapture %} + +
{{ notice--info | markdownify }}
+ You need to create a `Delete` object first, and then you can execute the object by using the `transaction.delete()` method as follows: ```java @@ -835,6 +857,15 @@ You can write arbitrary conditions (for example, a bank account balance must be When a `Put` or `Delete` operation includes a condition, the operation is executed only if the specified condition is met. If the condition is not met when the operation is executed, an exception called `UnsatisfiedConditionException` will be thrown. +{% capture notice--info %} +**Note** + +When you specify a condition in a `Put` operation, you need to read the record beforehand or enable implicit pre-read. +{% endcapture %} + +
{{ notice--info | markdownify }}
+ + ##### Conditions for `Put` You can specify a condition in a `Put` operation as follows: diff --git a/docs/storage-abstraction.md b/docs/storage-abstraction.md index d4ddf0f69a..5c090c21b7 100644 --- a/docs/storage-abstraction.md +++ b/docs/storage-abstraction.md @@ -680,7 +680,7 @@ Put put = {% capture notice--info %} **Note** -If you specify `disableImplicitPreRead()` or `implicitPreReadEnabled()` in the `Put` operation builder, they will be ignored. +If you specify `enableImplicitPreRead()`, `disableImplicitPreRead()`, or `implicitPreReadEnabled()` in the `Put` operation builder, they will be ignored. {% endcapture %} diff --git a/integration-test/src/main/java/com/scalar/db/api/DistributedTransactionIntegrationTestBase.java b/integration-test/src/main/java/com/scalar/db/api/DistributedTransactionIntegrationTestBase.java index 6b6b2bceb2..0c75502c20 100644 --- a/integration-test/src/main/java/com/scalar/db/api/DistributedTransactionIntegrationTestBase.java +++ b/integration-test/src/main/java/com/scalar/db/api/DistributedTransactionIntegrationTestBase.java @@ -599,6 +599,7 @@ public void putAndCommit_PutGivenForExisting_ShouldUpdateRecord() throws Transac .partitionKey(Key.ofInt(ACCOUNT_ID, 0)) .clusteringKey(Key.ofInt(ACCOUNT_TYPE, 0)) .intValue(BALANCE, expected) + .enableImplicitPreRead() .build(); transaction.put(put); transaction.commit(); @@ -839,7 +840,11 @@ public void mutateAndCommit_AfterRead_ShouldMutateRecordsProperly() throws Trans public void mutateAndCommit_ShouldMutateRecordsProperly() throws TransactionException { // Arrange populateRecords(); - Put put = preparePut(0, 0).withIntValue(BALANCE, INITIAL_BALANCE - 100); + Put put = + Put.newBuilder(preparePut(0, 0)) + .intValue(BALANCE, INITIAL_BALANCE - 100) + .enableImplicitPreRead() + .build(); Delete delete = prepareDelete(1, 0); DistributedTransaction transaction = manager.begin(); @@ -1126,6 +1131,7 @@ public void put_withPutIfWithVerifiedCondition_shouldPutProperly() throws Transa ConditionBuilder.column(BALANCE).isEqualToInt(INITIAL_BALANCE)) .and(ConditionBuilder.column(SOME_COLUMN).isNotNullInt()) .build()) + .enableImplicitPreRead() .build(); // Act @@ -1150,6 +1156,7 @@ public void put_withPutIfExistsWhenRecordExists_shouldPutProperly() throws Trans Put.newBuilder(put) .intValue(BALANCE, INITIAL_BALANCE) .condition(ConditionBuilder.putIfExists()) + .enableImplicitPreRead() .build(); // Act @@ -1170,7 +1177,10 @@ public void put_withPutIfNotExistsWhenRecordDoesNotExist_shouldPutProperly() throws TransactionException { // Arrange Put putIfNotExists = - Put.newBuilder(preparePut(0, 0)).condition(ConditionBuilder.putIfNotExists()).build(); + Put.newBuilder(preparePut(0, 0)) + .condition(ConditionBuilder.putIfNotExists()) + .enableImplicitPreRead() + .build(); // Act put(putIfNotExists); @@ -1235,6 +1245,7 @@ public void put_withPutIfWhenRecordDoesNotExist_shouldThrowUnsatisfiedConditionE Put.newBuilder(preparePut(0, 0)) .intValue(BALANCE, INITIAL_BALANCE) .condition(ConditionBuilder.putIf(ConditionBuilder.column(BALANCE).isNullInt()).build()) + .enableImplicitPreRead() .build(); // Act Assert @@ -1252,6 +1263,7 @@ public void put_withPutIfExistsWhenRecordDoesNotExist_shouldThrowUnsatisfiedCond Put.newBuilder(preparePut(0, 0)) .intValue(BALANCE, INITIAL_BALANCE) .condition(ConditionBuilder.putIfExists()) + .enableImplicitPreRead() .build(); // Act Assert @@ -1267,7 +1279,11 @@ public void put_withPutIfNotExistsWhenRecordExists_shouldThrowUnsatisfiedConditi // Arrange Put put = preparePut(0, 0); put(put); - Put putIfNotExists = Put.newBuilder(put).condition(ConditionBuilder.putIfNotExists()).build(); + Put putIfNotExists = + Put.newBuilder(put) + .condition(ConditionBuilder.putIfNotExists()) + .enableImplicitPreRead() + .build(); // Act Assert assertThatThrownBy(() -> put(putIfNotExists)).isInstanceOf(UnsatisfiedConditionException.class); @@ -1336,6 +1352,7 @@ public void put_withPutIfWithNonVerifiedCondition_shouldThrowUnsatisfiedConditio ConditionBuilder.column(BALANCE).isEqualToInt(INITIAL_BALANCE)) .and(ConditionBuilder.column(SOME_COLUMN).isNotNullInt()) .build()) + .enableImplicitPreRead() .build(); // Act Assert diff --git a/integration-test/src/main/java/com/scalar/db/api/TwoPhaseCommitTransactionIntegrationTestBase.java b/integration-test/src/main/java/com/scalar/db/api/TwoPhaseCommitTransactionIntegrationTestBase.java index fb620f8a2d..a98eeca9e7 100644 --- a/integration-test/src/main/java/com/scalar/db/api/TwoPhaseCommitTransactionIntegrationTestBase.java +++ b/integration-test/src/main/java/com/scalar/db/api/TwoPhaseCommitTransactionIntegrationTestBase.java @@ -516,6 +516,7 @@ public void putAndCommit_PutGivenForExisting_ShouldUpdateRecord() throws Transac .partitionKey(Key.ofInt(ACCOUNT_ID, 0)) .clusteringKey(Key.ofInt(ACCOUNT_TYPE, 0)) .intValue(BALANCE, expected) + .enableImplicitPreRead() .build(); transaction.put(put); transaction.prepare(); @@ -788,7 +789,11 @@ public void mutateAndCommit_AfterRead_ShouldMutateRecordsProperly() throws Trans public void mutateAndCommit_ShouldMutateRecordsProperly() throws TransactionException { // Arrange populateRecords(manager1, namespace1, TABLE_1); - Put put = preparePut(0, 0, namespace1, TABLE_1).withIntValue(BALANCE, INITIAL_BALANCE - 100); + Put put = + Put.newBuilder(preparePut(0, 0, namespace1, TABLE_1)) + .intValue(BALANCE, INITIAL_BALANCE - 100) + .enableImplicitPreRead() + .build(); Delete delete = prepareDelete(1, 0, namespace1, TABLE_1); TwoPhaseCommitTransaction transaction = manager1.begin(); @@ -819,7 +824,11 @@ public void mutateAndCommit_WithMultipleSubTransactions_ShouldMutateRecordsPrope populateRecords(manager1, namespace1, TABLE_1); populateRecords(manager2, namespace2, TABLE_2); - Put put = preparePut(0, 0, namespace1, TABLE_1).withIntValue(BALANCE, INITIAL_BALANCE - 100); + Put put = + Put.newBuilder(preparePut(0, 0, namespace1, TABLE_1)) + .intValue(BALANCE, INITIAL_BALANCE - 100) + .enableImplicitPreRead() + .build(); Delete delete = prepareDelete(1, 0, namespace2, TABLE_2); TwoPhaseCommitTransaction transaction1 = manager1.begin(); @@ -871,7 +880,11 @@ public void mutateAndRollback_WithMultipleSubTransactions_ShouldRollbackRecordsP populateRecords(manager1, namespace1, TABLE_1); populateRecords(manager2, namespace2, TABLE_2); - Put put = preparePut(0, 0, namespace1, TABLE_1).withIntValue(BALANCE, INITIAL_BALANCE - 100); + Put put = + Put.newBuilder(preparePut(0, 0, namespace1, TABLE_1)) + .intValue(BALANCE, INITIAL_BALANCE - 100) + .enableImplicitPreRead() + .build(); Delete delete = prepareDelete(1, 0, namespace2, TABLE_2); TwoPhaseCommitTransaction transaction1 = manager1.begin(); @@ -1356,6 +1369,7 @@ public void put_withPutIfWithVerifiedCondition_shouldPutProperly() throws Transa ConditionBuilder.column(BALANCE).isEqualToInt(INITIAL_BALANCE)) .and(ConditionBuilder.column(SOME_COLUMN).isNotNullInt()) .build()) + .enableImplicitPreRead() .build(); // Act @@ -1389,6 +1403,7 @@ public void put_withPutIfWithNonVerifiedCondition_shouldThrowUnsatisfiedConditio ConditionBuilder.column(BALANCE).isEqualToInt(INITIAL_BALANCE)) .and(ConditionBuilder.column(SOME_COLUMN).isNotNullInt()) .build()) + .enableImplicitPreRead() .build(); // Act Assert @@ -1412,6 +1427,7 @@ public void put_withPutIfWhenRecordDoesNotExist_shouldThrowUnsatisfiedConditionE .intValue(BALANCE, INITIAL_BALANCE) .condition( ConditionBuilder.putIf(ConditionBuilder.column(BALANCE).isNullText()).build()) + .enableImplicitPreRead() .build(); // Act Assert @@ -1429,6 +1445,7 @@ public void put_withPutIfExistsWhenRecordDoesNotExist_shouldThrowUnsatisfiedCond Put.newBuilder(preparePut(0, 0, namespace1, TABLE_1)) .intValue(BALANCE, INITIAL_BALANCE) .condition(ConditionBuilder.putIfExists()) + .enableImplicitPreRead() .build(); // Act Assert @@ -1447,6 +1464,7 @@ public void put_withPutIfExistsWhenRecordExists_shouldPutProperly() throws Trans Put.newBuilder(put) .intValue(BALANCE, INITIAL_BALANCE) .condition(ConditionBuilder.putIfExists()) + .enableImplicitPreRead() .build(); // Act @@ -1469,6 +1487,7 @@ public void put_withPutIfNotExistsWhenRecordDoesNotExist_shouldPutProperly() Put putIfNotExists = Put.newBuilder(preparePut(0, 0, namespace1, TABLE_1)) .condition(ConditionBuilder.putIfNotExists()) + .enableImplicitPreRead() .build(); // Act @@ -1494,6 +1513,7 @@ public void put_withPutIfNotExistsWhenRecordExists_shouldThrowUnsatisfiedConditi Put.newBuilder(put) .intValue(BALANCE, INITIAL_BALANCE) .condition(ConditionBuilder.putIfNotExists()) + .enableImplicitPreRead() .build(); // Act Assert diff --git a/integration-test/src/main/java/com/scalar/db/transaction/consensuscommit/ConsensusCommitNullMetadataIntegrationTestBase.java b/integration-test/src/main/java/com/scalar/db/transaction/consensuscommit/ConsensusCommitNullMetadataIntegrationTestBase.java index 839f3e5ad6..3a9510e923 100644 --- a/integration-test/src/main/java/com/scalar/db/transaction/consensuscommit/ConsensusCommitNullMetadataIntegrationTestBase.java +++ b/integration-test/src/main/java/com/scalar/db/transaction/consensuscommit/ConsensusCommitNullMetadataIntegrationTestBase.java @@ -1247,7 +1247,7 @@ public void putAndCommit_PutGivenForExistingAfterRead_ShouldUpdateRecord() } @Test - public void putAndCommit_PutGivenForExistingAndNeverRead_ShouldUpdateRecord() + public void putAndCommit_PutWithImplicitPreReadEnabledGivenForExisting_ShouldUpdateRecord() throws TransactionException, ExecutionException { // Arrange populateRecordsWithNullMetadata(namespace1, TABLE_1); @@ -1256,7 +1256,10 @@ public void putAndCommit_PutGivenForExistingAndNeverRead_ShouldUpdateRecord() // Act int expected = INITIAL_BALANCE + 100; - Put put = preparePut(0, 0, expected, namespace1, TABLE_1); + Put put = + Put.newBuilder(preparePut(0, 0, expected, namespace1, TABLE_1)) + .enableImplicitPreRead() + .build(); transaction.put(put); transaction.commit(); 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 c51722e8a9..6fcdc7a60c 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 @@ -1102,7 +1102,7 @@ public void putAndCommit_PutGivenForExistingAfterRead_ShouldUpdateRecord() } @Test - public void putAndCommit_PutGivenForExistingAndNeverRead_ShouldUpdateRecord() + public void putAndCommit_PutWithImplicitPreReadEnabledGivenForExisting_ShouldUpdateRecord() throws TransactionException, ExecutionException { // Arrange populateRecords(namespace1, TABLE_1); @@ -1110,7 +1110,11 @@ public void putAndCommit_PutGivenForExistingAndNeverRead_ShouldUpdateRecord() // Act int expected = INITIAL_BALANCE + 100; - Put put = preparePut(0, 0, namespace1, TABLE_1).withValue(BALANCE, expected); + Put put = + Put.newBuilder(preparePut(0, 0, namespace1, TABLE_1)) + .intValue(BALANCE, expected) + .enableImplicitPreRead() + .build(); transaction.put(put); transaction.commit(); diff --git a/integration-test/src/main/java/com/scalar/db/transaction/consensuscommit/TwoPhaseConsensusCommitSpecificIntegrationTestBase.java b/integration-test/src/main/java/com/scalar/db/transaction/consensuscommit/TwoPhaseConsensusCommitSpecificIntegrationTestBase.java index cb5a5cde74..c5c0e39932 100644 --- a/integration-test/src/main/java/com/scalar/db/transaction/consensuscommit/TwoPhaseConsensusCommitSpecificIntegrationTestBase.java +++ b/integration-test/src/main/java/com/scalar/db/transaction/consensuscommit/TwoPhaseConsensusCommitSpecificIntegrationTestBase.java @@ -1100,7 +1100,7 @@ public void putAndCommit_PutGivenForExistingAfterRead_ShouldUpdateRecord() } @Test - public void putAndCommit_PutGivenForExistingAndNeverRead_ShouldUpdateRecord() + public void putAndCommit_PutWithImplicitPreReadEnabledGivenForExisting_ShouldUpdateRecord() throws TransactionException { // Arrange populate(manager1, namespace1, TABLE_1); @@ -1109,7 +1109,12 @@ public void putAndCommit_PutGivenForExistingAndNeverRead_ShouldUpdateRecord() // Act int afterBalance = INITIAL_BALANCE + 100; - transaction.put(preparePut(0, 0, namespace1, TABLE_1).withValue(BALANCE, afterBalance)); + Put put = + Put.newBuilder(preparePut(0, 0, namespace1, TABLE_1)) + .intValue(BALANCE, afterBalance) + .enableImplicitPreRead() + .build(); + transaction.put(put); transaction.prepare(); transaction.commit();