-
Notifications
You must be signed in to change notification settings - Fork 40
Support begin in read-only mode for Consensus Commit transactions #2739
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -47,6 +47,10 @@ public class CrudHandler { | |
| private final boolean isIncludeMetadataEnabled; | ||
| private final MutationConditionsValidator mutationConditionsValidator; | ||
| private final ParallelExecutor parallelExecutor; | ||
|
|
||
| // Whether the transaction is in read-only mode or not. | ||
| private final boolean readOnly; | ||
|
|
||
| private final List<ConsensusCommitScanner> scanners = new ArrayList<>(); | ||
|
|
||
| @SuppressFBWarnings("EI_EXPOSE_REP2") | ||
|
|
@@ -55,13 +59,15 @@ public CrudHandler( | |
| Snapshot snapshot, | ||
| TransactionTableMetadataManager tableMetadataManager, | ||
| boolean isIncludeMetadataEnabled, | ||
| ParallelExecutor parallelExecutor) { | ||
| ParallelExecutor parallelExecutor, | ||
| boolean readOnly) { | ||
| this.storage = checkNotNull(storage); | ||
| this.snapshot = checkNotNull(snapshot); | ||
| this.tableMetadataManager = tableMetadataManager; | ||
| this.isIncludeMetadataEnabled = isIncludeMetadataEnabled; | ||
| this.mutationConditionsValidator = new MutationConditionsValidator(snapshot.getId()); | ||
| this.parallelExecutor = parallelExecutor; | ||
| this.readOnly = readOnly; | ||
| } | ||
|
|
||
| @VisibleForTesting | ||
|
|
@@ -71,13 +77,15 @@ public CrudHandler( | |
| TransactionTableMetadataManager tableMetadataManager, | ||
| boolean isIncludeMetadataEnabled, | ||
| MutationConditionsValidator mutationConditionsValidator, | ||
| ParallelExecutor parallelExecutor) { | ||
| ParallelExecutor parallelExecutor, | ||
| boolean readOnly) { | ||
| this.storage = checkNotNull(storage); | ||
| this.snapshot = checkNotNull(snapshot); | ||
| this.tableMetadataManager = tableMetadataManager; | ||
| this.isIncludeMetadataEnabled = isIncludeMetadataEnabled; | ||
| this.mutationConditionsValidator = mutationConditionsValidator; | ||
| this.parallelExecutor = parallelExecutor; | ||
| this.readOnly = readOnly; | ||
| } | ||
|
|
||
| public Optional<Result> get(Get originalGet) throws CrudException { | ||
|
|
@@ -122,19 +130,19 @@ void read(@Nullable Snapshot.Key key, Get get) throws CrudException { | |
| // conjunction or the result exists. This is because we don’t know whether the record | ||
| // actually exists or not due to the conjunction. | ||
| if (key != null) { | ||
| snapshot.putIntoReadSet(key, result); | ||
| putIntoReadSetInSnapshot(key, result); | ||
| } else { | ||
| // Only for a Get with index, the argument `key` is null | ||
|
|
||
| if (result.isPresent()) { | ||
| // Only when we can get the record with the Get with index, we can put it into the read | ||
| // set | ||
| key = new Snapshot.Key(get, result.get()); | ||
| snapshot.putIntoReadSet(key, result); | ||
| putIntoReadSetInSnapshot(key, result); | ||
| } | ||
| } | ||
| } | ||
| snapshot.putIntoGetSet(get, result); // for re-read and validation | ||
| snapshot.putIntoGetSet(get, result); | ||
| return; | ||
| } | ||
| throw new UncommittedRecordException( | ||
|
|
@@ -148,7 +156,7 @@ public List<Result> scan(Scan originalScan) throws CrudException { | |
| List<String> originalProjections = new ArrayList<>(originalScan.getProjections()); | ||
| Scan scan = (Scan) prepareStorageSelection(originalScan); | ||
| LinkedHashMap<Snapshot.Key, TransactionResult> results = scanInternal(scan); | ||
| snapshot.verifyNoOverlap(scan, results); | ||
| verifyNoOverlap(scan, results); | ||
|
|
||
| TableMetadata metadata = getTableMetadata(scan); | ||
| return results.values().stream() | ||
|
|
@@ -214,7 +222,7 @@ private void processScanResult(Snapshot.Key key, Scan scan, TransactionResult re | |
| // We always update the read set to create before image by using the latest record (result) | ||
| // because another conflicting transaction might have updated the record after this | ||
| // transaction read it first. | ||
| snapshot.putIntoReadSet(key, Optional.of(result)); | ||
| putIntoReadSetInSnapshot(key, Optional.of(result)); | ||
| } | ||
|
|
||
| public TransactionCrudOperable.Scanner getScanner(Scan originalScan) throws CrudException { | ||
|
|
@@ -248,6 +256,20 @@ public void closeScanners() throws CrudException { | |
| } | ||
| } | ||
|
|
||
| private void putIntoReadSetInSnapshot(Snapshot.Key key, Optional<TransactionResult> result) { | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As an optimization, in read-only mode, we don't need to add the result to the read set, since the read set is only used for write operations. |
||
| // In read-only mode, we don't need to put the result into the read set | ||
| if (!readOnly) { | ||
| snapshot.putIntoReadSet(key, result); | ||
| } | ||
| } | ||
|
|
||
| private void verifyNoOverlap(Scan scan, Map<Snapshot.Key, TransactionResult> results) { | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, we don't need to verify the overlap in read-only mode, since there are no write operations. |
||
| // In read-only mode, we don't need to verify the overlap | ||
| if (!readOnly) { | ||
| snapshot.verifyNoOverlap(scan, results); | ||
| } | ||
| } | ||
|
|
||
| public void put(Put put) throws CrudException { | ||
| Snapshot.Key key = new Snapshot.Key(put); | ||
|
|
||
|
|
@@ -483,7 +505,7 @@ public void close() { | |
| snapshot.putIntoScannerSet(scan, results); | ||
| } | ||
|
|
||
| snapshot.verifyNoOverlap(scan, results); | ||
| verifyNoOverlap(scan, results); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -554,7 +576,7 @@ public List<Result> all() throws CrudException { | |
| @Override | ||
| public void close() { | ||
| closed = true; | ||
| snapshot.verifyNoOverlap(scan, results); | ||
| verifyNoOverlap(scan, results); | ||
| } | ||
|
|
||
| @Override | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -58,15 +58,29 @@ public class Snapshot { | |
| private final Isolation isolation; | ||
| private final TransactionTableMetadataManager tableMetadataManager; | ||
| private final ParallelExecutor parallelExecutor; | ||
|
|
||
| // The read set stores information about the records that are read in this transaction. This is | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
| // used as a previous version for write operations. | ||
| private final ConcurrentMap<Key, Optional<TransactionResult>> readSet; | ||
|
|
||
| // The get set stores information about the records retrieved by Get operations in this | ||
| // transaction. This is used for validation and snapshot read. | ||
| private final ConcurrentMap<Get, Optional<TransactionResult>> getSet; | ||
|
|
||
| // The scan set stores information about the records retrieved by Scan operations in this | ||
| // transaction. This is used for validation and snapshot read. | ||
| private final Map<Scan, LinkedHashMap<Key, TransactionResult>> scanSet; | ||
| private final Map<Key, Put> writeSet; | ||
| private final Map<Key, Delete> deleteSet; | ||
|
|
||
| // The scanner set used to store information about scanners that are not fully scanned | ||
| // The scanner set stores information about scanners that are not fully scanned. This is used for | ||
| // validation. | ||
| private final List<ScannerInfo> scannerSet; | ||
|
|
||
| // The write set stores information about writes in this transaction. | ||
| private final Map<Key, Put> writeSet; | ||
|
|
||
| // The delete set stores information about deletes in this transaction. | ||
| private final Map<Key, Delete> deleteSet; | ||
|
|
||
| public Snapshot( | ||
| String id, | ||
| Isolation isolation, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrap the transaction object with
ReadOnlyDistributedTransactionfor read-only transactions.