Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JBTM-3859 clear MBean cache before probing #2338

Open
wants to merge 2 commits into
base: 6.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1634,6 +1634,10 @@ public void warn_objectstore_JDBCImple_over_max_image_size(int imageSize,
@LogMessage(level = WARN)
void warn_invalidObjStoreBrowser_type(String type, @Cause Exception e);

@Message(id = 12407, value = "Skipping handler for bean type: '{0}'", format = MESSAGE_FORMAT)
@LogMessage(level = INFO)
void info_osbSkipHandler(String type);

/*
Allocate new messages directly above this notice.
- id: use the next id number in numeric sequence. Don't reuse ids.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,20 @@ public class ObjStoreBrowser implements ObjStoreBrowserMBean {
"StateManager/BasicAction/TwoPhaseCoordinator/AtomicAction",
null
),
// JTAActionBean overrides ActionBean when the ArjunaJTA module is present, as opposed to just ArjunaCore
// on its own.
// These handlers are iterated over and added to the osbTypeMap map using typeName as the key so,
// to ensure that JTAActionBean is added to the map in JTA mode, please ensure that it appears
// last in this collection so that it overwrites the previous value. An alternative could be to make
// the beanClass field a comma separated list and the first one that is found to be known to the
// class loader would be used, or a completely different design for the instrumentation could be chosen
new OSBTypeHandler(
true,
"com.arjuna.ats.arjuna.AtomicAction",
"com.arjuna.ats.internal.jta.tools.osb.mbean.jta.JTAActionBean",
"StateManager/BasicAction/TwoPhaseCoordinator/AtomicAction",
null
),
};

private static final OSBTypeHandler[] defaultJTSOsbTypes = {
Expand Down Expand Up @@ -294,8 +308,17 @@ private void init(String logDir) {
setExposeAllRecordsAsMBeans(arjPropertyManager.
getObjectStoreEnvironmentBean().getExposeAllLogRecordsAsMBeans());

for (OSBTypeHandler osbType : defaultOsbTypes)
osbTypeMap.put(osbType.getTypeName(), osbType);
for (OSBTypeHandler osbType : defaultOsbTypes) {
try {
Class.forName(osbType.getBeanClass(), true, this.getClass().getClassLoader());
osbTypeMap.put(osbType.getTypeName(), osbType);
} catch (ClassNotFoundException ignore) {
// Some record types (currently only StateManager/BasicAction/TwoPhaseCoordinator/AtomicAction)
// use different handlers depending upon whether ArjunaJTA is present. Ignore classes which
// aren't present and log an info message
tsLogger.i18NLogger.info_osbSkipHandler(osbType.getBeanClass());
}
}

for (OSBTypeHandler osbType : defaultJTSOsbTypes)
osbTypeMap.put(osbType.getTypeName(), osbType);
Expand Down Expand Up @@ -423,34 +446,6 @@ public void setExposeAllRecordsAsMBeans(boolean exposeAllLogs) {
this.exposeAllLogs = exposeAllLogs;
}

/**
* Update registered MBeans based on the current set of Uids.
* @param allCurrUids any registered MBeans not in this collection will be deregistered
*/
private void unregisterRemovedUids(Map<String, Collection<Uid>> allCurrUids) {

for (Map.Entry<String, List<UidWrapper>> e : registeredMBeans.entrySet()) {
String type = e.getKey();
List<UidWrapper> registeredBeansOfType = e.getValue();
Collection<Uid> currUidsOfType = allCurrUids.get(type);

if (currUidsOfType != null) {
Iterator<UidWrapper> iterator = registeredBeansOfType.iterator();

while (iterator.hasNext()) {
UidWrapper w = iterator.next();

if (!currUidsOfType.contains(w.getUid())) {
w.unregister();
iterator.remove();
}
}
} else {
unregisterMBeans(registeredBeansOfType);
}
}
}

/**
* See if any new MBeans need to be registered or if any existing MBeans no longer exist
* as ObjectStore entries.
Expand All @@ -460,12 +455,12 @@ private void unregisterRemovedUids(Map<String, Collection<Uid>> allCurrUids) {
public synchronized void probe() throws MBeanException {
Map<String, Collection<Uid>> currUidsForType = new HashMap<>();

// recreate every MBean so clear the cache first
unregisterMBeans();

for (String type : getTypes())
currUidsForType.put(type, getUids(type));

// if there are any beans in registeredMBeans that don't appear in new list and unregister them
unregisterRemovedUids(currUidsForType); //unregisterMBeans();

for (Map.Entry<String, Collection<Uid>> e : currUidsForType.entrySet()) {
String type = e.getKey();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@
import com.arjuna.ats.arjuna.coordinator.RecordType;
import com.arjuna.ats.arjuna.coordinator.abstractrecord.RecordTypeManager;
import com.arjuna.ats.arjuna.coordinator.abstractrecord.RecordTypeMap;
import com.arjuna.ats.arjuna.recovery.RecoveryDriver;
import com.arjuna.ats.arjuna.recovery.RecoveryManager;
import com.arjuna.ats.arjuna.tools.osb.mbean.ActionBean;
import com.arjuna.ats.arjuna.tools.osb.mbean.LogRecordWrapper;
import com.arjuna.ats.arjuna.tools.osb.mbean.OSEntryBean;
Expand All @@ -51,6 +49,8 @@
import com.arjuna.ats.internal.arjuna.recovery.RecoveryManagerImple;
import com.hp.mwtests.ts.arjuna.resources.CrashRecord;

import java.util.Collection;

/**
* @deprecated as of 5.0.5.Final In a subsequent release we will change packages names in order to
* provide a better separation between public and internal classes.
Expand Down Expand Up @@ -182,15 +182,8 @@ public void aaTest(boolean replay) throws Exception {
osb.start();
osb.probe();

// there should be one MBean corresponding to the AtomicAction A
UidWrapper w = osb.findUid(A.get_uid());
assertNotNull(w);
OSEntryBean ai = w.getMBean();
assertNotNull(ai);

// the MBean should wrap an ActionBean
assertTrue(ai instanceof ActionBean);
ActionBean actionBean = (ActionBean) ai;
// there should be one MBean corresponding to the AtomicAction A and the MBean should wrap an ActionBean
ActionBean actionBean = lookupActionBean(osb, A.get_uid());

// and there should be one MBean corresponding to the CrashRecord that got the heuristic:
int recCount = 0;
Expand All @@ -211,6 +204,16 @@ public void aaTest(boolean replay) throws Exception {

assertEquals(1, recCount);

// verify that the state on disk is no longer a heuristic
actionBean = lookupActionBean(osb, A.get_uid());
Collection<LogRecordWrapper> participants = actionBean.getParticipants();

// there should be only the heuristic participant remaining:
assertEquals(1, participants.size());
LogRecordWrapper wrapper = actionBean.getParticipants().iterator().next();
// and it should no longer be a heuristic
assertFalse(wrapper.isHeuristic());

if (!replay) {
actionBean.remove();
} else {
Expand All @@ -228,13 +231,21 @@ public void aaTest(boolean replay) throws Exception {
osb.probe();

// look up the MBean and verify that it no longer exists
w = osb.findUid(A.get_uid());
assertNull(w);
assertNull(osb.findUid(A.get_uid()));

osb.dump(new StringBuilder());
osb.stop();
}

private ActionBean lookupActionBean(ObjStoreBrowser osb, Uid uid) {
UidWrapper w = osb.findUid(uid);
assertNotNull(w);
OSEntryBean ai = w.getMBean();
assertNotNull(ai);
assertTrue(ai instanceof ActionBean);

return (ActionBean) ai;
}

// define an MBean interface for use in the next test
public interface NotAnotherMBean extends ObjStoreItemMBean {}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
package com.hp.mwtests.ts.jta.tools;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import javax.management.MBeanException;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;

import com.arjuna.ats.arjuna.exceptions.ObjectStoreException;
import com.arjuna.ats.internal.jta.resources.arjunacore.XAResourceRecord;
import org.jboss.tm.XAResourceWrapper;
import com.arjuna.ats.internal.jta.resources.arjunacore.XAResourceRecordWrappingPlugin;
import com.arjuna.ats.jta.common.JTAEnvironmentBean;
import com.arjuna.ats.jta.common.jtaPropertyManager;
import jakarta.transaction.HeuristicMixedException;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
Expand Down Expand Up @@ -45,8 +52,13 @@
* provide a better separation between public and internal classes.
*/
@Deprecated // in order to provide a better separation between public and internal classes.
class ExtendedFailureXAResource extends FailureXAResource {
class ExtendedFailureXAResource extends FailureXAResource implements XAResourceWrapper {
private boolean forgotten;
private String productName;

public ExtendedFailureXAResource(FailLocation loc) {
super(loc);
}

@Override
public void commit(Xid id, boolean onePhase) throws XAException {
Expand All @@ -59,18 +71,34 @@ public void forget(Xid xid) throws XAException {
super.forget(xid);
forgotten = true;
}
}

public class ObjStoreBrowserTest {
private ObjStoreBrowser osb;
@Override
public XAResource getResource() {
return null;
}

private ObjStoreBrowser createObjStoreBrowser() {
ObjStoreBrowser osb = new ObjStoreBrowser();
public void setProductName(String productName) {
this.productName = productName;
}

osb.setType("com.arjuna.ats.arjuna.AtomicAction", "com.arjuna.ats.internal.jta.tools.osb.mbean.jta.JTAActionBean");
@Override
public String getProductName() {
return productName;
}

return osb;
}
@Override
public String getProductVersion() {
return null;
}

@Override
public String getJndiName() {
return null;
}
}

public class ObjStoreBrowserTest {
private ObjStoreBrowser osb;

@BeforeClass
public static void setUp() {
Expand All @@ -79,7 +107,8 @@ public static void setUp() {
@Before
public void beforeTest() {
FailureXAResource.resetForgetCounts();
osb = createObjStoreBrowser();

osb = new ObjStoreBrowser();

osb.start();
}
Expand All @@ -106,9 +135,16 @@ public void testCommitMarkableResourceRecordBean() throws Exception {
@Test
public void testMBeanHeuristic () throws Exception
{
FailureXAResource failureXAResource = new FailureXAResource(FailureXAResource.FailLocation.commit); // generates a heuristic on commit
// generates a heuristic on commit
ExtendedFailureXAResource failureXAResource =
new ExtendedFailureXAResource(FailureXAResource.FailLocation.commit);
String productName = "P";

failureXAResource.setProductName(productName);

XAResourceRecordBeanMBean mbean = getHeuristicMBean(osb, new TransactionImple(1000000000), failureXAResource);

getHeuristicMBean(osb, new TransactionImple(1000000000), failureXAResource);
assertEquals(productName, mbean.getEisProductName());
}

/**
Expand Down Expand Up @@ -337,25 +373,61 @@ private JTAActionBean getTransactionBean(ObjStoreBrowser osb, TransactionImple t
}

private XAResourceRecordBeanMBean getHeuristicMBean(ObjStoreBrowser osb, TransactionImple tx, FailureXAResource failureXAResource) throws Exception {
generateHeuristic(tx, failureXAResource);
// use the wrapper plugin because we'd also like to test resource metadata
XAResourceRecordWrappingPlugin xarWrapperPlugin = new XAResourceRecordWrappingPlugin() {
String productName = "";
@Override
public void transcribeWrapperData(XAResourceRecord xaResourceRecord) {
final XAResource xaResource = (XAResource) xaResourceRecord.value();

if (xaResource instanceof XAResourceWrapper) {
XAResourceWrapper xaResourceWrapper = (XAResourceWrapper) xaResource;
productName = xaResourceWrapper.getProductName();

xaResourceRecord.setProductName(xaResourceWrapper.getProductName());
xaResourceRecord.setProductVersion(xaResourceWrapper.getProductVersion());
xaResourceRecord.setJndiName(xaResourceWrapper.getJndiName());
}
}

@Override
public Integer getEISName(XAResource xaResource) throws IOException, ObjectStoreException {
return 0;
}

@Override
public String getEISName(Integer eisName) {
return productName;
}
};

osb.probe();
// there should be one MBean corresponding to the Transaction
JTAActionBean actionBean = getTransactionBean(osb, tx, true);
JTAEnvironmentBean env = jtaPropertyManager.getJTAEnvironmentBean();
XAResourceRecordWrappingPlugin prevWrappingPlugin = env.getXAResourceRecordWrappingPlugin();

try {
env.setXAResourceRecordWrappingPlugin(xarWrapperPlugin);
generateHeuristic(tx, failureXAResource);
osb.probe();
// there should be one MBean corresponding to the Transaction
JTAActionBean actionBean = getTransactionBean(osb, tx, true);

assertNotNull(actionBean);
assertNotNull(actionBean);

// and the transaction should contain only one participant (namely the FailureXAResource that generated the heuristic):
Collection<LogRecordWrapper> participants = actionBean.getParticipants();
// and the transaction should contain only one participant
// (namely the FailureXAResource that generated the heuristic):
Collection<LogRecordWrapper> participants = actionBean.getParticipants();

assertEquals(1, participants.size());
assertNotNull(failureXAResource.getXid());
assertEquals(1, participants.size());
assertNotNull(failureXAResource.getXid());

LogRecordWrapper participant = participants.iterator().next();
LogRecordWrapper participant = participants.iterator().next();

assertTrue(participant.isHeuristic());
assertTrue(participant instanceof XAResourceRecordBeanMBean);
assertTrue(participant.isHeuristic());
assertTrue(participant instanceof XAResourceRecordBeanMBean);

return (XAResourceRecordBeanMBean) participant;
return (XAResourceRecordBeanMBean) participant;
} finally {
env.setXAResourceRecordWrappingPlugin(prevWrappingPlugin);
}
}
}