|
49 | 49 | import static org.apache.ignite.internal.tx.TxStateMetaUnknown.txStateMetaUnknown; |
50 | 50 | import static org.apache.ignite.internal.tx.impl.TxStateResolutionParameters.txStateResolutionParameters; |
51 | 51 | import static org.apache.ignite.internal.util.CollectionUtils.nullOrEmpty; |
| 52 | +import static org.apache.ignite.internal.util.CollectionUtils.view; |
52 | 53 | import static org.apache.ignite.internal.util.CompletableFutures.allOfToList; |
53 | 54 | import static org.apache.ignite.internal.util.CompletableFutures.emptyCollectionCompletedFuture; |
54 | 55 | import static org.apache.ignite.internal.util.CompletableFutures.emptyListCompletedFuture; |
|
208 | 209 | import org.apache.ignite.internal.tx.message.TxMessageGroup; |
209 | 210 | import org.apache.ignite.internal.tx.message.TxStatePrimaryReplicaRequest; |
210 | 211 | import org.apache.ignite.internal.tx.message.WriteIntentSwitchReplicaRequestBase; |
| 212 | +import org.apache.ignite.internal.util.CompletableFutures; |
211 | 213 | import org.apache.ignite.internal.util.Cursor; |
212 | 214 | import org.apache.ignite.internal.util.CursorUtils; |
213 | 215 | import org.apache.ignite.internal.util.IgniteSpinBusyLock; |
214 | 216 | import org.apache.ignite.internal.util.IgniteUtils; |
215 | 217 | import org.apache.ignite.internal.util.Lazy; |
| 218 | +import org.apache.ignite.internal.util.Pair; |
216 | 219 | import org.apache.ignite.internal.util.PendingComparableValuesTracker; |
217 | 220 | import org.apache.ignite.lang.ErrorGroups.Replicator; |
218 | 221 | import org.apache.ignite.lang.ErrorGroups.Transactions; |
@@ -1309,19 +1312,71 @@ private CompletableFuture<Void> continueReadOnlyIndexScan( |
1309 | 1312 | return nullCompletedFuture(); |
1310 | 1313 | } |
1311 | 1314 |
|
1312 | | - IndexRow indexRow = cursor.next(); |
| 1315 | + List<Pair<IndexRow, CompletableFuture<TimedBinaryRow>>> indexRowWithWriteIntentFutures = null; |
| 1316 | + int resultStartIndex = result.size(); |
| 1317 | + |
| 1318 | + while (result.size() < batchSize && cursor.hasNext()) { |
| 1319 | + IndexRow indexRow = cursor.next(); |
| 1320 | + RowId rowId = indexRow.rowId(); |
1313 | 1321 |
|
1314 | | - RowId rowId = indexRow.rowId(); |
| 1322 | + CompletableFuture<@Nullable TimedBinaryRow> resolutionResult = resolvePlainReadResult(rowId, null, readTimestamp); |
1315 | 1323 |
|
1316 | | - return resolvePlainReadResult(rowId, null, readTimestamp).thenComposeAsync(resolvedReadResult -> { |
1317 | | - BinaryRow binaryRow = upgrade(binaryRow(resolvedReadResult), tableVersion); |
| 1324 | + if (resolutionResult.isDone() && !resolutionResult.isCompletedExceptionally()) { |
| 1325 | + BinaryRow binaryRow = upgrade(binaryRow(resolutionResult.join()), tableVersion); |
1318 | 1326 |
|
1319 | | - if (binaryRow != null && indexRowMatches(indexRow, binaryRow, schemaAwareIndexStorage)) { |
1320 | | - result.add(binaryRow); |
| 1327 | + if (binaryRow != null && indexRowMatches(indexRow, binaryRow, schemaAwareIndexStorage)) { |
| 1328 | + result.add(binaryRow); |
| 1329 | + } |
| 1330 | + } else { |
| 1331 | + if (indexRowWithWriteIntentFutures == null) { |
| 1332 | + indexRowWithWriteIntentFutures = new ArrayList<>(); |
| 1333 | + } |
| 1334 | + |
| 1335 | + indexRowWithWriteIntentFutures.add(new Pair<>(indexRow, resolutionResult)); |
| 1336 | + result.add(null); // Placeholder; will be filled or removed after write intent resolution. |
1321 | 1337 | } |
| 1338 | + } |
| 1339 | + |
| 1340 | + if (nullOrEmpty(indexRowWithWriteIntentFutures)) { |
| 1341 | + return nullCompletedFuture(); |
| 1342 | + } |
| 1343 | + |
| 1344 | + List<Pair<IndexRow, CompletableFuture<TimedBinaryRow>>> finalIndexRowWithWriteIntentFutures = indexRowWithWriteIntentFutures; |
| 1345 | + return CompletableFutures.allOf(view(indexRowWithWriteIntentFutures, Pair::getSecond)) |
| 1346 | + .thenComposeAsync(unused -> { |
| 1347 | + int futureIdx = 0; |
| 1348 | + |
| 1349 | + ListIterator<BinaryRow> it = result.listIterator(resultStartIndex); |
1322 | 1350 |
|
1323 | | - return continueReadOnlyIndexScan(schemaAwareIndexStorage, cursor, readTimestamp, batchSize, result, tableVersion); |
1324 | | - }, scanRequestExecutor); |
| 1351 | + while (it.hasNext()) { |
| 1352 | + BinaryRow row = it.next(); |
| 1353 | + |
| 1354 | + if (row == null) { |
| 1355 | + Pair<IndexRow, CompletableFuture<TimedBinaryRow>> indexRowWithWriteIntent |
| 1356 | + = finalIndexRowWithWriteIntentFutures.get(futureIdx); |
| 1357 | + IndexRow indexRow = indexRowWithWriteIntent.getFirst(); |
| 1358 | + TimedBinaryRow resolved = indexRowWithWriteIntent.getSecond().join(); |
| 1359 | + futureIdx++; |
| 1360 | + |
| 1361 | + BinaryRow binaryRow = upgrade(binaryRow(resolved), tableVersion); |
| 1362 | + |
| 1363 | + if (binaryRow != null && indexRowMatches(indexRow, binaryRow, schemaAwareIndexStorage)) { |
| 1364 | + it.set(binaryRow); |
| 1365 | + } else { |
| 1366 | + it.remove(); |
| 1367 | + } |
| 1368 | + } |
| 1369 | + } |
| 1370 | + |
| 1371 | + assert futureIdx == finalIndexRowWithWriteIntentFutures.size() |
| 1372 | + : "Expected " + finalIndexRowWithWriteIntentFutures.size() + " iterations but was " + futureIdx; |
| 1373 | + |
| 1374 | + if (result.size() < batchSize && cursor.hasNext()) { |
| 1375 | + return continueReadOnlyIndexScan(schemaAwareIndexStorage, cursor, readTimestamp, batchSize, result, tableVersion); |
| 1376 | + } |
| 1377 | + |
| 1378 | + return nullCompletedFuture(); |
| 1379 | + }, scanRequestExecutor); |
1325 | 1380 | } |
1326 | 1381 |
|
1327 | 1382 | /** |
|
0 commit comments