@@ -49,7 +49,8 @@ public class Snapshot {
4949 private final TransactionTableMetadataManager tableMetadataManager ;
5050 private final ParallelExecutor parallelExecutor ;
5151 private final Map <Key , Optional <TransactionResult >> readSet ;
52- private final Map <Scan , List <Key >> scanSet ;
52+ private final Map <Get , Optional <TransactionResult >> getSet ;
53+ private final Map <Scan , Map <Key , TransactionResult >> scanSet ;
5354 private final Map <Key , Put > writeSet ;
5455 private final Map <Key , Delete > deleteSet ;
5556
@@ -65,6 +66,7 @@ public Snapshot(
6566 this .tableMetadataManager = tableMetadataManager ;
6667 this .parallelExecutor = parallelExecutor ;
6768 readSet = new HashMap <>();
69+ getSet = new HashMap <>();
6870 scanSet = new HashMap <>();
6971 writeSet = new HashMap <>();
7072 deleteSet = new HashMap <>();
@@ -78,7 +80,8 @@ public Snapshot(
7880 TransactionTableMetadataManager tableMetadataManager ,
7981 ParallelExecutor parallelExecutor ,
8082 Map <Key , Optional <TransactionResult >> readSet ,
81- Map <Scan , List <Key >> scanSet ,
83+ Map <Get , Optional <TransactionResult >> getSet ,
84+ Map <Scan , Map <Key , TransactionResult >> scanSet ,
8285 Map <Key , Put > writeSet ,
8386 Map <Key , Delete > deleteSet ) {
8487 this .id = id ;
@@ -87,6 +90,7 @@ public Snapshot(
8790 this .tableMetadataManager = tableMetadataManager ;
8891 this .parallelExecutor = parallelExecutor ;
8992 this .readSet = readSet ;
93+ this .getSet = getSet ;
9094 this .scanSet = scanSet ;
9195 this .writeSet = writeSet ;
9296 this .deleteSet = deleteSet ;
@@ -107,8 +111,12 @@ public void put(Key key, Optional<TransactionResult> result) {
107111 readSet .put (key , result );
108112 }
109113
110- public void put (Scan scan , List <Key > keys ) {
111- scanSet .put (scan , keys );
114+ public void put (Get get , Optional <TransactionResult > result ) {
115+ getSet .put (get , result );
116+ }
117+
118+ public void put (Scan scan , Map <Key , TransactionResult > results ) {
119+ scanSet .put (scan , results );
112120 }
113121
114122 public void put (Key key , Put put ) {
@@ -137,21 +145,18 @@ public Optional<TransactionResult> getFromReadSet(Key key) {
137145 return readSet .containsKey (key ) ? readSet .get (key ) : Optional .empty ();
138146 }
139147
140- public Optional <TransactionResult > get (Key key ) throws CrudException {
148+ public Optional <TransactionResult > mergeResult (Key key , Optional <TransactionResult > result )
149+ throws CrudException {
141150 if (deleteSet .containsKey (key )) {
142151 return Optional .empty ();
143- } else if (readSet .containsKey (key )) {
144- if (writeSet .containsKey (key )) {
145- // merge the result in the read set and the put in the write set
146- return Optional .of (
147- new TransactionResult (
148- new MergedResult (readSet .get (key ), writeSet .get (key ), getTableMetadata (key ))));
149- } else {
150- return readSet .get (key );
151- }
152+ } else if (writeSet .containsKey (key )) {
153+ // merge the result in the read set and the put in the write set
154+ return Optional .of (
155+ new TransactionResult (
156+ new MergedResult (result , writeSet .get (key ), getTableMetadata (key ))));
157+ } else {
158+ return result ;
152159 }
153- throw new IllegalArgumentException (
154- "getting data neither in the read set nor the delete set is not allowed" );
155160 }
156161
157162 private TableMetadata getTableMetadata (Key key ) throws CrudException {
@@ -185,7 +190,17 @@ private TableMetadata getTableMetadata(Scan scan) throws ExecutionException {
185190 }
186191 }
187192
188- public Optional <List <Key >> get (Scan scan ) {
193+ public boolean containsKeyInGetSet (Get get ) {
194+ return getSet .containsKey (get );
195+ }
196+
197+ public Optional <TransactionResult > get (Get get ) {
198+ // We expect this method is called after putting the result of the get operation in the get set.
199+ assert getSet .containsKey (get );
200+ return getSet .get (get );
201+ }
202+
203+ public Optional <Map <Key , TransactionResult >> get (Scan scan ) {
189204 if (scanSet .containsKey (scan )) {
190205 return Optional .ofNullable (scanSet .get (scan ));
191206 }
@@ -222,6 +237,10 @@ private boolean isWriteSetOverlappedWith(Scan scan) {
222237 }
223238
224239 for (Map .Entry <Key , Put > entry : writeSet .entrySet ()) {
240+ if (scanSet .get (scan ).containsKey (entry .getKey ())) {
241+ return true ;
242+ }
243+
225244 Put put = entry .getValue ();
226245
227246 if (!put .forNamespace ().equals (scan .forNamespace ())
@@ -278,7 +297,7 @@ private boolean isWriteSetOverlappedWith(Scan scan) {
278297
279298 private boolean isWriteSetOverlappedWith (ScanWithIndex scan ) {
280299 for (Map .Entry <Key , Put > entry : writeSet .entrySet ()) {
281- if (scanSet .get (scan ).contains (entry .getKey ())) {
300+ if (scanSet .get (scan ).containsKey (entry .getKey ())) {
282301 return true ;
283302 }
284303
@@ -315,7 +334,7 @@ private boolean isWriteSetOverlappedWith(ScanAll scan) {
315334 // yet. Thus, we need to evaluate if the scan condition potentially matches put operations.
316335
317336 // Check for cases 1 and 2
318- if (scanSet .get (scan ).contains (entry .getKey ())) {
337+ if (scanSet .get (scan ).containsKey (entry .getKey ())) {
319338 return true ;
320339 }
321340
@@ -433,14 +452,14 @@ void toSerializableWithExtraRead(DistributedStorage storage)
433452 List <ParallelExecutorTask > tasks = new ArrayList <>();
434453
435454 // Read set by scan is re-validated to check if there is no anti-dependency
436- for (Map .Entry <Scan , List <Key >> entry : scanSet .entrySet ()) {
455+ for (Map .Entry <Scan , Map <Key , TransactionResult >> entry : scanSet .entrySet ()) {
437456 tasks .add (
438457 () -> {
439458 Map <Key , TransactionResult > currentReadMap = new HashMap <>();
440459 Set <Key > validatedReadSet = new HashSet <>();
441460 Scanner scanner = null ;
461+ Scan scan = entry .getKey ();
442462 try {
443- Scan scan = entry .getKey ();
444463 // only get tx_id and tx_version columns because we use only them to compare
445464 scan .clearProjections ();
446465 scan .withProjection (Attribute .ID ).withProjection (Attribute .VERSION );
@@ -464,13 +483,15 @@ void toSerializableWithExtraRead(DistributedStorage storage)
464483 }
465484 }
466485
467- for (Key key : entry .getValue ()) {
486+ for (Map .Entry <Key , TransactionResult > e : entry .getValue ().entrySet ()) {
487+ Key key = e .getKey ();
488+ TransactionResult result = e .getValue ();
468489 if (writeSet .containsKey (key ) || deleteSet .containsKey (key )) {
469490 continue ;
470491 }
471492 // Check if read records are not changed
472493 TransactionResult latestResult = currentReadMap .get (key );
473- if (isChanged (Optional .ofNullable (latestResult ), readSet . get ( key ))) {
494+ if (isChanged (Optional .ofNullable (latestResult ), Optional . of ( result ))) {
474495 throwExceptionDueToAntiDependency ();
475496 }
476497 validatedReadSet .add (key );
@@ -483,35 +504,23 @@ void toSerializableWithExtraRead(DistributedStorage storage)
483504 });
484505 }
485506
486- // Calculate read set validated by scan
487- Set <Key > validatedReadSetByScan = new HashSet <>();
488- for (List <Key > values : scanSet .values ()) {
489- validatedReadSetByScan .addAll (values );
490- }
491-
492507 // Read set by get is re-validated to check if there is no anti-dependency
493- for (Map .Entry <Key , Optional <TransactionResult >> entry : readSet .entrySet ()) {
494- Key key = entry .getKey ();
495- if (writeSet .containsKey (key )
496- || deleteSet .containsKey (key )
497- || validatedReadSetByScan .contains (key )) {
508+ for (Map .Entry <Get , Optional <TransactionResult >> entry : getSet .entrySet ()) {
509+ Get get = entry .getKey ();
510+ Key key = new Key (get );
511+ if (writeSet .containsKey (key ) || deleteSet .containsKey (key )) {
498512 continue ;
499513 }
500514
501515 tasks .add (
502516 () -> {
517+ Optional <TransactionResult > originalResult = getSet .get (get );
503518 // only get tx_id and tx_version columns because we use only them to compare
504- Get get =
505- new Get (key .getPartitionKey (), key .getClusteringKey ().orElse (null ))
506- .withProjection (Attribute .ID )
507- .withProjection (Attribute .VERSION )
508- .withConsistency (Consistency .LINEARIZABLE )
509- .forNamespace (key .getNamespace ())
510- .forTable (key .getTable ());
511-
519+ get .clearProjections ();
520+ get .withProjection (Attribute .ID ).withProjection (Attribute .VERSION );
512521 Optional <TransactionResult > latestResult = storage .get (get ).map (TransactionResult ::new );
513522 // Check if a read record is not changed
514- if (isChanged (latestResult , entry . getValue () )) {
523+ if (isChanged (latestResult , originalResult )) {
515524 throwExceptionDueToAntiDependency ();
516525 }
517526 });
0 commit comments