Search in sources :

Example 16 with Xid

use of javax.transaction.xa.Xid in project graphdb by neo4j-attic.

the class TestJtaCompliance method testRollback1.

/**
     * o Tests that multiple enlistments receive rollback calls properly.
     */
@Test
public void testRollback1() throws Exception {
    tm.begin();
    FakeXAResource res1 = new FakeXAResource("XAResource1");
    FakeXAResource res2 = new FakeXAResource("XAResource2");
    // enlist two different resources and verify that the start method
    // is invoked with correct flags
    // res1
    tm.getTransaction().enlistResource(res1);
    MethodCall[] calls1 = res1.getAndRemoveMethodCalls();
    assertEquals(1, calls1.length);
    assertEquals("start", calls1[0].getMethodName());
    // res2
    tm.getTransaction().enlistResource(res2);
    MethodCall[] calls2 = res2.getAndRemoveMethodCalls();
    assertEquals(1, calls2.length);
    assertEquals("start", calls2[0].getMethodName());
    // verify Xid
    Object[] args = calls1[0].getArgs();
    Xid xid1 = (Xid) args[0];
    assertEquals(XAResource.TMNOFLAGS, ((Integer) args[1]).intValue());
    args = calls2[0].getArgs();
    Xid xid2 = (Xid) args[0];
    assertEquals(XAResource.TMNOFLAGS, ((Integer) args[1]).intValue());
    // should have same global transaction id
    byte[] globalTxId1 = xid1.getGlobalTransactionId();
    byte[] globalTxId2 = xid2.getGlobalTransactionId();
    assertTrue(globalTxId1.length == globalTxId2.length);
    for (int i = 0; i < globalTxId1.length; i++) {
        assertEquals(globalTxId1[i], globalTxId2[i]);
    }
    byte[] branch1 = xid1.getBranchQualifier();
    byte[] branch2 = xid2.getBranchQualifier();
    // make sure a different branch was created
    if (branch1.length == branch2.length) {
        boolean same = true;
        for (int i = 0; i < branch1.length; i++) {
            if (branch1[i] != branch2[i]) {
                same = false;
                break;
            }
        }
        assertTrue(!same);
    }
    // verify delist of resource
    tm.getTransaction().delistResource(res2, XAResource.TMSUCCESS);
    calls2 = res2.getAndRemoveMethodCalls();
    assertEquals(1, calls2.length);
    tm.getTransaction().delistResource(res1, XAResource.TMSUCCESS);
    calls1 = res1.getAndRemoveMethodCalls();
    // res1
    assertEquals(1, calls1.length);
    assertEquals("end", calls1[0].getMethodName());
    args = calls1[0].getArgs();
    assertTrue(((Xid) args[0]).equals(xid1));
    assertEquals(XAResource.TMSUCCESS, ((Integer) args[1]).intValue());
    // res2
    assertEquals(1, calls2.length);
    assertEquals("end", calls2[0].getMethodName());
    args = calls2[0].getArgs();
    assertTrue(((Xid) args[0]).equals(xid2));
    assertEquals(XAResource.TMSUCCESS, ((Integer) args[1]).intValue());
    // verify proper rollback
    tm.rollback();
    calls1 = res1.getAndRemoveMethodCalls();
    calls2 = res2.getAndRemoveMethodCalls();
    // res1
    assertEquals(1, calls1.length);
    assertEquals("rollback", calls1[0].getMethodName());
    args = calls1[0].getArgs();
    assertTrue(((Xid) args[0]).equals(xid1));
    // res2
    assertEquals(1, calls2.length);
    assertEquals("rollback", calls2[0].getMethodName());
    args = calls2[0].getArgs();
    assertTrue(((Xid) args[0]).equals(xid2));
}
Also used : Xid(javax.transaction.xa.Xid) Test(org.junit.Test)

Example 17 with Xid

use of javax.transaction.xa.Xid in project graphdb by neo4j-attic.

the class TestJtaCompliance method test2PhaseCommits2.

/**
     * o Tests that two enlistments of same resource (according to the
     * isSameRM() method) only receive one set of prepare/commit calls.
     */
@Test
public void test2PhaseCommits2() throws Exception {
    tm.begin();
    FakeXAResource res1 = new FakeXAResource("XAResource1");
    FakeXAResource res2 = new FakeXAResource("XAResource1");
    // enlist two (same) resources and verify that the start method
    // is invoked with correct flags
    // res1
    tm.getTransaction().enlistResource(res1);
    MethodCall[] calls1 = res1.getAndRemoveMethodCalls();
    assertEquals(1, calls1.length);
    assertEquals("start", calls1[0].getMethodName());
    // res2
    tm.getTransaction().enlistResource(res2);
    MethodCall[] calls2 = res2.getAndRemoveMethodCalls();
    assertEquals(1, calls2.length);
    assertEquals("start", calls2[0].getMethodName());
    // make sure we get a two-phase commit
    FakeXAResource res3 = new FakeXAResource("XAResource2");
    tm.getTransaction().enlistResource(res3);
    // verify Xid and flags
    Object[] args = calls1[0].getArgs();
    Xid xid1 = (Xid) args[0];
    assertEquals(XAResource.TMNOFLAGS, ((Integer) args[1]).intValue());
    args = calls2[0].getArgs();
    Xid xid2 = (Xid) args[0];
    assertEquals(XAResource.TMJOIN, ((Integer) args[1]).intValue());
    assertTrue(xid1.equals(xid2));
    assertTrue(xid2.equals(xid1));
    // verify delist of resource
    tm.getTransaction().delistResource(res3, XAResource.TMSUCCESS);
    tm.getTransaction().delistResource(res2, XAResource.TMSUCCESS);
    calls2 = res2.getAndRemoveMethodCalls();
    assertEquals(1, calls2.length);
    tm.getTransaction().delistResource(res1, XAResource.TMSUCCESS);
    calls1 = res1.getAndRemoveMethodCalls();
    // res1
    assertEquals(1, calls1.length);
    assertEquals("end", calls1[0].getMethodName());
    args = calls1[0].getArgs();
    assertTrue(((Xid) args[0]).equals(xid1));
    assertEquals(XAResource.TMSUCCESS, ((Integer) args[1]).intValue());
    // res2
    assertEquals(1, calls2.length);
    assertEquals("end", calls2[0].getMethodName());
    args = calls2[0].getArgs();
    assertTrue(((Xid) args[0]).equals(xid2));
    assertEquals(XAResource.TMSUCCESS, ((Integer) args[1]).intValue());
    // verify proper prepare/commit
    tm.commit();
    calls1 = res1.getAndRemoveMethodCalls();
    calls2 = res2.getAndRemoveMethodCalls();
    // res1
    assertEquals(2, calls1.length);
    assertEquals("prepare", calls1[0].getMethodName());
    args = calls1[0].getArgs();
    assertTrue(((Xid) args[0]).equals(xid1));
    assertEquals("commit", calls1[1].getMethodName());
    args = calls1[1].getArgs();
    assertTrue(((Xid) args[0]).equals(xid1));
    assertEquals(false, ((Boolean) args[1]).booleanValue());
    // res2
    assertEquals(0, calls2.length);
}
Also used : Xid(javax.transaction.xa.Xid) Test(org.junit.Test)

Example 18 with Xid

use of javax.transaction.xa.Xid in project graphdb by neo4j-attic.

the class TxLog method getDanglingRecords.

/**
     * Returns an array of lists, each list contains dangling records
     * (transactions that han't been completed yet) grouped after global by
     * transaction id.
     */
public synchronized Iterator<List<Record>> getDanglingRecords() throws IOException {
    fileChannel.position(0);
    buffer.clear();
    fileChannel.read(buffer);
    buffer.flip();
    // next record position
    long nextPosition = 0;
    // holds possible dangling records
    int seqNr = 0;
    Map<Xid, List<Record>> recordMap = new HashMap<Xid, List<Record>>();
    while (buffer.hasRemaining()) {
        byte recordType = buffer.get();
        if (recordType == TX_START) {
            if (!buffer.hasRemaining()) {
                break;
            }
            byte[] globalId = new byte[buffer.get()];
            if (buffer.limit() - buffer.position() < globalId.length) {
                break;
            }
            buffer.get(globalId);
            Xid xid = new XidImpl(globalId, new byte[0]);
            if (recordMap.containsKey(xid)) {
                throw new IOException("Tx start for same xid[" + xid + "] found twice");
            }
            List<Record> recordList = new LinkedList<Record>();
            recordList.add(new Record(recordType, globalId, null, seqNr++));
            recordMap.put(xid, recordList);
            nextPosition += 2 + globalId.length;
        } else if (recordType == BRANCH_ADD) {
            if (buffer.limit() - buffer.position() < 2) {
                break;
            }
            byte[] globalId = new byte[buffer.get()];
            byte[] branchId = new byte[buffer.get()];
            if (buffer.limit() - buffer.position() < globalId.length + branchId.length) {
                break;
            }
            buffer.get(globalId);
            buffer.get(branchId);
            Xid xid = new XidImpl(globalId, new byte[0]);
            if (!recordMap.containsKey(xid)) {
                throw new IOException("Branch[" + UTF8.decode(branchId) + "] found for [" + xid + "] but no record list found in map");
            }
            recordMap.get(xid).add(new Record(recordType, globalId, branchId, seqNr++));
            nextPosition += 3 + globalId.length + branchId.length;
        } else if (recordType == MARK_COMMIT) {
            if (!buffer.hasRemaining()) {
                break;
            }
            byte[] globalId = new byte[buffer.get()];
            if (buffer.limit() - buffer.position() < globalId.length) {
                break;
            }
            buffer.get(globalId);
            Xid xid = new XidImpl(globalId, new byte[0]);
            if (!recordMap.containsKey(xid)) {
                throw new IOException("Commiting xid[" + xid + "] mark found but no record list found in map");
            }
            List<Record> recordList = recordMap.get(xid);
            recordList.add(new Record(recordType, globalId, null, seqNr++));
            recordMap.put(xid, recordList);
            nextPosition += 2 + globalId.length;
        } else if (recordType == TX_DONE) {
            if (!buffer.hasRemaining()) {
                break;
            }
            byte[] globalId = new byte[buffer.get()];
            if (buffer.limit() - buffer.position() < globalId.length) {
                break;
            }
            buffer.get(globalId);
            Xid xid = new XidImpl(globalId, new byte[0]);
            if (!recordMap.containsKey(xid)) {
                throw new IOException("Commiting xid[" + xid + "] mark found but no record list found in map");
            }
            recordMap.remove(xid);
            nextPosition += 2 + globalId.length;
        } else if (recordType == 0) {
            continue;
        } else {
            throw new IOException("Unknown type: " + recordType);
        }
        if ((buffer.limit() - buffer.position()) < (3 + Xid.MAXGTRIDSIZE + Xid.MAXBQUALSIZE)) {
            // make sure we don't try to read non full entry
            buffer.clear();
            fileChannel.position(nextPosition);
            fileChannel.read(buffer);
            buffer.flip();
        }
    }
    return recordMap.values().iterator();
}
Also used : HashMap(java.util.HashMap) IOException(java.io.IOException) LinkedList(java.util.LinkedList) Xid(javax.transaction.xa.Xid) ArrayList(java.util.ArrayList) List(java.util.List) LinkedList(java.util.LinkedList)

Example 19 with Xid

use of javax.transaction.xa.Xid in project graphdb by neo4j-attic.

the class TxManager method buildRecoveryInfo.

private void buildRecoveryInfo(List<NonCompletedTransaction> commitList, List<Xid> rollbackList, Map<Resource, XAResource> resourceMap, Iterator<List<TxLog.Record>> danglingRecordList) {
    while (danglingRecordList.hasNext()) {
        Iterator<TxLog.Record> dListItr = danglingRecordList.next().iterator();
        TxLog.Record startRecord = dListItr.next();
        if (startRecord.getType() != TxLog.TX_START) {
            throw new TransactionFailureException("First record not a start record, type=" + startRecord.getType());
        }
        // get branches & commit status
        HashSet<Resource> branchSet = new HashSet<Resource>();
        int markedCommit = -1;
        while (dListItr.hasNext()) {
            TxLog.Record record = dListItr.next();
            if (record.getType() == TxLog.BRANCH_ADD) {
                if (markedCommit != -1) {
                    throw new TransactionFailureException("Already marked commit " + startRecord);
                }
                branchSet.add(new Resource(record.getBranchId()));
            } else if (record.getType() == TxLog.MARK_COMMIT) {
                if (markedCommit != -1) {
                    throw new TransactionFailureException("Already marked commit " + startRecord);
                }
                markedCommit = record.getSequenceNumber();
            } else {
                throw new TransactionFailureException("Illegal record type[" + record.getType() + "]");
            }
        }
        Iterator<Resource> resourceItr = branchSet.iterator();
        List<Xid> xids = new LinkedList<Xid>();
        while (resourceItr.hasNext()) {
            Resource resource = resourceItr.next();
            if (!resourceMap.containsKey(resource)) {
                resourceMap.put(resource, getXaResource(resource.getResourceId()));
            }
            xids.add(new XidImpl(startRecord.getGlobalId(), resource.getResourceId()));
        }
        if (// this xid needs to be committed
        markedCommit != -1) {
            commitList.add(new NonCompletedTransaction(markedCommit, xids));
        } else {
            rollbackList.addAll(xids);
        }
    }
}
Also used : XAResource(javax.transaction.xa.XAResource) XaResource(org.neo4j.kernel.impl.transaction.xaframework.XaResource) LinkedList(java.util.LinkedList) TransactionFailureException(org.neo4j.graphdb.TransactionFailureException) Xid(javax.transaction.xa.Xid) HashSet(java.util.HashSet)

Example 20 with Xid

use of javax.transaction.xa.Xid in project graphdb by neo4j-attic.

the class TxManager method recover.

private void recover(Iterator<List<TxLog.Record>> danglingRecordList) {
    msgLog.logMessage("TM non resolved transactions found in " + txLog.getName(), true);
    try {
        // contains NonCompletedTransaction that needs to be committed
        List<NonCompletedTransaction> commitList = new ArrayList<NonCompletedTransaction>();
        // contains Xids that should be rolledback
        List<Xid> rollbackList = new LinkedList<Xid>();
        // key = Resource(branchId) value = XAResource
        Map<Resource, XAResource> resourceMap = new HashMap<Resource, XAResource>();
        buildRecoveryInfo(commitList, rollbackList, resourceMap, danglingRecordList);
        // invoke recover on all xa resources found
        Iterator<Resource> resourceItr = resourceMap.keySet().iterator();
        List<Xid> recoveredXidsList = new LinkedList<Xid>();
        while (resourceItr.hasNext()) {
            XAResource xaRes = resourceMap.get(resourceItr.next());
            Xid[] xids = xaRes.recover(XAResource.TMNOFLAGS);
            for (int i = 0; i < xids.length; i++) {
                if (XidImpl.isThisTm(xids[i].getGlobalTransactionId())) {
                    // linear search
                    if (rollbackList.contains(xids[i])) {
                        log.fine("Found pre commit " + xids[i] + " rolling back ... ");
                        msgLog.logMessage("TM: Found pre commit " + xids[i] + " rolling back ... ", true);
                        rollbackList.remove(xids[i]);
                        xaRes.rollback(xids[i]);
                    } else {
                        recoveredXidsList.add(xids[i]);
                    }
                } else {
                    log.warning("Unknown xid: " + xids[i]);
                }
            }
        }
        // sort the commit list after sequence number
        Collections.sort(commitList, new Comparator<NonCompletedTransaction>() {

            public int compare(NonCompletedTransaction r1, NonCompletedTransaction r2) {
                return r1.getSequenceNumber() - r2.getSequenceNumber();
            }
        });
        // go through and commit
        Iterator<NonCompletedTransaction> commitItr = commitList.iterator();
        while (commitItr.hasNext()) {
            NonCompletedTransaction nct = commitItr.next();
            int seq = nct.getSequenceNumber();
            Xid[] xids = nct.getXids();
            log.fine("Marked as commit tx-seq[" + seq + "] branch length: " + xids.length);
            for (int i = 0; i < xids.length; i++) {
                if (!recoveredXidsList.contains(xids[i])) {
                    log.fine("Tx-seq[" + seq + "][" + xids[i] + "] not found in recovered xid list, " + "assuming already committed");
                    continue;
                }
                recoveredXidsList.remove(xids[i]);
                Resource resource = new Resource(xids[i].getBranchQualifier());
                if (!resourceMap.containsKey(resource)) {
                    throw new TransactionFailureException("Couldn't find XAResource for " + xids[i]);
                }
                log.fine("Commiting tx seq[" + seq + "][" + xids[i] + "] ... ");
                msgLog.logMessage("TM: Committing tx " + xids[i], true);
                resourceMap.get(resource).commit(xids[i], false);
            }
        }
        // rollback the rest
        Iterator<Xid> rollbackItr = recoveredXidsList.iterator();
        while (rollbackItr.hasNext()) {
            Xid xid = rollbackItr.next();
            Resource resource = new Resource(xid.getBranchQualifier());
            if (!resourceMap.containsKey(resource)) {
                throw new TransactionFailureException("Couldn't find XAResource for " + xid);
            }
            log.fine("Rollback " + xid + " ... ");
            msgLog.logMessage("TM: no match found for " + xid + " removing", true);
            resourceMap.get(resource).rollback(xid);
        }
        if (rollbackList.size() > 0) {
            log.fine("TxLog contained unresolved " + "xids that needed rollback. They couldn't be matched to " + "any of the XAResources recover list. " + "Assuming " + rollbackList.size() + " transactions already rolled back.");
            msgLog.logMessage("TM: no match found for in total " + rollbackList.size() + " transaction that should have been rolled back", true);
        }
    } catch (XAException e) {
        throw new TransactionFailureException("Recovery failed." + e);
    }
}
Also used : XAException(javax.transaction.xa.XAException) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) XAResource(javax.transaction.xa.XAResource) XaResource(org.neo4j.kernel.impl.transaction.xaframework.XaResource) LinkedList(java.util.LinkedList) Xid(javax.transaction.xa.Xid) XAResource(javax.transaction.xa.XAResource) TransactionFailureException(org.neo4j.graphdb.TransactionFailureException)

Aggregations

Xid (javax.transaction.xa.Xid)63 Test (org.junit.Test)23 XAException (javax.transaction.xa.XAException)19 IOException (java.io.IOException)16 XAResource (javax.transaction.xa.XAResource)13 XidImpl (org.neo4j.kernel.impl.transaction.XidImpl)11 LinkedList (java.util.LinkedList)10 InOrder (org.mockito.InOrder)6 HashMap (java.util.HashMap)5 RelationshipType (org.neo4j.graphdb.RelationshipType)5 HazelcastXAResource (com.hazelcast.transaction.HazelcastXAResource)4 ArrayList (java.util.ArrayList)4 RollbackException (javax.transaction.RollbackException)4 TransactionFailureException (org.neo4j.graphdb.TransactionFailureException)4 XaResource (org.neo4j.kernel.impl.transaction.xaframework.XaResource)4 TransactionContext (com.hazelcast.transaction.TransactionContext)3 SerializableXID (com.hazelcast.transaction.impl.xa.SerializableXID)3 SystemException (javax.transaction.SystemException)3 HazelcastInstance (com.hazelcast.core.HazelcastInstance)2 HashSet (java.util.HashSet)2