Skip to content

Commit cfb6e1f

Browse files
authored
IGNITE-27678 Same partitions on different nodes can hold different updates if writeThrough is enabled (#12925)
1 parent ef52e10 commit cfb6e1f

20 files changed

Lines changed: 570 additions & 31 deletions

modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxOnePhaseCommitAckRequest;
102102
import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxPrepareRequest;
103103
import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxPrepareResponse;
104+
import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxSalvageMessage;
104105
import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtUnlockRequest;
105106
import org.apache.ignite.internal.processors.cache.distributed.dht.PartitionUpdateCountersMessage;
106107
import org.apache.ignite.internal.processors.cache.distributed.dht.TransactionAttributesAwareRequest;
@@ -585,6 +586,7 @@ public CoreMessagesProvider(Marshaller dfltMarsh, Marshaller schemaAwareMarsh, C
585586
withNoSchema(StatisticsRequest.class);
586587
withNoSchema(StatisticsResponse.class);
587588
withNoSchema(CacheContinuousQueryBatchAck.class);
589+
withNoSchema(GridDhtTxSalvageMessage.class);
588590
withSchema(CacheContinuousQueryEntry.class);
589591
withNoSchema(QueryInlineSizesDataBagItem.class);
590592
withSchema(QueryProposalsDataBagItem.class);

modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishFuture.java

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ private boolean finish(boolean commit,
473473
if (isNull(cctx.discovery().getAlive(n.id()))) {
474474
log.error("Unable to send message (node left topology): " + n);
475475

476-
fut.onNodeLeft();
476+
fut.onNodeLeft(n.id());
477477
}
478478
else {
479479
cctx.tm().sendTransactionMessage(n, req, tx, tx.ioPolicy());
@@ -493,7 +493,7 @@ private boolean finish(boolean commit,
493493
catch (IgniteCheckedException e) {
494494
// Fail the whole thing.
495495
if (e instanceof ClusterTopologyCheckedException)
496-
fut.onNodeLeft();
496+
fut.onNodeLeft(n.id());
497497
else {
498498
if (msgLog.isDebugEnabled()) {
499499
msgLog.debug("DHT finish fut, failed to send request dht [txId=" + tx.nearXidVersion() +
@@ -687,6 +687,40 @@ void onResult(Throwable e) {
687687
onDone(e);
688688
}
689689

690+
/** */
691+
private void onNodeLeft(UUID nodeId) {
692+
// Cause in common case #onNodeLeft() completes with no error it`s necessary to send salvage message.
693+
if (tx.storeWriteThrough()) {
694+
Map<UUID, Collection<UUID>> txNodes = tx.transactionNodes();
695+
696+
if (txNodes != null) {
697+
Collection<UUID> backups = txNodes.get(nodeId);
698+
699+
if (!F.isEmpty(backups)) {
700+
GridDhtTxSalvageMessage salvageReq = null;
701+
702+
for (UUID backupId : backups) {
703+
ClusterNode backup = cctx.discovery().node(backupId);
704+
705+
if (backup != null && !backup.isLocal()) {
706+
if (salvageReq == null)
707+
salvageReq = new GridDhtTxSalvageMessage(tx.nearXidVersion());
708+
709+
try {
710+
cctx.io().send(backup, salvageReq, tx.ioPolicy());
711+
}
712+
catch (IgniteCheckedException e) {
713+
U.error(log, "Failed to send " + GridDhtTxSalvageMessage.class.getName() + " message.", e);
714+
}
715+
}
716+
}
717+
}
718+
}
719+
}
720+
721+
onNodeLeft();
722+
}
723+
690724
/**
691725
*/
692726
void onNodeLeft() {

modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocal.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,8 +460,12 @@ else if (!lockFut.isDone()) {
460460
logTxFinishErrorSafe(log, commit, e);
461461

462462
// Treat heuristic exception as critical.
463-
if (X.hasCause(e, IgniteTxHeuristicCheckedException.class))
463+
if (X.hasCause(e, IgniteTxHeuristicCheckedException.class)) {
464+
if (storeWriteThrough() && local())
465+
salvageTx();
466+
464467
cctx.kernalContext().failure().process(new FailureContext(FailureType.CRITICAL_ERROR, e));
468+
}
465469

466470
err = e;
467471
}

modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxRemote.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717

1818
package org.apache.ignite.internal.processors.cache.distributed.dht;
1919

20-
import java.util.ArrayList;
2120
import java.util.Collection;
2221
import java.util.Collections;
22+
import java.util.List;
2323
import java.util.Map;
2424
import java.util.UUID;
2525
import javax.cache.processor.EntryProcessor;
@@ -226,12 +226,7 @@ public GridDhtTxRemote(
226226

227227
/** {@inheritDoc} */
228228
@Override public Collection<UUID> masterNodeIds() {
229-
Collection<UUID> res = new ArrayList<>(2);
230-
231-
res.add(nearNodeId);
232-
res.add(nodeId);
233-
234-
return res;
229+
return List.of(nearNodeId, nodeId);
235230
}
236231

237232
/** {@inheritDoc} */
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.ignite.internal.processors.cache.distributed.dht;
19+
20+
import org.apache.ignite.internal.Order;
21+
import org.apache.ignite.internal.processors.cache.GridCacheMessage;
22+
import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
23+
24+
/** Salvage tx. */
25+
public class GridDhtTxSalvageMessage extends GridCacheMessage {
26+
/** */
27+
@Order(0)
28+
GridCacheVersion ver;
29+
30+
/** Empty constructor. */
31+
public GridDhtTxSalvageMessage() {
32+
// No-op.
33+
}
34+
35+
/**
36+
* @param ver Global transaction identifier within cluster, assigned by transaction coordinator.
37+
*/
38+
public GridDhtTxSalvageMessage(GridCacheVersion ver) {
39+
this.ver = ver;
40+
}
41+
42+
/** Tx version. */
43+
public GridCacheVersion version() {
44+
return ver;
45+
}
46+
47+
/** {@inheritDoc} */
48+
@Override public boolean addDeploymentInfo() {
49+
return addDepInfo;
50+
}
51+
}

modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte
270270
private final Map<ClusterNode, GridDhtPartitionsFullMessage> fullMsgs = new ConcurrentHashMap<>();
271271

272272
/** */
273+
@SuppressWarnings("unused")
273274
@GridToStringInclude
274275
private volatile IgniteInternalFuture<?> partReleaseFut;
275276

modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtLocalPartition.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1194,7 +1194,9 @@ public void clearDeferredDeletes() {
11941194
while (true) {
11951195
long state = this.state.get();
11961196

1197-
assert getPartState(state) != EVICTED;
1197+
GridDhtPartitionState partState = getPartState(state);
1198+
1199+
assert partState != EVICTED : partState;
11981200

11991201
if (this.state.compareAndSet(state, setSize(state, getSize(state) - 1)))
12001202
return;

modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxFinishFuture.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.apache.ignite.internal.processors.cache.distributed.GridDistributedTxMapping;
4141
import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxFinishRequest;
4242
import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxFinishResponse;
43+
import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxSalvageMessage;
4344
import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx;
4445
import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
4546
import org.apache.ignite.internal.processors.tracing.MTC;
@@ -983,6 +984,7 @@ ClusterNode primary() {
983984
});
984985

985986
GridDhtTxFinishRequest req = checkCommittedRequest(mini.futureId(), true);
987+
GridDhtTxSalvageMessage salvageReq = null;
986988

987989
for (UUID backupId : backups) {
988990
ClusterNode backup = cctx.discovery().node(backupId);
@@ -996,6 +998,13 @@ ClusterNode primary() {
996998
else {
997999
try {
9981000
cctx.io().send(backup, req, tx.ioPolicy());
1001+
1002+
if (tx.storeWriteThrough()) {
1003+
if (salvageReq == null)
1004+
salvageReq = new GridDhtTxSalvageMessage(tx.xidVersion());
1005+
1006+
cctx.io().send(backup, salvageReq, tx.ioPolicy());
1007+
}
9991008
}
10001009
catch (ClusterTopologyCheckedException ignored) {
10011010
mini.onNodeLeft(backupId, discoThread);

modules/core/src/main/java/org/apache/ignite/internal/processors/cache/store/GridCacheStoreManagerAdapter.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,11 @@ private void notifyCacheStoreSessionListeners(SessionData ses, @Nullable StoreOp
964964
lsnr.onSessionStart(locSes);
965965
}
966966
}
967+
catch (RuntimeException e) {
968+
U.error(log, "Exception raised during the notification of cache store session listeners: ", e);
969+
970+
throw e;
971+
}
967972
catch (Exception e) {
968973
throw new IgniteCheckedException("Failed to start store session: " + e, e);
969974
}
@@ -984,6 +989,14 @@ private void sessionEnd0(@Nullable IgniteInternalTx tx, boolean threwEx) throws
984989
store.sessionEnd(!threwEx);
985990
}
986991
}
992+
catch (RuntimeException e) {
993+
U.error(log, "Exception raised during the notification of cache store session listeners: ", e);
994+
995+
if (!threwEx)
996+
throw U.cast(e);
997+
else
998+
throw e;
999+
}
9871000
catch (Exception e) {
9881001
if (!threwEx)
9891002
throw U.cast(e);

modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxAdapter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,7 @@ protected void uncommit() {
628628
/**
629629
* @return Finalization status.
630630
*/
631-
@Override @Nullable public FinalizationStatus finalizationStatus() {
631+
@Override public FinalizationStatus finalizationStatus() {
632632
return finalizing;
633633
}
634634

0 commit comments

Comments
 (0)