@Test public void testCannotCommit1PcUnknownXid() throws Exception { EhcacheXAResource<Long, String> xaResource = new EhcacheXAResource<>(underlyingStore, journal, xaTransactionContextFactory); try { xaResource.commit(new TestXid(0, 0), true); fail("expected XAException"); } catch (XAException xae) { assertThat(xae.errorCode, is(XAException.XAER_NOTA)); } }
xaResource = new EhcacheXAResource<>(underlyingStore, journal, transactionContextFactory); transactionManagerWrapper.registerXAResource(uniqueXAResourceId, xaResource); transactionManagerWrapper.getTransactionManager().getTransaction().enlistResource(xaResource); XATransactionContext<K, V> currentContext = xaResource.getCurrentContext(); if (currentContext.hasTimedOut()) { throw new XACacheException("Current XA transaction has timed out");
@Override public Xid[] recover(int flags) throws XAException { if (flags != XAResource.TMNOFLAGS && flags != XAResource.TMSTARTRSCAN && flags != XAResource.TMENDRSCAN && flags != (XAResource.TMSTARTRSCAN | XAResource.TMENDRSCAN)) { throw new EhcacheXAException("Recover flags not supported : " + xaResourceFlagsToString(flags), XAException.XAER_INVAL); } if ((flags & XAResource.TMSTARTRSCAN) == XAResource.TMSTARTRSCAN) { List<Xid> xids = new ArrayList<>(); Set<TransactionId> transactionIds = journal.recover().keySet(); for (TransactionId transactionId : transactionIds) { // filter-out in-flight tx if (!transactionContextFactory.contains(transactionId)) { xids.add(transactionId.getSerializableXid()); } } return xids.toArray(new Xid[xids.size()]); } return new Xid[0]; }
@Test public void testEndWithoutStartFails() throws Exception { EhcacheXAResource<Long, String> xaResource = new EhcacheXAResource<>(underlyingStore, journal, xaTransactionContextFactory); try { xaResource.end(new TestXid(0, 0), XAResource.TMSUCCESS); fail("expected XAException"); } catch (XAException xae) { assertThat(xae.errorCode, is(XAException.XAER_PROTO)); } }
@Test public void testJoinWorks() throws Exception { EhcacheXAResource<Long, String> xaResource = new EhcacheXAResource<>(underlyingStore, journal, xaTransactionContextFactory); when(xaTransactionContextFactory.createTransactionContext(eq(new TransactionId(new TestXid(0, 0))), refEq(underlyingStore), refEq(journal), anyInt())).thenReturn(xaTransactionContext); xaResource.start(new TestXid(0, 0), XAResource.TMNOFLAGS); when(xaTransactionContextFactory.get(eq(new TransactionId(new TestXid(0, 0))))).thenReturn(xaTransactionContext); xaResource.end(new TestXid(0, 0), XAResource.TMSUCCESS); xaResource.start(new TestXid(0, 0), XAResource.TMJOIN); xaResource.end(new TestXid(0, 0), XAResource.TMSUCCESS); }
@Test public void testCannotPrepareUnknownXid() throws Exception { EhcacheXAResource<Long, String> xaResource = new EhcacheXAResource<>(underlyingStore, journal, xaTransactionContextFactory); try { xaResource.prepare(new TestXid(0, 0)); fail("expected XAException"); } catch (XAException xae) { assertThat(xae.errorCode, is(XAException.XAER_NOTA)); } }
@Test public void testRecoveryCommit() throws Exception { EhcacheXAResource<Long, String> xaResource = new EhcacheXAResource<>(underlyingStore, journal, xaTransactionContextFactory); when(journal.recover()).thenReturn(Collections.singletonMap(new TransactionId(new TestXid(0, 0)), (Collection<Long>) Arrays.asList(1L, 2L, 3L))); when(journal.getInDoubtKeys(eq(new TransactionId(new TestXid(0, 0))))).thenReturn(Arrays.asList(1L, 2L, 3L)); when(journal.isInDoubt(eq(new TransactionId(new TestXid(0, 0))))).thenReturn(true); Xid[] recoveredXids = xaResource.recover(XAResource.TMSTARTRSCAN | XAResource.TMENDRSCAN); assertThat(recoveredXids.length, is(1)); xaResource.commit(recoveredXids[0], false); verify(xaTransactionContextFactory, times(0)).destroy(eq(new TransactionId(new TestXid(0, 0)))); verify(underlyingStore, times(1)).get(eq(1L)); verify(underlyingStore, times(1)).get(eq(2L)); verify(underlyingStore, times(1)).get(eq(3L)); }
@Test public void testForgetUnknownXid() throws Exception { EhcacheXAResource<Long, String> xaResource = new EhcacheXAResource<>(underlyingStore, journal, xaTransactionContextFactory); when(journal.isInDoubt(eq(new TransactionId(new TestXid(0, 0))))).thenReturn(false); try { xaResource.forget(new TestXid(0, 0)); fail("expected XAException"); } catch (XAException xae) { assertThat(xae.errorCode, is(XAException.XAER_NOTA)); } }
@Test public void testCannotRollbackUnknownXidInFlight() throws Exception { EhcacheXAResource<Long, String> xaResource = new EhcacheXAResource<>(underlyingStore, journal, xaTransactionContextFactory); when(xaTransactionContextFactory.get(eq(new TransactionId(new TestXid(0, 0))))).thenReturn(xaTransactionContext); doThrow(IllegalStateException.class).when(xaTransactionContext).rollback(eq(false)); try { xaResource.rollback(new TestXid(0, 0)); fail("expected XAException"); } catch (XAException xae) { assertThat(xae.errorCode, is(XAException.XAER_NOTA)); } }
@Test public void testRecoveryRollback() throws Exception { EhcacheXAResource<Long, String> xaResource = new EhcacheXAResource<>(underlyingStore, journal, xaTransactionContextFactory); when(journal.isInDoubt(eq(new TransactionId(new TestXid(0, 0))))).thenReturn(true); when(journal.recover()).thenReturn(Collections.singletonMap(new TransactionId(new TestXid(0, 0)), (Collection<Long>) Arrays.asList(1L, 2L, 3L))); when(journal.getInDoubtKeys(eq(new TransactionId(new TestXid(0, 0))))).thenReturn(Arrays.asList(1L, 2L, 3L)); Xid[] recoveredXids = xaResource.recover(XAResource.TMSTARTRSCAN | XAResource.TMENDRSCAN); assertThat(recoveredXids.length, is(1)); xaResource.rollback(recoveredXids[0]); verify(xaTransactionContextFactory, times(0)).destroy(eq(new TransactionId(new TestXid(0, 0)))); verify(underlyingStore, times(1)).get(eq(1L)); verify(underlyingStore, times(1)).get(eq(2L)); verify(underlyingStore, times(1)).get(eq(3L)); }
@Test public void testCannotRollbackNonEndedXid() throws Exception { EhcacheXAResource<Long, String> xaResource = new EhcacheXAResource<>(underlyingStore, journal, xaTransactionContextFactory); when(xaTransactionContextFactory.createTransactionContext(eq(new TransactionId(new TestXid(0, 0))), refEq(underlyingStore), refEq(journal), anyInt())).thenReturn(xaTransactionContext); xaResource.start(new TestXid(0, 0), XAResource.TMNOFLAGS); try { xaResource.rollback(new TestXid(0, 0)); fail("expected XAException"); } catch (XAException xae) { assertThat(xae.errorCode, is(XAException.XAER_PROTO)); } }
@Test public void testCannotPrepareNonEndedXid() throws Exception { EhcacheXAResource<Long, String> xaResource = new EhcacheXAResource<>(underlyingStore, journal, xaTransactionContextFactory); when(xaTransactionContextFactory.createTransactionContext(eq(new TransactionId(new TestXid(0, 0))), refEq(underlyingStore), refEq(journal), anyInt())).thenReturn(xaTransactionContext); xaResource.start(new TestXid(0, 0), XAResource.TMNOFLAGS); try { xaResource.prepare(new TestXid(0, 0)); fail("expected XAException"); } catch (XAException xae) { assertThat(xae.errorCode, is(XAException.XAER_PROTO)); } }
@Test public void testCannotCommit1PcNonEndedXid() throws Exception { EhcacheXAResource<Long, String> xaResource = new EhcacheXAResource<>(underlyingStore, journal, xaTransactionContextFactory); when(xaTransactionContextFactory.createTransactionContext(eq(new TransactionId(new TestXid(0, 0))), refEq(underlyingStore), refEq(journal), anyInt())).thenReturn(xaTransactionContext); xaResource.start(new TestXid(0, 0), XAResource.TMNOFLAGS); try { xaResource.commit(new TestXid(0, 0), true); fail("expected XAException"); } catch (XAException xae) { assertThat(xae.errorCode, is(XAException.XAER_PROTO)); } }
@Test public void testRecoverIgnoresInFlightTx() throws Exception { EhcacheXAResource<Long, String> xaResource = new EhcacheXAResource<>(underlyingStore, journal, xaTransactionContextFactory); when(journal.recover()).thenReturn(Collections.singletonMap(new TransactionId(new TestXid(0, 0)), (Collection<Long>) Arrays.asList(1L, 2L, 3L))); when(xaTransactionContextFactory.contains(eq(new TransactionId(new TestXid(0, 0))))).thenReturn(true); Xid[] recovered = xaResource.recover(XAResource.TMSTARTRSCAN | XAResource.TMENDRSCAN); assertThat(recovered.length, is(0)); }
@Test public void testTimeoutStart() throws Exception { EhcacheXAResource<Long, String> xaResource = new EhcacheXAResource<>(underlyingStore, journal, xaTransactionContextFactory); when(xaTransactionContextFactory.createTransactionContext(eq(new TransactionId(new TestXid(0, 0))), refEq(underlyingStore), refEq(journal), anyInt())).thenReturn(xaTransactionContext); when(xaTransactionContext.hasTimedOut()).thenReturn(true); try { xaResource.start(new TestXid(0, 0), XAResource.TMNOFLAGS); fail("expected XAException"); } catch (XAException xae) { assertThat(xae.errorCode, is(XAException.XA_RBTIMEOUT)); } verify(xaTransactionContextFactory, times(1)).destroy(eq(new TransactionId(new TestXid(0, 0)))); }
public XAStore(Class<K> keyType, Class<V> valueType, Store<K, SoftLock<V>> underlyingStore, TransactionManagerWrapper transactionManagerWrapper, TimeSource timeSource, Journal<K> journal, String uniqueXAResourceId) { super(keyType, valueType, true); this.underlyingStore = underlyingStore; this.transactionManagerWrapper = transactionManagerWrapper; this.timeSource = timeSource; this.journal = journal; this.uniqueXAResourceId = uniqueXAResourceId; this.transactionContextFactory = new XATransactionContextFactory<>(timeSource); this.recoveryXaResource = new EhcacheXAResource<>(underlyingStore, journal, transactionContextFactory); this.eventSourceWrapper = new StoreEventSourceWrapper<>(underlyingStore.getStoreEventSource()); ContextManager.associate(underlyingStore).withParent(this); }
@Test public void testStartEndWorks() throws Exception { EhcacheXAResource<Long, String> xaResource = new EhcacheXAResource<>(underlyingStore, journal, xaTransactionContextFactory); when(xaTransactionContextFactory.createTransactionContext(eq(new TransactionId(new TestXid(0, 0))), refEq(underlyingStore), refEq(journal), anyInt())).thenReturn(xaTransactionContext); xaResource.start(new TestXid(0, 0), XAResource.TMNOFLAGS); when(xaTransactionContextFactory.get(eq(new TransactionId(new TestXid(0, 0))))).thenReturn(xaTransactionContext); xaResource.end(new TestXid(0, 0), XAResource.TMSUCCESS); when(xaTransactionContextFactory.createTransactionContext(eq(new TransactionId(new TestXid(0, 1))), refEq(underlyingStore), refEq(journal), anyInt())).thenReturn(xaTransactionContext); xaResource.start(new TestXid(0, 1), XAResource.TMNOFLAGS); when(xaTransactionContextFactory.get(eq(new TransactionId(new TestXid(0, 1))))).thenReturn(xaTransactionContext); xaResource.end(new TestXid(0, 1), XAResource.TMSUCCESS); }
@Test public void testPrepareOk() throws Exception { EhcacheXAResource<Long, String> xaResource = new EhcacheXAResource<>(underlyingStore, journal, xaTransactionContextFactory); when(xaTransactionContextFactory.get(eq(new TransactionId(new TestXid(0, 0))))).thenReturn(xaTransactionContext); when(xaTransactionContext.prepare()).thenReturn(1); int prepareRc = xaResource.prepare(new TestXid(0, 0)); assertThat(prepareRc, is(XAResource.XA_OK)); verify(xaTransactionContextFactory, times(0)).destroy(eq(new TransactionId(new TestXid(0, 0)))); }
@Test public void testRecoveryCommitOnePhaseFails() throws Exception { EhcacheXAResource<Long, String> xaResource = new EhcacheXAResource<>(underlyingStore, journal, xaTransactionContextFactory); when(journal.recover()).thenReturn(Collections.singletonMap(new TransactionId(new TestXid(0, 0)), (Collection<Long>) Arrays.asList(1L, 2L, 3L))); when(journal.getInDoubtKeys(eq(new TransactionId(new TestXid(0, 0))))).thenReturn(Arrays.asList(1L, 2L, 3L)); Xid[] recoveredXids = xaResource.recover(XAResource.TMSTARTRSCAN | XAResource.TMENDRSCAN); assertThat(recoveredXids.length, is(1)); try { xaResource.commit(recoveredXids[0], true); fail("expected XAException"); } catch (XAException xae) { assertThat(xae.errorCode, is(XAException.XAER_NOTA)); } verify(xaTransactionContextFactory, times(0)).destroy(eq(new TransactionId(new TestXid(0, 0)))); }
@Test public void testForgetInDoubtXid() throws Exception { EhcacheXAResource<Long, String> xaResource = new EhcacheXAResource<>(underlyingStore, journal, xaTransactionContextFactory); when(journal.isInDoubt(eq(new TransactionId(new TestXid(0, 0))))).thenReturn(true); try { xaResource.forget(new TestXid(0, 0)); fail("expected XAException"); } catch (XAException xae) { assertThat(xae.errorCode, is(XAException.XAER_PROTO)); } }