[JBoss JIRA] Created: (JBMESSAGING-978) NullPointerException within DefaultClusteredPostOffice.handleMessagePullResult()
by Ray Ploski (JIRA)
NullPointerException within DefaultClusteredPostOffice.handleMessagePullResult()
--------------------------------------------------------------------------------
Key: JBMESSAGING-978
URL: http://jira.jboss.com/jira/browse/JBMESSAGING-978
Project: JBoss Messaging
Issue Type: Bug
Components: JMS Clustering
Affects Versions: 1.2.0.SP1
Environment: CentOS 4, JBoss AS 4.0.5, Sun JDK 1.5.07, MySQL 5.x for persistence. Six node cluster.
Reporter: Ray Ploski
Assigned To: Tim Fox
After sending about 10,000 messages through a clustered JMS deployment we received the following error, locking up the topic. I worked around it by adding a null check to the condition within handleMessagePullResult(). Fix is for line 968 of org.jboss.messaging.core.plugin.postoffice.cluster.DefaultClusteredPostOffice is listed at the end of the description.
2007-05-31 11:41:39,130 ERROR @IncomingMessageHandler (channel=DefaultPostOffice) [DefaultClusteredPostOffice] Caught Exception in Receiver
java.lang.NullPointerException
at org.jboss.messaging.core.plugin.postoffice.cluster.DefaultClusteredPostOffice.handleMessagePullResult(DefaultClusteredPostOffice.java:968)
at org.jboss.messaging.core.plugin.postoffice.cluster.PullMessageResultRequest.execute(PullMessageResultRequest.java:105)
at org.jboss.messaging.core.plugin.postoffice.cluster.DefaultClusteredPostOffice$DataReceiver.receive(DefaultClusteredPostOffice.java:2461)
at org.jgroups.JChannel.up(JChannel.java:1102)
at org.jgroups.stack.ProtocolStack.up(ProtocolStack.java:377)
at org.jgroups.stack.ProtocolStack.receiveUpEvent(ProtocolStack.java:393)
at org.jgroups.stack.Protocol.passUp(Protocol.java:538)
at org.jgroups.protocols.pbcast.GMS.up(GMS.java:771)
at org.jgroups.stack.Protocol.receiveUpEvent(Protocol.java:488)
at org.jgroups.protocols.pbcast.GMS.receiveUpEvent(GMS.java:791)
at org.jgroups.stack.Protocol.passUp(Protocol.java:538)
at org.jgroups.protocols.VIEW_SYNC.up(VIEW_SYNC.java:154)
at org.jgroups.stack.Protocol.receiveUpEvent(Protocol.java:488)
at org.jgroups.stack.Protocol.passUp(Protocol.java:538)
at org.jgroups.protocols.FRAG.up(FRAG.java:168)
at org.jgroups.stack.Protocol.receiveUpEvent(Protocol.java:488)
at org.jgroups.stack.Protocol.passUp(Protocol.java:538)
at org.jgroups.protocols.pbcast.STABLE.up(STABLE.java:258)
at org.jgroups.stack.Protocol.receiveUpEvent(Protocol.java:488)
at org.jgroups.stack.Protocol.passUp(Protocol.java:538)
at org.jgroups.protocols.UNICAST.handleDataReceived(UNICAST.java:476)
at org.jgroups.protocols.UNICAST.up(UNICAST.java:206)
at org.jgroups.stack.Protocol.receiveUpEvent(Protocol.java:488)
at org.jgroups.stack.Protocol.passUp(Protocol.java:538)
at org.jgroups.protocols.pbcast.NAKACK.up(NAKACK.java:569)
at org.jgroups.stack.Protocol.receiveUpEvent(Protocol.java:488)
FIX:
if (remoteQueue == null || remoteNodeId != remoteQueue.getNodeId() )
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://jira.jboss.com/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
19 years, 1 month
[JBoss JIRA] Created: (JBPM-973) Implement a DbPersistenceService that delegates to transaction handling to Hibernate
by Matt Read (JIRA)
Implement a DbPersistenceService that delegates to transaction handling to Hibernate
------------------------------------------------------------------------------------
Key: JBPM-973
URL: http://jira.jboss.com/jira/browse/JBPM-973
Project: JBoss jBPM
Issue Type: Feature Request
Components: Core Engine
Affects Versions: jBPM jPDL 3.2
Reporter: Matt Read
Assigned To: Tom Baeyens
Priority: Minor
Attachments: HibernateDbPersistenceServiceFactory.java
Rather than use the JtaDbPersistenceService we wanted to delegate all transaction handling to Hibernate. The file attached to this issue needs the following jbpm.cfg.xml:
<service name="persistence" factory="com.catlin.workflow.engine.persistence.HibernateDbPersistenceServiceFactory" />
and appropriate session context management in hibernate.cfg.xml:
<property name="current_session_context_class">jta</property>
or
<property name="current_session_context_class">thread</property>
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://jira.jboss.com/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
19 years, 1 month
[JBoss JIRA] Created: (JBPM-970) Orphaned records remain in the DB after process instance is deleted
by Tihomir Daskalov (JIRA)
Orphaned records remain in the DB after process instance is deleted
-------------------------------------------------------------------
Key: JBPM-970
URL: http://jira.jboss.com/jira/browse/JBPM-970
Project: JBoss jBPM
Issue Type: Bug
Components: Core Engine
Affects Versions: jBPM 3.1.2
Reporter: Tihomir Daskalov
Assigned To: Tom Baeyens
I have detected leak of orphaned records in the DB in the following cases:
1) deleting a process instance variable
2) changing the type of a process instance variable (for example from string to long)
3) updating a byte array (the leak appears only when the updates are performed in different JBPM sessions - i.e. when the process instance execution is asynchronous)
Seems that for the first two cases the orphaned records are left because of the cascade="save-update" in org.jbpm.context.log.VariableLog.hbm.xml. It causes the variable instances that are referenced only from the process instance log to be not deleted in the DB. As workaround I had to manually remove the orphaned records in the following way:
// The logs map contains the logs per token.
Map tokensLogs = SessionContext.getJbpmContext().getLoggingSession()
.findLogsByProcessInstance(_processInstance.getId());
if (tokensLogs.size() != 1) {
// For now are supported only logs with one token.
throw new IllegalArgumentException("Expected exactly one token but found: "
+ tokensLogs.size());
}
// The map is expected to have only one element mapping the root token
// to the list of its logs.
List logs = (List) tokensLogs.values().iterator().next();
Session session = SessionContext.getJbpmContext().getSession();
for (Iterator iter = logs.iterator(); iter.hasNext();) {
ProcessLog log = (ProcessLog) iter.next();
if (log instanceof VariableLog) {
VariableLog variableLog = ((VariableLog) log);
VariableInstance variableInstance = variableLog.getVariableInstance();
// Remove only the variable instances that are not associated with token.
if (variableInstance.getToken() == null) {
session.delete(variableInstance);
}
}
session.delete(log);
}
The third case seems to be caused from orphaned child entity (org.jbpm.bytes.ByteArray). The new ByteArray value replaces the old ByteArray value in the org.jbpm.context.exe.VariableInstance class, and thus the old ByteArray remains orphan. This is no problem if the old ByteArray is still transient - it will be GC-ed, but if it was already persisted then the persisted entity will remain orphan in the DB. This explains why the 3-rd case can be reproduced only when the byte array is persisted between the two states of the process instance.
I have used the following code to workaround the 3-rd case:
// Take reference to the old ByteArray entity.
ByteArray oldByteArray = null;
TokenVariableMap tokenVariableMap = pProcessInstance.getContextInstance().getTokenVariableMap(pProcessInstance.getRootToken());
if (tokenVariableMap != null) {
VariableInstance variableInstance = tokenVariableMap.getVariableInstance(pVariableName);
if (variableInstance != null) {
oldByteArray = (ByteArray) ((ByteArrayInstance) variableInstance).getObject();
}
}
// Set the new value of the byte array.
pProcessInstance.getContextInstance().setVariable(pVariableName, pBytes);
// Manually remove the old byte array.
if (oldByteArray != null) {
Session session = _jbpmContext().getSession();
if (session != null && session.contains(oldByteArray)) {
SessionContext.getJbpmContext().getSession().delete(oldByteArray);
}
}
Follows the test case that reproduces (via failing) the three operations described above:
public class JbpmTest extends TestCase {
private JbpmContext _jbpmContext;
protected void setUp() throws Exception {
JbpmConfiguration.getInstance().createSchema();
_jbpmContext = JbpmConfiguration.getInstance().createJbpmContext();
}
protected void tearDown() throws Exception {
_jbpmContext.close();
JbpmConfiguration.getInstance().dropSchema();
}
/**
* Tests that deleting a JBPM variable leaks orphaned records.
*/
public void testOrphanRecords_1() throws HibernateException, SQLException {
ProcessDefinition processDefinition = ProcessDefinition
.parseXmlString("<process-definition name='test'>"
+ " <start-state>"
+ " <transition to='s' />"
+ " </start-state>"
+ " <state name='s'>"
+ " <transition to='end' />"
+ " </state>"
+ " <end-state name='end' />"
+ "</process-definition>");
_jbpmContext.deployProcessDefinition(processDefinition);
// Assure that the watched tables are empty.
assertEquals(0, getRecordCount("JBPM_VARIABLEINSTANCE"));
assertEquals(0, getRecordCount("JBPM_LOG"));
assertEquals(0, getRecordCount("JBPM_BYTEBLOCK"));
assertEquals(0, getRecordCount("JBPM_BYTEARRAY"));
// Execute a process instance and create and delete a variable.
ProcessInstance processInstance = new ProcessInstance(processDefinition);
processInstance.getContextInstance().setVariable("test", "abc");
processInstance.signal();
assertFalse(processInstance.hasEnded());
processInstance.getContextInstance().deleteVariable("test");
processInstance.signal();
assertTrue(processInstance.hasEnded());
// Persist the process instance.
_jbpmContext.save(processInstance);
_jbpmContext.getSession().flush();
long processInstanceId = processInstance.getId();
// Assure that the log entries are really persisted.
assertTrue(0 < getRecordCount("JBPM_LOG"));
// Delete the process instance.
_jbpmContext.getGraphSession().deleteProcessInstance(processInstanceId);
// Assure that the watched tables are empty.
assertEquals(0, getRecordCount("JBPM_VARIABLEINSTANCE"));
assertEquals(0, getRecordCount("JBPM_LOG"));
assertEquals(0, getRecordCount("JBPM_BYTEBLOCK"));
assertEquals(0, getRecordCount("JBPM_BYTEARRAY"));
}
/**
* Tests that changing the type of a JBPM variable leaks orphaned records.
*/
public void testOrphanRecords_2() throws HibernateException, SQLException {
ProcessDefinition processDefinition = ProcessDefinition
.parseXmlString("<process-definition name='test'>"
+ " <start-state>"
+ " <transition to='s' />"
+ " </start-state>"
+ " <state name='s'>"
+ " <transition to='end' />"
+ " </state>"
+ " <end-state name='end' />"
+ "</process-definition>");
_jbpmContext.deployProcessDefinition(processDefinition);
// Assure that the watched tables are empty.
assertEquals(0, getRecordCount("JBPM_VARIABLEINSTANCE"));
assertEquals(0, getRecordCount("JBPM_LOG"));
assertEquals(0, getRecordCount("JBPM_BYTEBLOCK"));
assertEquals(0, getRecordCount("JBPM_BYTEARRAY"));
// Execute a process instance and create and then change the type of a variable.
ProcessInstance processInstance = new ProcessInstance(processDefinition);
processInstance.getContextInstance().setVariable("test", "abc");
processInstance.signal();
assertFalse(processInstance.hasEnded());
processInstance.getContextInstance().setVariable("test", new Long(10));
processInstance.signal();
assertTrue(processInstance.hasEnded());
// Persist the process instance.
_jbpmContext.save(processInstance);
_jbpmContext.getSession().flush();
long processInstanceId = processInstance.getId();
// Assure that the log entries are really persisted.
assertTrue(0 < getRecordCount("JBPM_LOG"));
// Delete the process instance.
_jbpmContext.getGraphSession().deleteProcessInstance(processInstanceId);
// Assure that the watched tables are empty.
assertEquals(0, getRecordCount("JBPM_VARIABLEINSTANCE"));
assertEquals(0, getRecordCount("JBPM_LOG"));
assertEquals(0, getRecordCount("JBPM_BYTEBLOCK"));
assertEquals(0, getRecordCount("JBPM_BYTEARRAY"));
}
/**
* Tests that a JBPM variable of byte array type leaks orphaned records.
* Note that the leak appears only when the JBPM session is reopened between the states.
*/
public void testOrphanRecords_3() throws HibernateException, SQLException {
ProcessDefinition processDefinition = ProcessDefinition
.parseXmlString("<process-definition name='test'>"
+ " <start-state>"
+ " <transition to='s' />"
+ " </start-state>"
+ " <state name='s'>"
+ " <transition to='end' />"
+ " </state>"
+ " <end-state name='end' />"
+ "</process-definition>");
_jbpmContext.deployProcessDefinition(processDefinition);
// Assure that the watched tables are empty.
assertEquals(0, getRecordCount("JBPM_VARIABLEINSTANCE"));
assertEquals(0, getRecordCount("JBPM_LOG"));
assertEquals(0, getRecordCount("JBPM_BYTEBLOCK"));
assertEquals(0, getRecordCount("JBPM_BYTEARRAY"));
// Execute a process instance and create a byte array variable.
// Note that the leak appears only when the JBPM session is reopened between the states.
ProcessInstance processInstance = new ProcessInstance(processDefinition);
processInstance.getContextInstance().setVariable("bytes", new byte[] {1, 2});
_jbpmContext.save(processInstance);
_jbpmContext.getSession().flush();
long processInstanceId = processInstance.getId();
_jbpmContext.close();
// Reopen the session and continue the execution.
_jbpmContext = JbpmConfiguration.getInstance().createJbpmContext();
processInstance = _jbpmContext.loadProcessInstance(processInstanceId);
processInstance.signal();
assertFalse(processInstance.hasEnded());
processInstance.getContextInstance().setVariable("bytes", new byte[] {1, 2, 3, 4});
processInstance.signal();
assertTrue(processInstance.hasEnded());
_jbpmContext.save(processInstance);
_jbpmContext.close();
_jbpmContext = JbpmConfiguration.getInstance().createJbpmContext();
// Assure that the log entries are really persisted.
assertTrue(0 < getRecordCount("JBPM_LOG"));
// Delete the process instance.
_jbpmContext.getGraphSession().deleteProcessInstance(processInstanceId);
// Assure that the watched tables are empty.
assertEquals(0, getRecordCount("JBPM_VARIABLEINSTANCE"));
assertEquals(0, getRecordCount("JBPM_LOG"));
assertEquals(0, getRecordCount("JBPM_BYTEBLOCK"));
assertEquals(0, getRecordCount("JBPM_BYTEARRAY"));
}
private int getRecordCount(String pTableName) throws HibernateException, SQLException {
Statement stmt = null;
ResultSet rs = null;
try {
stmt = _jbpmContext.getSession().connection().createStatement();
String sql = "SELECT count(*) FROM " + pTableName;
rs = stmt.executeQuery(sql);
rs.next();
return rs.getInt(1);
} finally {
if (rs != null) {
rs.close();
}
if (stmt != null) {
stmt.close();
}
}
}
}
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://jira.jboss.com/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
19 years, 1 month