Skip to content

Commit 88ccee8

Browse files
authored
Add support for beginning transactions in read-only mode (#2749)
1 parent ec595ae commit 88ccee8

26 files changed

+1328
-175
lines changed

core/src/main/java/com/scalar/db/api/DistributedTransactionManager.java

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,34 @@ public interface DistributedTransactionManager
8181
DistributedTransaction begin(String txId)
8282
throws TransactionNotFoundException, TransactionException;
8383

84+
/**
85+
* Begins a new transaction in read-only mode.
86+
*
87+
* @return {@link DistributedTransaction}
88+
* @throws TransactionNotFoundException if the transaction fails to begin due to transient faults.
89+
* You can retry the transaction
90+
* @throws TransactionException if the transaction fails to begin due to transient or nontransient
91+
* faults. You can try retrying the transaction, but you may not be able to begin the
92+
* transaction due to nontransient faults
93+
*/
94+
DistributedTransaction beginReadOnly() throws TransactionNotFoundException, TransactionException;
95+
96+
/**
97+
* Begins a new transaction with the specified transaction ID in read-only mode. It is users'
98+
* responsibility to guarantee uniqueness of the ID, so it is not recommended to use this method
99+
* unless you know exactly what you are doing.
100+
*
101+
* @param txId an user-provided unique transaction ID
102+
* @return {@link DistributedTransaction}
103+
* @throws TransactionNotFoundException if the transaction fails to begin due to transient faults.
104+
* You can retry the transaction
105+
* @throws TransactionException if the transaction fails to begin due to transient or nontransient
106+
* faults. You can try retrying the transaction, but you may not be able to begin the
107+
* transaction due to nontransient faults
108+
*/
109+
DistributedTransaction beginReadOnly(String txId)
110+
throws TransactionNotFoundException, TransactionException;
111+
84112
/**
85113
* Starts a new transaction. This method is an alias of {@link #begin()}.
86114
*
@@ -112,6 +140,39 @@ default DistributedTransaction start(String txId)
112140
return begin(txId);
113141
}
114142

143+
/**
144+
* Starts a new transaction in read-only mode. This method is an alias of {@link
145+
* #beginReadOnly()}.
146+
*
147+
* @return {@link DistributedTransaction}
148+
* @throws TransactionNotFoundException if the transaction fails to start due to transient faults.
149+
* You can retry the transaction
150+
* @throws TransactionException if the transaction fails to start due to transient or nontransient
151+
* faults. You can try retrying the transaction, but you may not be able to start the
152+
* transaction due to nontransient faults
153+
*/
154+
default DistributedTransaction startReadOnly()
155+
throws TransactionNotFoundException, TransactionException {
156+
return beginReadOnly();
157+
}
158+
159+
/**
160+
* Starts a new transaction with the specified transaction ID in read-only mode. This method is an
161+
* alias of {@link #beginReadOnly(String)}.
162+
*
163+
* @param txId an user-provided unique transaction ID
164+
* @return {@link DistributedTransaction}
165+
* @throws TransactionNotFoundException if the transaction fails to start due to transient faults.
166+
* You can retry the transaction
167+
* @throws TransactionException if the transaction fails to start due to transient or nontransient
168+
* faults. You can try retrying the transaction, but you may not be able to start the
169+
* transaction due to nontransient faults
170+
*/
171+
default DistributedTransaction startReadOnly(String txId)
172+
throws TransactionNotFoundException, TransactionException {
173+
return beginReadOnly(txId);
174+
}
175+
115176
/**
116177
* Starts a new transaction with the specified {@link Isolation} level.
117178
*

core/src/main/java/com/scalar/db/common/ActiveTransactionManagedDistributedTransactionManager.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@
2626
import java.util.Optional;
2727
import java.util.concurrent.atomic.AtomicReference;
2828
import java.util.function.BiConsumer;
29+
import javax.annotation.concurrent.ThreadSafe;
2930
import org.slf4j.Logger;
3031
import org.slf4j.LoggerFactory;
3132

33+
@ThreadSafe
3234
public class ActiveTransactionManagedDistributedTransactionManager
3335
extends DecoratedDistributedTransactionManager {
3436

core/src/main/java/com/scalar/db/common/ActiveTransactionManagedTwoPhaseCommitTransactionManager.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@
2828
import java.util.Optional;
2929
import java.util.concurrent.atomic.AtomicReference;
3030
import java.util.function.BiConsumer;
31+
import javax.annotation.concurrent.ThreadSafe;
3132
import org.slf4j.Logger;
3233
import org.slf4j.LoggerFactory;
3334

35+
@ThreadSafe
3436
public class ActiveTransactionManagedTwoPhaseCommitTransactionManager
3537
extends DecoratedTwoPhaseCommitTransactionManager {
3638

core/src/main/java/com/scalar/db/common/DecoratedDistributedTransactionManager.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,16 @@ public DistributedTransaction begin(String txId) throws TransactionException {
7676
return decorateTransactionOnBeginOrStart(transactionManager.begin(txId));
7777
}
7878

79+
@Override
80+
public DistributedTransaction beginReadOnly() throws TransactionException {
81+
return decorateTransactionOnBeginOrStart(transactionManager.beginReadOnly());
82+
}
83+
84+
@Override
85+
public DistributedTransaction beginReadOnly(String txId) throws TransactionException {
86+
return decorateTransactionOnBeginOrStart(transactionManager.beginReadOnly(txId));
87+
}
88+
7989
@Override
8090
public DistributedTransaction start() throws TransactionException {
8191
return decorateTransactionOnBeginOrStart(transactionManager.start());
@@ -86,6 +96,16 @@ public DistributedTransaction start(String txId) throws TransactionException {
8696
return decorateTransactionOnBeginOrStart(transactionManager.start(txId));
8797
}
8898

99+
@Override
100+
public DistributedTransaction startReadOnly(String txId) throws TransactionException {
101+
return decorateTransactionOnBeginOrStart(transactionManager.startReadOnly(txId));
102+
}
103+
104+
@Override
105+
public DistributedTransaction startReadOnly() throws TransactionException {
106+
return decorateTransactionOnBeginOrStart(transactionManager.startReadOnly());
107+
}
108+
89109
/** @deprecated As of release 2.4.0. Will be removed in release 4.0.0. */
90110
@Deprecated
91111
@Override
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package com.scalar.db.common;
2+
3+
import com.scalar.db.api.Delete;
4+
import com.scalar.db.api.DistributedTransaction;
5+
import com.scalar.db.api.Insert;
6+
import com.scalar.db.api.Mutation;
7+
import com.scalar.db.api.Put;
8+
import com.scalar.db.api.Update;
9+
import com.scalar.db.api.Upsert;
10+
import com.scalar.db.common.error.CoreError;
11+
import com.scalar.db.exception.transaction.CrudException;
12+
import java.util.List;
13+
import javax.annotation.concurrent.NotThreadSafe;
14+
15+
@NotThreadSafe
16+
public class ReadOnlyDistributedTransaction extends DecoratedDistributedTransaction {
17+
18+
public ReadOnlyDistributedTransaction(DistributedTransaction transaction) {
19+
super(transaction);
20+
}
21+
22+
/** @deprecated As of release 3.13.0. Will be removed in release 5.0.0. */
23+
@Deprecated
24+
@Override
25+
public void put(Put put) throws CrudException {
26+
throw new IllegalStateException(
27+
CoreError.MUTATION_NOT_ALLOWED_IN_READ_ONLY_TRANSACTION.buildMessage(getId()));
28+
}
29+
30+
/** @deprecated As of release 3.13.0. Will be removed in release 5.0.0. */
31+
@Deprecated
32+
@Override
33+
public void put(List<Put> puts) throws CrudException {
34+
throw new IllegalStateException(
35+
CoreError.MUTATION_NOT_ALLOWED_IN_READ_ONLY_TRANSACTION.buildMessage(getId()));
36+
}
37+
38+
@Override
39+
public void insert(Insert insert) throws CrudException {
40+
throw new IllegalStateException(
41+
CoreError.MUTATION_NOT_ALLOWED_IN_READ_ONLY_TRANSACTION.buildMessage(getId()));
42+
}
43+
44+
@Override
45+
public void upsert(Upsert upsert) throws CrudException {
46+
throw new IllegalStateException(
47+
CoreError.MUTATION_NOT_ALLOWED_IN_READ_ONLY_TRANSACTION.buildMessage(getId()));
48+
}
49+
50+
@Override
51+
public void update(Update update) throws CrudException {
52+
throw new IllegalStateException(
53+
CoreError.MUTATION_NOT_ALLOWED_IN_READ_ONLY_TRANSACTION.buildMessage(getId()));
54+
}
55+
56+
@Override
57+
public void delete(Delete delete) throws CrudException {
58+
throw new IllegalStateException(
59+
CoreError.MUTATION_NOT_ALLOWED_IN_READ_ONLY_TRANSACTION.buildMessage(getId()));
60+
}
61+
62+
/** @deprecated As of release 3.13.0. Will be removed in release 5.0.0. */
63+
@Deprecated
64+
@Override
65+
public void delete(List<Delete> deletes) throws CrudException {
66+
throw new IllegalStateException(
67+
CoreError.MUTATION_NOT_ALLOWED_IN_READ_ONLY_TRANSACTION.buildMessage(getId()));
68+
}
69+
70+
@Override
71+
public void mutate(List<? extends Mutation> mutations) throws CrudException {
72+
throw new IllegalStateException(
73+
CoreError.MUTATION_NOT_ALLOWED_IN_READ_ONLY_TRANSACTION.buildMessage(getId()));
74+
}
75+
}

core/src/main/java/com/scalar/db/common/StateManagedDistributedTransactionManager.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
import com.scalar.db.exception.transaction.UnknownTransactionStatusException;
2121
import java.util.List;
2222
import java.util.Optional;
23+
import javax.annotation.concurrent.ThreadSafe;
2324

25+
@ThreadSafe
2426
public class StateManagedDistributedTransactionManager
2527
extends DecoratedDistributedTransactionManager {
2628

core/src/main/java/com/scalar/db/common/StateManagedTwoPhaseCommitTransactionManager.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
import com.scalar.db.exception.transaction.ValidationException;
2323
import java.util.List;
2424
import java.util.Optional;
25+
import javax.annotation.concurrent.ThreadSafe;
2526

27+
@ThreadSafe
2628
public class StateManagedTwoPhaseCommitTransactionManager
2729
extends DecoratedTwoPhaseCommitTransactionManager {
2830

core/src/main/java/com/scalar/db/common/error/CoreError.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,12 @@ public enum CoreError implements ScalarDbError {
930930
Category.USER_ERROR, "0209", "Number of max threads must be greater than 0", "", ""),
931931
DATA_LOADER_INVALID_DATA_CHUNK_QUEUE_SIZE(
932932
Category.USER_ERROR, "0210", "Data chunk queue size must be greater than 0", "", ""),
933+
MUTATION_NOT_ALLOWED_IN_READ_ONLY_TRANSACTION(
934+
Category.USER_ERROR,
935+
"0211",
936+
"Mutations are not allowed in read-only transactions. Transaction ID: %s",
937+
"",
938+
""),
933939

934940
//
935941
// Errors for the concurrency error category

core/src/main/java/com/scalar/db/service/TransactionService.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,16 @@ public DistributedTransaction begin(String txId) throws TransactionException {
8181
return manager.begin(txId);
8282
}
8383

84+
@Override
85+
public DistributedTransaction beginReadOnly() throws TransactionException {
86+
return manager.beginReadOnly();
87+
}
88+
89+
@Override
90+
public DistributedTransaction beginReadOnly(String txId) throws TransactionException {
91+
return manager.beginReadOnly(txId);
92+
}
93+
8494
@Override
8595
public DistributedTransaction start() throws TransactionException {
8696
return manager.start();
@@ -91,6 +101,16 @@ public DistributedTransaction start(String txId) throws TransactionException {
91101
return manager.start(txId);
92102
}
93103

104+
@Override
105+
public DistributedTransaction startReadOnly() throws TransactionException {
106+
return manager.startReadOnly();
107+
}
108+
109+
@Override
110+
public DistributedTransaction startReadOnly(String txId) throws TransactionException {
111+
return manager.startReadOnly(txId);
112+
}
113+
94114
/** @deprecated As of release 2.4.0. Will be removed in release 4.0.0. */
95115
@Deprecated
96116
@Override

core/src/main/java/com/scalar/db/storage/dynamo/SelectStatementHandler.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ public class SelectStatementHandler {
5858
* @param client {@code DynamoDbClient}
5959
* @param metadataManager {@code TableMetadataManager}
6060
* @param namespacePrefix a namespace prefix
61+
* @param fetchSize the number of items to fetch in each request
6162
*/
6263
@SuppressFBWarnings("EI_EXPOSE_REP2")
6364
public SelectStatementHandler(

0 commit comments

Comments
 (0)