[jboss-cvs] JBossAS SVN: r60265 - branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/sso.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Sun Feb 4 12:55:29 EST 2007
Author: bstansberry at jboss.com
Date: 2007-02-04 12:55:29 -0500 (Sun, 04 Feb 2007)
New Revision: 60265
Modified:
branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/sso/TreeCacheSSOClusterManager.java
Log:
[JBAS-3721] Clean up SSO entries if a server crashes
Modified: branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/sso/TreeCacheSSOClusterManager.java
===================================================================
--- branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/sso/TreeCacheSSOClusterManager.java 2007-02-04 17:51:13 UTC (rev 60264)
+++ branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/sso/TreeCacheSSOClusterManager.java 2007-02-04 17:55:29 UTC (rev 60265)
@@ -96,6 +96,12 @@
JBossWeb.DEFAULT_CACHE_NAME;
/**
+ * Default global value for the threadPoolName property
+ */
+ public static final String DEFAULT_THREAD_POOL_NAME =
+ "jboss.system:service=ThreadPool";
+
+ /**
* Parameter signature used for TreeCache.get calls over JMX
*/
private static final String[] GET_SIGNATURE =
@@ -146,10 +152,9 @@
*/
private ObjectName cacheObjectName = null;
-// DISABLED UNTIL 4.0.6.CR1
-// private String threadPoolName = "jboss.system:service=ThreadPool";
-//
-// private ThreadPool threadPool;
+ private String threadPoolName = DEFAULT_THREAD_POOL_NAME;
+
+ private ThreadPool threadPool;
/**
* String version of the object name to use to access the TreeCache
@@ -206,13 +211,14 @@
*/
private Serializable localAddress = null;
-// DISABLED UNTIL 4.0.6.CR1
-// /** The last view passed to viewAccepted() */
-// private View currentView;
-//
-// /** Mutex lock to ensure only one view change at a time is being processed */
-// private Object cleanupMutex = new Object();
+ /** The members of the last view passed to viewChange() */
+ private Set currentView;
+ /** Mutex lock to ensure only one view change at a time is being processed */
+ private Object cleanupMutex = new Object();
+
+ private boolean checkForInvalidAddresses = false;
+
// ---------------------------------------------------------- Constructors
@@ -298,25 +304,29 @@
}
}
-// DISABLED UNTIL 4.0.6.CR1
-// public String getThreadPoolName()
-// {
-// return threadPoolName;
-// }
-//
-//
-// public void setThreadPoolName(String threadPoolName)
-// {
-// if (started)
-// {
-// log.info("Call to setThreadPoolName() ignored; already started");
-// }
-// else
-// {
-// this.threadPoolName = threadPoolName;
-// }
-// }
+ public String getThreadPoolName()
+ {
+ return threadPoolName;
+ }
+
+
+ public void setThreadPoolName(String threadPoolName)
+ {
+ if (started)
+ {
+ log.info("Call to setThreadPoolName() ignored; already started");
+ }
+ else
+ {
+ this.threadPoolName = threadPoolName;
+ }
+ }
+ public boolean isUsingThreadPool()
+ {
+ return threadPool != null;
+ }
+
// ----------------------------------------------------- SSOClusterManager
@@ -363,6 +373,11 @@
Set sessions = getSessionSet(fqn, true, false);
sessions.add(new SessionAddress(session.getId(), localAddress));
+
+ if (checkForInvalidAddresses)
+ {
+ cleanDeadMembers(sessions, new HashSet(currentView));
+ }
putInTreeCache(fqn, sessions, false);
}
catch (Exception e)
@@ -580,20 +595,13 @@
sessions.size() + " sessions remain");
}
-// if (sessions.size() == 0)
-// {
-// // No sessions left; remove node
-//
-// // Add this SSO to our list of in-process local removals so
-// // this.nodeRemoved() will ignore the removal
-// removing = true;
-// beingLocallyRemoved.set(ssoId);
-// removeFromTreeCache(getSingleSignOnFqn(ssoId));
-// }
-// else
-// {
- putInTreeCache(fqn, sessions, false);
-// }
+
+ if (checkForInvalidAddresses)
+ {
+ cleanDeadMembers(sessions, new HashSet(currentView));
+ }
+ putInTreeCache(fqn, sessions, false);
+
}
}
catch (Exception e)
@@ -613,18 +621,8 @@
}
finally
{
-// try
-// {
-// if (removing)
-// {
-// beingLocallyRemoved.set(null);
-// }
-// }
-// finally
-// {
- if (doTx)
- endTransaction();
-// }
+ if (doTx)
+ endTransaction();
}
}
@@ -756,14 +754,11 @@
}
// Put this SSO in the queue of those to be updated
-// credentialUpdater.enqueue(sso, ssoId);
try
{
SSOCredentials data = (SSOCredentials) getFromTreeCache(fqn, false);
if (data != null)
{
- // We want to release our read lock quickly, so get the needed
- // data from the cache, commit the tx, and then use the data
String authType = data.getAuthType();
String username = data.getUsername();
String password = data.getPassword();
@@ -821,57 +816,49 @@
}
}
-// DISABLE UNTIL 4.0.6.CR1
-// /**
-// * If any nodes have been removed from the view, asynchronously scans
-// * all SSOs looking for and removing sessions owned by the removed node.
-// * Notifies the SSO valve if as a result any SSOs no longer have active
-// * sessions. If the removed node is the one associated with this object,
-// * does nothing.
-// */
-// public void viewChange(View new_view)
-// {
-// if (currentView == null)
-// {
-// currentView = new_view;
-// return;
-// }
-//
-// Vector oldMembers = currentView.getMembers();
-//
-// currentView = new_view;
-//
-// // If we're not in the view, just exit
-// if (localAddress == null || !currentView.containsMember((Address) localAddress))
-// return;
-//
-// boolean hasDeadMembers = false;
-// for (Iterator iter = oldMembers.iterator(); iter.hasNext(); )
-// {
-// Address member = (Address) iter.next();
-// if (!new_view.containsMember(member))
-// {
-// hasDeadMembers = true;
-// break;
-// }
-// }
-//
-// if (hasDeadMembers)
-// {
-// DeadMemberCleaner cleaner = new DeadMemberCleaner();
-// if (threadPool != null)
-// {
-// threadPool.run(cleaner);
-// }
-// else
-// {
-// Thread t = new Thread(cleaner, "ClusteredSSOCleaner");
-// t.setDaemon(true);
-// t.start();
-// }
-// }
-//
-// }
+ /**
+ * If any nodes have been removed from the view, asynchronously scans
+ * all SSOs looking for and removing sessions owned by the removed node.
+ * Notifies the SSO valve if as a result any SSOs no longer have active
+ * sessions. If the removed node is the one associated with this object,
+ * does nothing.
+ */
+ public synchronized void viewChange(View new_view)
+ {
+ Set oldMembers = currentView;
+ currentView = new HashSet(new_view.getMembers());
+
+ if (oldMembers == null)
+ return; // we must not be started yet
+
+ // If we're not in the view, just exit
+ if (localAddress == null || !currentView.contains((Address) localAddress))
+ return;
+
+ // Remove all the current members from the old set; any left
+ // are the dead members
+ oldMembers.removeAll(currentView);
+
+ if (oldMembers.size() > 0)
+ {
+ // Inform threads updating our SSOs to check for dead members so
+ // we don't replicate a dead member and thus override another
+ // node's cleanup work
+ this.checkForInvalidAddresses = true;
+ DeadMemberCleaner cleaner = new DeadMemberCleaner();
+ if (threadPool != null)
+ {
+ threadPool.run(cleaner);
+ }
+ else
+ {
+ Thread t = new Thread(cleaner, "ClusteredSSOCleaner");
+ t.setDaemon(true);
+ t.start();
+ }
+ }
+
+ }
// ------------------------------------------------------------- Lifecycle
@@ -938,8 +925,7 @@
"TransactionManager from TreeCache", e);
}
-// DISABLED UNTIL 4.0.6.CR1
-// initThreadPool();
+ initThreadPool();
started = true;
@@ -981,14 +967,13 @@
return server.invoke(getCacheObjectName(), "get", args, GET_SIGNATURE);
}
-// DISABLED UNTIL 4.0.6.CR1
-// private Set getSSOIds() throws Exception
-// {
-// Fqn ssoRoot = new Fqn(new Object[] {SSO});
-// return (Set) server.invoke(getCacheObjectName(), "getChildrenNames",
-// new Object[]{ ssoRoot },
-// new String[]{ Fqn.class.getName() });
-// }
+ private Set getSSOIds() throws Exception
+ {
+ Fqn ssoRoot = new Fqn(new Object[] {SSO});
+ return (Set) server.invoke(getCacheObjectName(), "getChildrenNames",
+ new Object[]{ ssoRoot },
+ new String[]{ Fqn.class.getName() });
+ }
private Fqn getCredentialsFqn(String ssoid)
{
@@ -1081,6 +1066,12 @@
localAddress = (Serializable) address;
else
localAddress = address.toString();
+
+ // Get the currentView
+ Vector members = (Vector) server.getAttribute(getCacheObjectName(),
+ "Members");
+ if (members != null)
+ currentView = new HashSet(members);
}
@@ -1261,23 +1252,29 @@
REMOVE_SIGNATURE);
}
-// DISABLED UNTIL 4.0.6.CR1
-// private void initThreadPool()
-// {
-// if (threadPoolName != null)
-// {
-// try
-// {
-// ObjectName on = new ObjectName(threadPoolName);
-// threadPool = (ThreadPool) MBeanProxyExt.create(ThreadPoolMBean.class, on);
-// }
-// catch (Exception e)
-// {
-// log.info("Unable to access ThreadPool at " + threadPoolName +
-// " -- will use individual threads for cleanup work");
-// }
-// }
-// }
+ private void initThreadPool()
+ {
+ if (threadPoolName != null)
+ {
+ try
+ {
+ ObjectName on = new ObjectName(threadPoolName);
+ ThreadPoolMBean mbean = (ThreadPoolMBean) MBeanProxyExt.create(ThreadPoolMBean.class, on, server);
+ threadPool = mbean.getInstance();
+ log.debug("Using ThreadPool at " + threadPoolName + " to clean dead members");
+ }
+ catch (Exception e)
+ {
+ log.info("Unable to access ThreadPool at " + threadPoolName +
+ " -- will use individual threads for cleanup work");
+ log.debug("Failure to access ThreadPool due to: " + e);
+ }
+ }
+ else
+ {
+ log.debug("No ThreadPool configured -- will use individual threads for cleanup work");
+ }
+ }
/**
* Stores the given data to the clustered cache in a tree branch whose FQN
@@ -1348,6 +1345,27 @@
setMissingCacheErrorLogged(true);
}
}
+
+ private static boolean cleanDeadMembers(Set sessionSet, Set currentMembers)
+ {
+ boolean changed = false;
+ synchronized (sessionSet)
+ {
+ for (Iterator iter = sessionSet.iterator(); iter.hasNext(); )
+ {
+ Object obj = iter.next();
+ if (obj instanceof SessionAddress)
+ {
+ if (!currentMembers.contains(((SessionAddress) obj).address))
+ {
+ iter.remove();
+ changed = true;
+ }
+ }
+ }
+ }
+ return changed;
+ }
// --------------------------------------------------------- Outer Classes
@@ -1451,97 +1469,92 @@
}
-// DISABLED UNTIL 4.0.6.CR1
-// /**
-// * Runnable that's run when the removal of a node from the cluster has been detected.
-// * Removes any SessionAddress objects associated with dead members from the
-// * session set of each SSO. Operates locally only so each node can independently clean
-// * its SSOs without concern about replication lock conflicts.
-// */
-// private class DeadMemberCleaner implements Runnable
-// {
-// public void run()
-// {
-// synchronized (cleanupMutex)
-// {
-// try
-// {
-// // Ensure we have a TransactionManager
-// if (tm == null)
-// configureFromCache();
-//
-// Set ids = getSSOIds();
-//
-// for (Iterator iter = ids.iterator(); iter.hasNext();)
-// {
-// cleanDeadMembersFromSSO((String) iter.next());
-//
-// }
-// }
-// catch (Exception e)
-// {
-// log.error("Caught exception cleaning sessions from dead cluster members from SSOs ", e);
-// }
-// }
-// }
-//
-// private void cleanDeadMembersFromSSO(String ssoId)
-// {
-// Fqn fqn = getSessionsFqn(ssoId);
-// boolean doTx = false;
-// try
-// {
-// // Don't start tx if there is already one associated with this thread.
-// if(tm.getTransaction() == null)
-// doTx = true;
-//
-// if(doTx)
-// tm.begin();
-//
-// Set sessions = getSessionSet(fqn, false, true);
-// if (sessions != null && sessions.size() > 0)
-// {
-// boolean changed = false;
-// for (Iterator iter = sessions.iterator(); iter.hasNext();)
-// {
-// SessionAddress session = (SessionAddress) iter.next();
-// if (!currentView.containsMember((Address) session.address))
-// {
-// iter.remove();
-// changed = true;
-// }
-// }
-//
-// if (changed)
-// {
-// if (sessions.size() == 0)
-// {
-// ssoValve.notifySSOEmpty(ssoId);
-// }
-//
-// putInTreeCache(fqn, sessions, true);
-// }
-// }
-// }
-// catch (Exception e)
-// {
-// try
-// {
-// if(doTx)
-// tm.setRollbackOnly();
-// }
-// catch (Exception ignored)
-// {
-// }
-// log.error("caught exception cleaning dead members from SSO " + ssoId, e);
-// }
-// finally
-// {
-// if (doTx)
-// endTransaction();
-// }
-// }
-// }
+ /**
+ * Runnable that's run when the removal of a node from the cluster has been detected.
+ * Removes any SessionAddress objects associated with dead members from the
+ * session set of each SSO. Operates locally only so each node can independently clean
+ * its SSOs without concern about replication lock conflicts.
+ */
+ private class DeadMemberCleaner implements Runnable
+ {
+ public void run()
+ {
+ synchronized (cleanupMutex)
+ {
+ try
+ {
+ // Ensure we have a TransactionManager
+ if (tm == null)
+ configureFromCache();
+
+ Set ids = getSSOIds();
+ // Copy off the currentView
+ Set members = new HashSet(currentView);
+ for (Iterator iter = ids.iterator(); iter.hasNext();)
+ {
+ cleanDeadMembersFromSSO((String) iter.next(), members);
+ }
+
+ // We've cleaned up; no need for other threads to help
+ checkForInvalidAddresses = false;
+ }
+ catch (Exception e)
+ {
+ log.error("Caught exception cleaning sessions from dead cluster members from SSOs ", e);
+ }
+ }
+ }
+
+ private void cleanDeadMembersFromSSO(String ssoId, Set currentMembers)
+ {
+ Fqn fqn = getSessionsFqn(ssoId);
+ boolean doTx = false;
+ try
+ {
+ // Don't start tx if there is already one associated with this thread.
+ if(tm.getTransaction() == null)
+ doTx = true;
+ if(doTx)
+ tm.begin();
+
+ Set sessions = getSessionSet(fqn, false, true);
+ if (sessions != null && sessions.size() > 0)
+ {
+ boolean changed = cleanDeadMembers(sessions, currentMembers);
+
+ if (changed)
+ {
+ if (sessions.size() == 0)
+ {
+ ssoValve.notifySSOEmpty(ssoId);
+ }
+
+ // Don't bother with the local-onlyput; we have a lock on the node
+ // from the get and the cached data is a ref to the set we just changed
+ //putInTreeCache(fqn, sessions, true);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ try
+ {
+ if(doTx)
+ tm.setRollbackOnly();
+ }
+ catch (Exception ignored)
+ {
+ }
+ log.error("caught exception cleaning dead members from SSO " + ssoId, e);
+ }
+ finally
+ {
+ if (doTx)
+ endTransaction();
+ }
+ }
+ }
+
} // end TreeCacheSSOClusterManager
More information about the jboss-cvs-commits
mailing list