User: danch Date: 01/06/18 07:34:27 Modified: src/main/org/jboss/ejb/plugins/jaws/jdbc JDBCCommand.java JDBCCommandFactory.java JDBCFindByCommand.java JDBCFindEntitiesCommand.java Log: Use SoftReferences for the preloaded data; also, patch #418196 (creating finders of nested CMP-fields) Revision Changes Path 1.33 +2 -2 jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCCommand.java Index: JDBCCommand.java =================================================================== RCS file: /cvsroot/jboss/jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCCommand.java,v retrieving revision 1.32 retrieving revision 1.33 diff -u -r1.32 -r1.33 --- JDBCCommand.java 2001/06/06 01:07:40 1.32 +++ JDBCCommand.java 2001/06/18 14:34:27 1.33 @@ -57,7 +57,7 @@ * * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a> * @author <a href="mailto:[EMAIL PROTECTED]">Dirk Zimmermann</a> - * @version $Revision: 1.32 $ + * @version $Revision: 1.33 $ */ public abstract class JDBCCommand { @@ -386,7 +386,7 @@ protected Object getResultObject(ResultSet rs, int idx, Class destination) throws SQLException{ -log.debug("getting a "+destination.getName()+" from resultset at index "+idx); +// log.debug("getting a "+destination.getName()+" from resultset at index "+idx); Object result = null; Method method = (Method)rsTypes.get(destination.getName()); 1.10 +142 -58 jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCCommandFactory.java Index: JDBCCommandFactory.java =================================================================== RCS file: /cvsroot/jboss/jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCCommandFactory.java,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- JDBCCommandFactory.java 2001/06/13 06:52:17 1.9 +++ JDBCCommandFactory.java 2001/06/18 14:34:27 1.10 @@ -8,11 +8,15 @@ package org.jboss.ejb.plugins.jaws.jdbc; import java.lang.reflect.Method; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; +import java.lang.ref.ReferenceQueue; import java.util.Map; import java.util.HashMap; import java.util.List; import java.util.LinkedList; import java.util.Iterator; +import java.util.WeakHashMap; import javax.naming.Context; import javax.naming.InitialContext; @@ -46,13 +50,25 @@ import org.jboss.logging.Log; import org.jboss.util.FinderResults; +import org.jboss.util.TimerTask; +import org.jboss.util.TimerQueue; /** - * JAWSPersistenceManager JDBCCommandFactory + * Command factory for the JAWS JDBC layer. This class is primarily responsible + * for creating instances of the JDBC implementations for the various JPM + * commands so that the JAWSPersistenceManager (actually an persistence store) + * can delegate to them in a decoupled manner. + * <p>This class also acts as the manager for the read-ahead buffer added in + * version 2.3/2.4. In order to manage this buffer, it must register itself + * with any transaction that is active when a finder is called so that the + * data that was read ahead can be discarded before completion of the + * transaction. The read ahead buffer is managed using Soft references, with + * a ReferenceQueue being used to tell when the VM has garbage collected an + * object so that we can keep the hashtables clean. * * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a> * @author <a href="[EMAIL PROTECTED]">danch (Dan Christopherson</a> - * @version $Revision: 1.9 $ + * @version $Revision: 1.10 $ */ public class JDBCCommandFactory implements JPMCommandFactory { @@ -63,7 +79,15 @@ private JawsEntityMetaData metadata; private Log log; private boolean debug = false; + + /** Timer queue used to time polls on the preloadRefQueue on all JAWS + * handled entities + */ + private static TimerQueue softRefHandler; + /** Timer queue used to get references to preload data who've been GC'ed */ + private ReferenceQueue preloadRefQueue = new ReferenceQueue(); + /** a map of data preloaded within some transaction for some entity. This map * is keyed by Transaction and the data are hashmaps with key = entityKey and * data = Object[] containing the entity data. @@ -81,7 +105,13 @@ // These support singletons (within the scope of this factory) private JDBCBeanExistsCommand beanExistsCommand; private JPMFindEntitiesCommand findEntitiesCommand; - + + //static initializer to kick off our softRefhandler + static { + softRefHandler = new TimerQueue("JAWS Preload reference handler"); + softRefHandler.start(); + } + // Constructors -------------------------------------------------- public JDBCCommandFactory(EntityContainer container, @@ -93,24 +123,26 @@ this.javaCtx = (Context)new InitialContext().lookup("java:comp/env"); - String ejbName = container.getBeanMetaData().getEjbName(); - ApplicationMetaData amd = container.getBeanMetaData().getApplicationMetaData(); - JawsApplicationMetaData jamd = (JawsApplicationMetaData)amd.getPluginData("JAWS"); - - if (jamd == null) { - // we are the first cmp entity to need jaws. Load jaws.xml for the whole application - JawsXmlFileLoader jfl = new JawsXmlFileLoader(amd, container.getClassLoader(), container.getLocalClassLoader(), log); - jamd = jfl.load(); - amd.addPluginData("JAWS", jamd); - } - debug = jamd.getDebug(); - - metadata = jamd.getBeanByEjbName(ejbName); - if (metadata == null) { - throw new DeploymentException("No metadata found for bean " + ejbName); - } + String ejbName = container.getBeanMetaData().getEjbName(); + ApplicationMetaData amd = container.getBeanMetaData().getApplicationMetaData(); + JawsApplicationMetaData jamd = (JawsApplicationMetaData)amd.getPluginData("JAWS"); + + if (jamd == null) { + // we are the first cmp entity to need jaws. Load jaws.xml for the whole application + JawsXmlFileLoader jfl = new JawsXmlFileLoader(amd, container.getClassLoader(), container.getLocalClassLoader(), log); + jamd = jfl.load(); + amd.addPluginData("JAWS", jamd); + } + debug = jamd.getDebug(); + + metadata = jamd.getBeanByEjbName(ejbName); + if (metadata == null) { + throw new DeploymentException("No metadata found for bean " + ejbName); + } + + tm = (TransactionManager) container.getTransactionManager(); - tm = (TransactionManager) container.getTransactionManager(); + softRefHandler.schedule(new PreloadRefQueueHandlerTask(), 50); } // Public -------------------------------------------------------- @@ -262,10 +294,10 @@ try { trans = tm.getTransaction(); } catch (javax.transaction.SystemException sysE) { - log.warning("System exception getting transaction for preload - can't get preloaded data for "+entityKey); + log.warning("System exception getting transaction for preload - can't preload data for "+entityKey); return; } -//log.debug("PRELOAD: adding preload for "+entityKey+" in transaction "+(trans != null ? trans.toString() : "NONE")); +//log.debug("PRELOAD: adding preload for "+entityKey+" in transaction "+(trans != null ? trans.toString() : "NONE")+" entityData="+entityData); if (trans != null) { synchronized (preloadedData) { @@ -283,11 +315,13 @@ entitiesInTransaction = new HashMap(); preloadedData.put(trans, entitiesInTransaction); } - entitiesInTransaction.put(entityKey, entityData); + PreloadData preloadData = new PreloadData(trans, entityKey, entityData, preloadRefQueue); + entitiesInTransaction.put(entityKey, preloadData); } } else { synchronized (nonTransactionalPreloadData) { - nonTransactionalPreloadData.put(entityKey, entityData); + PreloadData preloadData = new PreloadData(null, entityKey, entityData, preloadRefQueue); + nonTransactionalPreloadData.put(entityKey, preloadData); } } } @@ -306,19 +340,36 @@ } Object[] result = null; + PreloadData preloadData = null; if (trans != null) { - synchronized (preloadedData) { - Map entitiesInTransaction = (Map)preloadedData.get(trans); - if (entitiesInTransaction != null) - result = (Object[])entitiesInTransaction.get(entityKey); - //remove it now? + Map entitiesInTransaction = null; + // Do we really need this to be syncrhonized? What is the effect of + // another thread trying to modify this map? It won't be to remove + // our transaction (we're in it here!, trying to call a business + // method), and who cares if another is added/removed? +// synchronized (preloadedData) { + entitiesInTransaction = (Map)preloadedData.get(trans); +// } + if (entitiesInTransaction != null) { + synchronized (entitiesInTransaction) { + preloadData = (PreloadData)entitiesInTransaction.get(entityKey); + entitiesInTransaction.remove(entityKey); + } } } else { synchronized (nonTransactionalPreloadData) { - result = (Object[])nonTransactionalPreloadData.get(entityKey); + preloadData = (PreloadData)nonTransactionalPreloadData.get(entityKey); + nonTransactionalPreloadData.remove(entityKey); } } -//log.debug("PRELOAD: returning "+result+" as preload for "+entityKey); + if (preloadData != null) { + result = preloadData.getData(); + } /*else { + log.debug("PRELOAD: preloadData == null for "+entityKey); + } +if (result == null) + log.debug("PRELOAD: returning null as preload for "+entityKey); + */ return result; } @@ -333,38 +384,71 @@ // Private ------------------------------------------------------- - /** an inner class used to key the FinderResults by their finder method and - * the transaction they're invoked within + + /** Inner class that handles our reference queue. I didn't think this would + * be neccessary, but for some reason the VM won't call an override of + * Reference.clear() + */ + private class PreloadRefQueueHandlerTask extends TimerTask { + public void execute() throws Exception { + PreloadData preloadData = (PreloadData)preloadRefQueue.poll(); + int handled = 0; + while (preloadData != null && handled < 10) { + log.debug("PRELOAD: clearing "+preloadData.getKey()); + if (preloadData.getTransaction() != null) { + Map entitiesInTransaction = null; + // Do we really need this to be syncrhonized? What is the effect of + // another thread trying to modify this map? It won't be to remove + // our transaction (we're in it here!, trying to call a business + // method), and who cares if another is added/removed? + // synchronized (preloadedData) { + entitiesInTransaction = (Map)preloadedData.get(preloadData.getTransaction()); + // } + if (entitiesInTransaction != null) { + synchronized (entitiesInTransaction) { + entitiesInTransaction.remove(preloadData.getKey()); + } + } + } else { + synchronized (nonTransactionalPreloadData) { + nonTransactionalPreloadData.remove(preloadData.getKey()); + } + } + preloadData.empty(); + handled++; + + preloadData = (PreloadData)preloadRefQueue.poll(); + } + } + } + /** Inner class used in the preload Data hashmaps so that we can wrap a + * SoftReference around the data and still have enough information to remove + * the reference from the appropriate hashMap. */ - private static class PreloadDataKey { - private Object entityKey; - private Transaction transaction; - - private int hashCode; + private class PreloadData extends SoftReference { + private Object key; + private Transaction trans; - public PreloadDataKey(Object entityKey, Transaction transaction) { - this.entityKey = entityKey; - this.transaction = transaction; - - //accumulate the hashcode. - /** @todo investigate ways of combining these that will give the least collisions */ - this.hashCode = entityKey.hashCode(); - if (transaction != null) - this.hashCode += transaction.hashCode(); + PreloadData(Transaction trans, Object key, Object[] data, ReferenceQueue queue) { + super(data, queue); + this.trans = trans; + this.key = key; } - public int hashCode() { - return hashCode; + Transaction getTransaction() { + return trans; } - public boolean equals(Object o) { - if (o instanceof PreloadDataKey) { - PreloadDataKey other = (PreloadDataKey)o; - return (other.entityKey.equals(this.entityKey)) && - ( (other.transaction == null && this.transaction == null) || - ( (other.transaction != null && this.transaction != null) && - (other.transaction.equals(this.transaction)) ) ); - } - return false; + Object getKey() { + return key; + } + Object[] getData() { + return (Object[])get(); + } + + /** Named empty to not collide with superclass clear */ + public void empty() { + key = null; + trans = null; } } 1.10 +5 -2 jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCFindByCommand.java Index: JDBCFindByCommand.java =================================================================== RCS file: /cvsroot/jboss/jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCFindByCommand.java,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- JDBCFindByCommand.java 2001/06/13 06:52:17 1.9 +++ JDBCFindByCommand.java 2001/06/18 14:34:27 1.10 @@ -27,7 +27,8 @@ * @author <a href="mailto:[EMAIL PROTECTED]">Joe Shevland</a> * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a> * @author <a href="mailto:[EMAIL PROTECTED]">danch (Dan Christopherson)</a> - * @version $Revision: 1.9 $ + * @author <a href="mailto:[EMAIL PROTECTED]">Torben Jäger</a> + * @version $Revision: 1.10 $ */ public class JDBCFindByCommand extends JDBCFinderCommand { @@ -55,7 +56,9 @@ { CMPFieldMetaData fi = (CMPFieldMetaData)iter.next(); - if (cmpFieldName.equals(fi.getName().toLowerCase())) + String lastComponentOfName = + CMPFieldMetaData.getLastComponent(fi.getName()).toLowerCase(); + if (cmpFieldName.equals(lastComponentOfName)) { cmpField = fi; } 1.10 +3 -2 jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCFindEntitiesCommand.java Index: JDBCFindEntitiesCommand.java =================================================================== RCS file: /cvsroot/jboss/jboss/src/main/org/jboss/ejb/plugins/jaws/jdbc/JDBCFindEntitiesCommand.java,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- JDBCFindEntitiesCommand.java 2001/05/27 00:49:15 1.9 +++ JDBCFindEntitiesCommand.java 2001/06/18 14:34:27 1.10 @@ -33,7 +33,7 @@ * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a> * @author <a href="mailto:[EMAIL PROTECTED]">Joe Shevland</a> * @author <a href="mailto:[EMAIL PROTECTED]">Justin Forder</a> - * @version $Revision: 1.9 $ + * @version $Revision: 1.10 $ */ public class JDBCFindEntitiesCommand implements JPMFindEntitiesCommand { @@ -74,7 +74,8 @@ } } } catch (Exception e) { - // for some reason, this failed; try to use defined or automatic instead + // for some reason, this failed; try to use defined or automatic instead + factory.getLog().warning("Error initializing custom finder "+e.getMessage()); } // Make commands for the defined finders _______________________________________________ Jboss-development mailing list [EMAIL PROTECTED] http://lists.sourceforge.net/lists/listinfo/jboss-development