private void testLockMigration(int nodeThatPuts) throws Exception { Map<Object, DummyTransaction> key2Tx = new HashMap<Object, DummyTransaction>(); for (int i = 0; i < NUM_KEYS; i++) { Object key = getKeyForCache(0); if (key2Tx.containsKey(key)) continue; dummyTm(nodeThatPuts).begin(); cache(nodeThatPuts).put(key, key); DummyTransaction tx = dummyTm(nodeThatPuts).getTransaction(); tx.runPrepare(); dummyTm(nodeThatPuts).suspend(); key2Tx.put(key, tx); assertLocked(0, key); } log.trace("Lock transfer happens here"); addClusterEnabledCacheManager(dccc); waitForClusterToForm(); Object migratedKey = null; ConsistentHash ch = advancedCache(2).getDistributionManager().getConsistentHash(); for (Object key : key2Tx.keySet()) { if (ch.locatePrimaryOwner(key).equals(address(2))) { migratedKey = key; break; } } if (migratedKey == null) { log.trace("No key migrated to new owner."); } else { log.trace("migratedKey = " + migratedKey); dummyTm(2).begin(); cache(2).put(migratedKey, "someValue"); try { dummyTm(2).commit(); fail("RollbackException should have been thrown here."); } catch (RollbackException e) { // expected } } log.trace("About to commit existing transactions."); log.trace("Committing the tx to the new node."); for (Transaction tx : key2Tx.values()) { tm(nodeThatPuts).resume(tx); dummyTm(nodeThatPuts).getTransaction().runCommitTx(); } for (Object key : key2Tx.keySet()) { Object value = getValue( key); // make sure that data from the container, just to make sure all replicas are // correctly set assertEquals(key, value); } }
public void testPrimaryOwnerCrash() throws Exception { // cache 0 is the originator and backup, cache 1 is the primary owner StateSequencer ss = new StateSequencer(); ss.logicalThread("main", "block_prepare", "crash_primary", "resume_prepare"); tm(0).begin(); cache(0).put("k", "v1"); DummyTransaction tx1 = (DummyTransaction) tm(0).suspend(); tx1.runPrepare(); advanceOnInboundRpc(ss, cache(1), matchCommand(PrepareCommand.class).build()) .before("block_prepare", "resume_prepare"); Future<DummyTransaction> tx2Future = fork( () -> { tm(0).begin(); cache(0).put("k", "v2"); DummyTransaction tx2 = (DummyTransaction) tm(0).suspend(); tx2.runPrepare(); return tx2; }); ss.enter("crash_primary"); killMember(1); ss.exit("crash_primary"); DummyTransaction tx2 = tx2Future.get(10, SECONDS); try { tx2.runCommit(false); fail("tx2 should not be able to commit"); } catch (Exception e) { log.tracef(e, "Received expected exception"); } tx1.runCommit(false); }
protected void doTest(final SplitMode splitMode, boolean txFail, boolean discard) throws Exception { waitForClusterToForm(OPTIMISTIC_TX_CACHE_NAME); final KeyInfo keyInfo = createKeys(OPTIMISTIC_TX_CACHE_NAME); final Cache<Object, String> originator = cache(0, OPTIMISTIC_TX_CACHE_NAME); final FilterCollection filterCollection = createFilters(OPTIMISTIC_TX_CACHE_NAME, discard, getCommandClass(), splitMode); Future<Void> put = fork( () -> { final DummyTransactionManager transactionManager = (DummyTransactionManager) originator.getAdvancedCache().getTransactionManager(); transactionManager.begin(); keyInfo.putFinalValue(originator); final DummyTransaction transaction = transactionManager.getTransaction(); transaction.runPrepare(); transaction.runCommit(forceRollback()); transaction.throwRollbackExceptionIfAny(); return null; }); filterCollection.await(30, TimeUnit.SECONDS); splitMode.split(this); filterCollection.unblock(); try { put.get(); assertFalse(txFail); } catch (ExecutionException e) { assertTrue(txFail); } checkLocksDuringPartition(splitMode, keyInfo, discard); mergeCluster(OPTIMISTIC_TX_CACHE_NAME); finalAsserts(OPTIMISTIC_TX_CACHE_NAME, keyInfo, txFail ? INITIAL_VALUE : FINAL_VALUE); }