Skip to content
Permalink
Browse files
GERONIMO-6372: RecoveryImpl completing in-progress transactions, XidF…
…actoryImpl needs to be smarter with matching

git-svn-id: https://svn.apache.org/repos/asf/geronimo/components/txmanager/trunk@1365021 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
gnodet committed Jul 24, 2012
1 parent bbaaabb commit 8564bb3c145a162bf31eeb5343a84fff343f054e
Showing 2 changed files with 103 additions and 14 deletions.
@@ -17,10 +17,10 @@

package org.apache.geronimo.transaction.manager;

import java.util.Random;
import javax.transaction.xa.Xid;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Random;
import javax.transaction.xa.Xid;

/**
* Factory for transaction ids.
@@ -35,10 +35,11 @@
*/
public class XidFactoryImpl implements XidFactory {
private final byte[] baseId = new byte[Xid.MAXGTRIDSIZE];
private long count = 1;
private final long start = System.currentTimeMillis();
private long count = start;

public XidFactoryImpl(byte[] tmId) {
System.arraycopy(tmId, 0, baseId, 8, tmId.length);
System.arraycopy(tmId, 0, baseId, 8, tmId.length);
}

public XidFactoryImpl() {
@@ -68,14 +69,7 @@ public Xid createXid() {
synchronized (this) {
id = count++;
}
globalId[0] = (byte) id;
globalId[1] = (byte) (id >>> 8);
globalId[2] = (byte) (id >>> 16);
globalId[3] = (byte) (id >>> 24);
globalId[4] = (byte) (id >>> 32);
globalId[5] = (byte) (id >>> 40);
globalId[6] = (byte) (id >>> 48);
globalId[7] = (byte) (id >>> 56);
insertLong(id, globalId, 0);
return new XidImpl(globalId);
}

@@ -85,6 +79,7 @@ public Xid createBranch(Xid globalId, int branch) {
branchId[1] = (byte) (branch >>> 8);
branchId[2] = (byte) (branch >>> 16);
branchId[3] = (byte) (branch >>> 24);
insertLong(start, branchId, 4);
return new XidImpl(globalId, branchId);
}

@@ -97,14 +92,22 @@ public boolean matchesGlobalId(byte[] globalTransactionId) {
return false;
}
}
return true;
// for recovery, only match old transactions
long id = extractLong(globalTransactionId, 0);
return (id < start);
}

public boolean matchesBranchId(byte[] branchQualifier) {
if (branchQualifier.length != Xid.MAXBQUALSIZE) {
return false;
}
for (int i = 8; i < branchQualifier.length; i++) {
long id = extractLong(branchQualifier, 4);
if (id >= start) {
// newly created branch, not recoverable
return false;
}

for (int i = 12; i < branchQualifier.length; i++) {
if (branchQualifier[i] != baseId[i]) {
return false;
}
@@ -116,4 +119,26 @@ public Xid recover(int formatId, byte[] globalTransactionid, byte[] branchQualif
return new XidImpl(formatId, globalTransactionid, branchQualifier);
}

static void insertLong(long value, byte[] bytes, int offset) {
bytes[offset + 0] = (byte) value;
bytes[offset + 1] = (byte) (value >>> 8);
bytes[offset + 2] = (byte) (value >>> 16);
bytes[offset + 3] = (byte) (value >>> 24);
bytes[offset + 4] = (byte) (value >>> 32);
bytes[offset + 5] = (byte) (value >>> 40);
bytes[offset + 6] = (byte) (value >>> 48);
bytes[offset + 7] = (byte) (value >>> 56);
}

static long extractLong(byte[] bytes, int offset) {
return (bytes[offset + 0] & 0xff)
+ (((bytes[offset + 1] & 0xff)) << 8)
+ (((bytes[offset + 2] & 0xff)) << 16)
+ (((bytes[offset + 3] & 0xffL)) << 24)
+ (((bytes[offset + 4] & 0xffL)) << 32)
+ (((bytes[offset + 5] & 0xffL)) << 40)
+ (((bytes[offset + 6] & 0xffL)) << 48)
+ (((long) bytes[offset + 7]) << 56);
}

}
@@ -0,0 +1,64 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.geronimo.transaction.manager;

import java.util.concurrent.TimeUnit;
import javax.transaction.xa.Xid;

import junit.framework.TestCase;

public class XidFactoryImplTest extends TestCase {

public void testLong() {
byte[] buffer = new byte[64];
long l1 = 1343120074022l;
XidFactoryImpl.insertLong(l1, buffer, 4);
long l2 = XidFactoryImpl.extractLong(buffer, 4);
assertEquals(l1, l2);

l1 = 1343120074022l - TimeUnit.DAYS.toMillis(15);
XidFactoryImpl.insertLong(l1, buffer, 4);
l2 = XidFactoryImpl.extractLong(buffer, 4);
assertEquals(l1, l2);
}

public void testFactory() throws Exception {
XidFactory factory = new XidFactoryImpl("hi".getBytes());
Xid id1 = factory.createXid();
Xid id2 = factory.createXid();

assertFalse("Should not match new: " + id1, factory.matchesGlobalId(id1.getGlobalTransactionId()));
assertFalse("Should not match new: " + id2, factory.matchesGlobalId(id2.getGlobalTransactionId()));

Xid b_id1 = factory.createBranch(id1, 1);
Xid b_id2 = factory.createBranch(id2, 1);

assertFalse("Should not match new branch: " + b_id1, factory.matchesBranchId(b_id1.getBranchQualifier()));
assertFalse("Should not match new branch: " + b_id2, factory.matchesBranchId(b_id2.getBranchQualifier()));

Thread.sleep(5);

XidFactory factory2 = new XidFactoryImpl("hi".getBytes());
assertTrue("Should match old: " + id1, factory2.matchesGlobalId(id1.getGlobalTransactionId()));
assertTrue("Should match old: " + id2, factory2.matchesGlobalId(id2.getGlobalTransactionId()));

assertTrue("Should match old branch: " + b_id1, factory2.matchesBranchId(b_id1.getBranchQualifier()));
assertTrue("Should match old branch: " + b_id2, factory2.matchesBranchId(b_id2.getBranchQualifier()));
}

}

0 comments on commit 8564bb3

Please sign in to comment.