55import com .scalar .db .api .Put ;
66import com .scalar .db .api .Result ;
77import com .scalar .db .api .Scan ;
8+ import com .scalar .db .api .TransactionCrudOperable ;
89import com .scalar .db .exception .transaction .TransactionException ;
910import com .scalar .db .exception .transaction .UnknownTransactionStatusException ;
1011import com .scalar .kelpie .config .Config ;
1112import com .scalar .kelpie .exception .ProcessFatalException ;
1213import com .scalar .kelpie .modules .TimeBasedProcessor ;
14+ import java .util .ArrayList ;
15+ import java .util .HashSet ;
1316import java .util .List ;
17+ import java .util .Optional ;
18+ import java .util .Set ;
1419import java .util .concurrent .ThreadLocalRandom ;
1520import java .util .concurrent .atomic .AtomicBoolean ;
21+ import java .util .concurrent .atomic .AtomicInteger ;
1622import javax .json .Json ;
1723import kelpie .scalardb .Common ;
1824
@@ -21,6 +27,7 @@ public class SensorProcessor extends TimeBasedProcessor {
2127 private final int numDevices ;
2228 private final AtomicBoolean isVerification ;
2329 private final int startTimestamp ;
30+ private final AtomicInteger numAttempts = new AtomicInteger ();
2431
2532 public SensorProcessor (Config config ) {
2633 super (config );
@@ -67,13 +74,43 @@ public void close() {
6774
6875 private void updateRevision (DistributedTransaction transaction , int timestamp , int deviceId )
6976 throws TransactionException {
70-
7177 Scan scan = SensorCommon .prepareScan (timestamp );
72- List <Result > results = transaction .scan (scan );
7378
74- boolean hasDuplicatedRevision = SensorCommon .hasDuplicatedRevision (results );
79+ boolean hasDuplicatedRevision ;
80+ List <Result > results ;
81+
82+ // Alternate between scan() and getScanner() based on the attempt count.
83+ boolean scannerUsed = numAttempts .getAndIncrement () % 2 == 0 ;
84+ if (!scannerUsed ) {
85+ // Use scan()
86+ results = transaction .scan (scan );
87+ hasDuplicatedRevision = SensorCommon .hasDuplicatedRevision (results );
88+ } else {
89+ // Use getScanner()
90+ hasDuplicatedRevision = false ;
91+ results = new ArrayList <>();
92+ try (TransactionCrudOperable .Scanner scanner = transaction .getScanner (scan )) {
93+ Set <Integer > tempSet = new HashSet <>();
94+ while (true ) {
95+ Optional <Result > result = scanner .one ();
96+ if (!result .isPresent ()) {
97+ break ;
98+ }
99+
100+ int revision = SensorCommon .getRevisionFromResult (result .get ());
101+ if (!tempSet .add (revision )) {
102+ hasDuplicatedRevision = true ;
103+ break ;
104+ }
105+
106+ results .add (result .get ());
107+ }
108+ }
109+ }
110+
75111 if (hasDuplicatedRevision ) {
76- throw new ProcessFatalException ("A revision is duplicated at " + timestamp );
112+ throw new ProcessFatalException (
113+ "A revision is duplicated. timestamp: " + timestamp + "; scannerUsed: " + scannerUsed );
77114 }
78115
79116 int revision = SensorCommon .getMaxRevision (results ) + 1 ;
0 commit comments