You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pc...@apache.org on 2007/03/10 18:15:53 UTC

svn commit: r516750 - in /incubator/openjpa/trunk: openjpa-kernel/src/main/java/org/apache/openjpa/datacache/ openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/ openj...

Author: pcl
Date: Sat Mar 10 09:15:49 2007
New Revision: 516750

URL: http://svn.apache.org/viewvc?view=rev&rev=516750
Log:
OPENJPA-35: fixed bulk update / bulk delete logic to properly clear out the data cache as well as the query cache. We could probably change the logic to remove the query cache mutations, since the data cache clear should automatically clear out the query cache as needed. Also changed the test framework a bit to allow for easier test harness creation without using SingleEMTest, which required providing access to the open brokers from AbstractBrokerFactory.

Added:
    incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestBulkJPQLAndDataCache.java   (with props)
    incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SingleEMFTest.java   (with props)
Modified:
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java
    incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SingleEMTest.java

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java?view=diff&rev=516750&r1=516749&r2=516750
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java Sat Mar 10 09:15:49 2007
@@ -19,7 +19,6 @@
 import java.io.Serializable;
 import java.util.AbstractList;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.BitSet;
 import java.util.Collections;
 import java.util.Date;
@@ -112,7 +111,7 @@
         if (fetch.getReadLockLevel() > LockLevels.LOCK_NONE)
             return null;
 
-        // get the cached oids
+        // get the cached data
         QueryResult res = _cache.get(qk);
         if (res == null)
             return null;
@@ -123,7 +122,7 @@
         if (projs == 0) {
             // make sure the data cache contains the oids for the query result;
             // if it doesn't, then using the result could be slower than not
-            // using it becauseo of the individual by-oid lookups
+            // using it because of the individual by-oid lookups
             ClassMetaData meta = _repos.getMetaData(getContext().
                 getCandidateType(), _sctx.getClassLoader(), true);
             BitSet idxs = meta.getDataCache().containsAll(res);
@@ -313,7 +312,7 @@
          * (such as deletes or updates) are performed so that the
          * cache remains up-to-date.
          */
-        private void clearAccesssPath(StoreQuery q) {
+        private void clearAccessPath(StoreQuery q) {
             if (q == null)
                 return;
 
@@ -321,20 +320,26 @@
             if (cmd == null || cmd.length == 0)
                 return;
 
-            Class[] classes = new Class[cmd.length];
+            List classes = new ArrayList(cmd.length);
             for (int i = 0; i < cmd.length; i++)
-                classes[i] = cmd[i].getDescribedType();
+                classes.add(cmd[i].getDescribedType());
 
+            // evict from the query cache
             QueryCacheStoreQuery cq = (QueryCacheStoreQuery) q;
             cq.getCache().onTypesChanged(new TypesChangedEvent
-                (q.getContext(), Arrays.asList(classes)));
+                (q.getContext(), classes));
+
+            // evict from the data cache
+            for (int i = 0; i < cmd.length; i++)
+                cmd[i].getDataCache().removeAll(
+                    cmd[i].getDescribedType(), true);
         }
 
         public Number executeDelete(StoreQuery q, Object[] params) {
             try {
                 return _ex.executeDelete(unwrap(q), params);
             } finally {
-                clearAccesssPath(q);
+                clearAccessPath(q);
             }
         }
 
@@ -342,7 +347,7 @@
             try {
                 return _ex.executeUpdate(unwrap(q), params);
             } finally {
-                clearAccesssPath(q);
+                clearAccessPath(q);
             }
         }
 

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java?view=diff&rev=516750&r1=516749&r2=516750
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java Sat Mar 10 09:15:49 2007
@@ -646,6 +646,14 @@
     }
 
     /**
+     * Returns a set of all the open brokers associated with this factory. The
+     * returned set is unmodifiable, and may contain null references.
+     */
+    public Collection getOpenBrokers() {
+        return Collections.unmodifiableCollection(_brokers);
+    }
+
+    /**
      * Simple synchronization listener to remove completed transactions
      * from our cache.
      */

Added: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestBulkJPQLAndDataCache.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestBulkJPQLAndDataCache.java?view=auto&rev=516750
==============================================================================
--- incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestBulkJPQLAndDataCache.java (added)
+++ incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestBulkJPQLAndDataCache.java Sat Mar 10 09:15:49 2007
@@ -0,0 +1,91 @@
+package org.apache.openjpa.persistence.datacache;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.openjpa.persistence.OpenJPAEntityManager;
+import org.apache.openjpa.persistence.OpenJPAPersistence;
+import org.apache.openjpa.persistence.simple.AllFieldTypes;
+import org.apache.openjpa.persistence.test.SingleEMFTest;
+
+public class TestBulkJPQLAndDataCache
+    extends SingleEMFTest {
+
+    private Object oid;
+
+    public TestBulkJPQLAndDataCache() {
+        super(AllFieldTypes.class);
+    }
+
+    @Override
+    protected boolean clearDatabaseInSetUp() {
+        return true;
+    }
+
+    protected void setEMFProps(Map props) {
+        super.setEMFProps(props);
+        props.put("openjpa.DataCache", "true");
+        props.put("openjpa.RemoteCommitProvider", "sjvm");
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        OpenJPAEntityManager em =
+            OpenJPAPersistence.cast(emf.createEntityManager());
+        em.getTransaction().begin();
+        AllFieldTypes pc = new AllFieldTypes();
+        pc.setStringField("DeleteMe");
+        em.persist(pc);
+        oid = em.getObjectId(pc);
+        em.getTransaction().commit();
+        em.close();
+    }
+
+    public void testBulkDelete() {
+        OpenJPAEntityManager em =
+            OpenJPAPersistence.cast(emf.createEntityManager());
+
+        em.getTransaction().begin();
+        List result = em.createQuery("SELECT o FROM AllFieldTypes o")
+            .getResultList();
+        assertEquals(1, result.size());
+        em.createQuery("DELETE FROM AllFieldTypes o").executeUpdate();
+        em.getTransaction().commit();
+        em.close();
+
+        em = OpenJPAPersistence.cast(emf.createEntityManager());
+
+        // this assumes that we invalidate the cache, rather than update it
+        // according to the bulk rule.
+        assertFalse(OpenJPAPersistence.cast(emf).getStoreCache()
+            .contains(AllFieldTypes.class, oid));
+
+        assertNull(em.find(AllFieldTypes.class, oid));
+        em.close();
+    }
+
+    public void testBulkUpdate() {
+        OpenJPAEntityManager em =
+            OpenJPAPersistence.cast(emf.createEntityManager());
+
+        em.getTransaction().begin();
+        List result = em.createQuery("SELECT o FROM AllFieldTypes o "
+            + "WHERE o.intField = 0").getResultList();
+        assertEquals(1, result.size());
+        em.createQuery("UPDATE AllFieldTypes o SET o.intField = 10")
+            .executeUpdate();
+        em.getTransaction().commit();
+        em.close();
+
+        em = OpenJPAPersistence.cast(emf.createEntityManager());
+
+        // this assumes that we invalidate the cache, rather than update it
+        // according to the bulk rule.
+        assertFalse(OpenJPAPersistence.cast(emf).getStoreCache()
+            .contains(AllFieldTypes.class, oid));
+
+        em.close();
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestBulkJPQLAndDataCache.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SingleEMFTest.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SingleEMFTest.java?view=auto&rev=516750
==============================================================================
--- incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SingleEMFTest.java (added)
+++ incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SingleEMFTest.java Sat Mar 10 09:15:49 2007
@@ -0,0 +1,106 @@
+package org.apache.openjpa.persistence.test;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+import javax.persistence.EntityManager;
+
+import junit.framework.TestCase;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactory;
+import org.apache.openjpa.persistence.OpenJPAPersistence;
+import org.apache.openjpa.kernel.AbstractBrokerFactory;
+import org.apache.openjpa.kernel.Broker;
+
+public abstract class SingleEMFTest extends TestCase {
+
+    protected EntityManagerFactory emf;
+    protected Class[] classes;
+
+    public SingleEMFTest(Class... classes) {
+        this.classes = classes;
+    }
+
+    /**
+     * Can be overridden to return a list of classes that will be used
+     * for this test.
+     */
+    protected Class[] getClasses() {
+        return classes;
+    }
+
+    /**
+     * Modify the properties that are used to create the EntityManagerFactory.
+     * By default, this will set up the MetaDataFactory with the
+     * persistent classes for this test case. This method can be overridden
+     * to add more properties to the map.
+     */
+    protected void setEMFProps(Map props) {
+        // if we have specified a list of persistent classes to examine,
+        // then set it in the MetaDataFactory so that our automatic
+        // schema generation will work.
+        Class[] pclasses = getClasses();
+        if (pclasses != null) {
+            StringBuilder str = new StringBuilder();
+            for (Class c : pclasses)
+                str.append(str.length() > 0 ? ";" : "").append(c.getName());
+
+            props.put("openjpa.MetaDataFactory", "jpa(Types=" + str + ")");
+        }
+
+        if (clearDatabaseInSetUp()) {
+            props.put("openjpa.jdbc.SynchronizeMappings",
+                "buildSchema(ForeignKeys=true," +
+                    "SchemaAction='add,deleteTableContents')");
+        }
+    }
+
+    protected boolean clearDatabaseInSetUp() {
+        return false;
+    }
+
+    public EntityManagerFactory emf() {
+        return emf;
+    }
+
+    public boolean closeEMF() {
+        if (emf == null)
+            return false;
+
+        if (!emf.isOpen())
+            return false;
+
+        for (Iterator iter = ((AbstractBrokerFactory) OpenJPAPersistence
+            .toBrokerFactory(emf)).getOpenBrokers().iterator();
+            iter.hasNext(); ) {
+            Broker b = (Broker) iter.next();
+            if (b != null && !b.isClosed()) {
+                EntityManager em = OpenJPAPersistence.toEntityManager(b);
+                if (em.getTransaction().isActive())
+                    em.getTransaction().rollback();
+                em.close();
+            }
+        }
+
+        emf.close();
+        return !emf.isOpen();
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        Map props = new HashMap(System.getProperties());
+        setEMFProps(props);
+        emf = Persistence.createEntityManagerFactory("test", props);
+
+        if (clearDatabaseInSetUp()) // get an EM to trigger schema manipulations
+            emf.createEntityManager().close();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        closeEMF();
+        super.tearDown();
+    }
+}
\ No newline at end of file

Propchange: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SingleEMFTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SingleEMTest.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SingleEMTest.java?view=diff&rev=516750&r1=516749&r2=516750
==============================================================================
--- incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SingleEMTest.java (original)
+++ incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SingleEMTest.java Sat Mar 10 09:15:49 2007
@@ -19,84 +19,31 @@
 
 import javax.persistence.*;
 
-import junit.framework.TestCase;
-import junit.textui.TestRunner;
-import org.apache.openjpa.persistence.*;
-
 /**
  * A base test case that can be used to easily test scenarios where there
  * is only a single EntityManager at any given time.
  *
  * @author Marc Prud'hommeaux
  */
-public abstract class SingleEMTest extends TestCase {
+public abstract class SingleEMTest extends SingleEMFTest {
 
-    protected EntityManagerFactory emf;
     protected EntityManager em;
-    protected Class[] classes;
 
     public SingleEMTest(Class... classes) {
-        this.classes = classes;
-    }
-
-    /** 
-     * Can be overridden to return a list of classes that will be used
-     * for this test.
-     */
-    protected Class[] getClasses() { 
-        return classes;
-    }
-
-    /** 
-     * Modify the properties that are used to create the EntityManagerFactory.
-     * By default, this will set up the MetaDataFactory with the
-     * persistent classes for this test case. This method can be overridden
-     * to add more properties to the map.
-     */
-    protected void setEMFProps(Map props) {
-        // if we have specified a list of persistent classes to examine,
-        // then set it in the MetaDataFactory so that our automatic
-        // schema generation will work.
-        Class[] pclasses = getClasses();
-        if (pclasses != null) {
-            StringBuilder str = new StringBuilder();
-            for (Class c : pclasses)
-                str.append(str.length() > 0 ? ";" : "").append(c.getName());
-
-            props.put("openjpa.MetaDataFactory", "jpa(Types=" + str + ")");
-        }
-
-        if (clearDatabaseInSetUp()) {
-            props.put("openjpa.jdbc.SynchronizeMappings",
-                "buildSchema(ForeignKeys=true," +
-                    "SchemaAction='add,deleteTableContents')");
-        }
+        super(classes);
     }
 
-    protected boolean clearDatabaseInSetUp() {
-        return false;
-    }
-
-    public void setUp() throws Exception {
-        Map props = new HashMap(System.getProperties());
-        setEMFProps(props);
-        emf = Persistence.createEntityManagerFactory("test", props);
-    }
-
-    /** 
+    /**
      * Rolls back the current transaction and closes the EntityManager. 
      */
+    @Override
     public void tearDown() throws Exception {
         rollback();
         close();
-        closeEMF();
+        super.tearDown();
     }
 
-    public EntityManagerFactory emf() {
-        return emf;
-    }
-
-    /** 
+    /**
      * Returns the current EntityManager, creating one from the
      * EntityManagerFactory if it doesn't already exist. 
      */
@@ -164,17 +111,10 @@
         return !em.isOpen();
     }
 
+    @Override
     public boolean closeEMF() {
-        if (emf == null)
-            return false;
-
         close();
-
-        if (!emf.isOpen())
-            return false;
-
-        emf.close();
-        return !emf.isOpen();
+        return super.closeEMF();
     }
 
     /** 
@@ -283,5 +223,4 @@
 
         return total;
     }
-}
-
+}
\ No newline at end of file