You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2013/06/22 19:23:56 UTC

svn commit: r1495760 - in /cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map: DefaultMappingCache.java EntityResolver.java MappingCache.java ProxiedMappingCache.java

Author: aadamchik
Date: Sat Jun 22 17:23:55 2013
New Revision: 1495760

URL: http://svn.apache.org/r1495760
Log:
CAY-1789  Lock-free EntityResolver

adding a proxy wrapper for lazy initialization

Added:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/DefaultMappingCache.java
      - copied, changed from r1495759, cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/MappingCache.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/ProxiedMappingCache.java
Modified:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityResolver.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/MappingCache.java

Copied: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/DefaultMappingCache.java (from r1495759, cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/MappingCache.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/DefaultMappingCache.java?p2=cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/DefaultMappingCache.java&p1=cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/MappingCache.java&r1=1495759&r2=1495760&rev=1495760&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/MappingCache.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/DefaultMappingCache.java Sat Jun 22 17:23:55 2013
@@ -30,11 +30,11 @@ import org.apache.commons.logging.LogFac
 /**
  * @since 3.2
  */
-class MappingCache {
+class DefaultMappingCache implements MappingCache {
 
     private static final ObjEntity OBJ_DUPLICATE_MARKER = new ObjEntity();
 
-    protected static final Log logger = LogFactory.getLog(MappingCache.class);
+    protected static final Log logger = LogFactory.getLog(DefaultMappingCache.class);
 
     protected Map<String, Query> queryCache;
     protected Map<String, Embeddable> embeddableCache;
@@ -44,7 +44,7 @@ class MappingCache {
     protected Map<String, Procedure> procedureCache;
     protected Map<String, EntityInheritanceTree> entityInheritanceCache;
 
-    MappingCache(Collection<DataMap> maps) {
+    DefaultMappingCache(Collection<DataMap> maps) {
         this.embeddableCache = new HashMap<String, Embeddable>();
         this.queryCache = new HashMap<String, Query>();
         this.dbEntityCache = new HashMap<String, DbEntity>();
@@ -163,35 +163,35 @@ class MappingCache {
         return "^cl^" + className;
     }
 
-    Embeddable getEmbeddable(String className) {
+    public Embeddable getEmbeddable(String className) {
         return embeddableCache.get(className);
     }
 
-    SQLResult getResult(String name) {
+    public SQLResult getResult(String name) {
         return resultsCache.get(name);
     }
 
-    EntityInheritanceTree getInheritanceTree(String entityName) {
+    public EntityInheritanceTree getInheritanceTree(String entityName) {
         return entityInheritanceCache.get(entityName);
     }
 
-    Procedure getProcedure(String procedureName) {
+    public Procedure getProcedure(String procedureName) {
         return procedureCache.get(procedureName);
     }
 
-    Query getQuery(String queryName) {
+    public Query getQuery(String queryName) {
         return queryCache.get(queryName);
     }
 
-    DbEntity getDbEntity(String name) {
+    public DbEntity getDbEntity(String name) {
         return dbEntityCache.get(name);
     }
 
-    ObjEntity getObjEntity(Class<?> entityClass) {
+    public ObjEntity getObjEntity(Class<?> entityClass) {
         return getObjEntity(classKey(entityClass.getName()));
     }
 
-    ObjEntity getObjEntity(String name) {
+    public ObjEntity getObjEntity(String name) {
         ObjEntity entity = objEntityCache.get(name);
 
         if (entity == OBJ_DUPLICATE_MARKER) {

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityResolver.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityResolver.java?rev=1495760&r1=1495759&r2=1495760&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityResolver.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityResolver.java Sat Jun 22 17:23:55 2013
@@ -60,7 +60,7 @@ public class EntityResolver implements M
     protected boolean indexedByClass;
 
     protected Collection<DataMap> maps;
-    protected transient MappingCache entityCache;
+    protected transient MappingCache mappingCache;
     protected EntityResolver clientEntityResolver;
 
     // must be transient, as resolver may get deserialized in another VM, and
@@ -379,24 +379,24 @@ public class EntityResolver implements M
     }
 
     public DbEntity getDbEntity(String name) {
-        DbEntity result = entityCache.getDbEntity(name);
+        DbEntity result = mappingCache.getDbEntity(name);
         if (result == null) {
             // reconstruct cache just in case some of the datamaps
             // have changed and now contain the required information
             refreshMappingCache();
-            result = entityCache.getDbEntity(name);
+            result = mappingCache.getDbEntity(name);
         }
 
         return result;
     }
 
     public ObjEntity getObjEntity(String name) {
-        ObjEntity result = entityCache.getObjEntity(name);
+        ObjEntity result = mappingCache.getObjEntity(name);
         if (result == null) {
             // reconstruct cache just in case some of the datamaps
             // have changed and now contain the required information
             refreshMappingCache();
-            result = entityCache.getObjEntity(name);
+            result = mappingCache.getObjEntity(name);
         }
 
         return result;
@@ -414,13 +414,13 @@ public class EntityResolver implements M
      * @since 3.0
      */
     public Embeddable getEmbeddable(String className) {
-        Embeddable result = entityCache.getEmbeddable(className);
+        Embeddable result = mappingCache.getEmbeddable(className);
 
         if (result == null) {
             // reconstruct cache just in case some of the datamaps
             // have changed and now contain the required information
             refreshMappingCache();
-            result = entityCache.getEmbeddable(className);
+            result = mappingCache.getEmbeddable(className);
         }
 
         return result;
@@ -430,13 +430,13 @@ public class EntityResolver implements M
      * @since 3.0
      */
     public SQLResult getResult(String name) {
-        SQLResult result = entityCache.getResult(name);
+        SQLResult result = mappingCache.getResult(name);
 
         if (result == null) {
             // reconstruct cache just in case some of the datamaps
             // have changed and now contain the required information
             refreshMappingCache();
-            result = entityCache.getResult(name);
+            result = mappingCache.getResult(name);
         }
 
         return result;
@@ -481,7 +481,14 @@ public class EntityResolver implements M
      * @since 3.2
      */
     public void refreshMappingCache() {
-        entityCache = new MappingCache(maps);
+        mappingCache = new ProxiedMappingCache() {
+
+            @Override
+            protected MappingCache createDelegate() {
+                return new DefaultMappingCache(maps);
+            }
+        };
+        
         clientEntityResolver = null;
     }
 
@@ -525,7 +532,7 @@ public class EntityResolver implements M
      */
     public EntityInheritanceTree lookupInheritanceTree(String entityName) {
 
-        EntityInheritanceTree tree = entityCache.getInheritanceTree(entityName);
+        EntityInheritanceTree tree = mappingCache.getInheritanceTree(entityName);
 
         if (tree == null) {
             // since we keep inheritance trees for all entities, null means
@@ -534,7 +541,7 @@ public class EntityResolver implements M
             // rebuild cache just in case some of the datamaps
             // have changed and now contain the required information
             refreshMappingCache();
-            tree = entityCache.getInheritanceTree(entityName);
+            tree = mappingCache.getInheritanceTree(entityName);
         }
 
         return tree;
@@ -548,12 +555,12 @@ public class EntityResolver implements M
      *         specifier
      */
     public ObjEntity lookupObjEntity(Class<?> aClass) {
-        ObjEntity result = entityCache.getObjEntity(aClass);
+        ObjEntity result = mappingCache.getObjEntity(aClass);
         if (result == null) {
             // reconstruct cache just in case some of the datamaps
             // have changed and now contain the required information
             refreshMappingCache();
-            result = entityCache.getObjEntity(aClass);
+            result = mappingCache.getObjEntity(aClass);
         }
 
         return result;
@@ -588,12 +595,12 @@ public class EntityResolver implements M
 
     public Procedure lookupProcedure(String procedureName) {
 
-        Procedure result = entityCache.getProcedure(procedureName);
+        Procedure result = mappingCache.getProcedure(procedureName);
         if (result == null) {
             // reconstruct cache just in case some of the datamaps
             // have changed and now contain the required information
             refreshMappingCache();
-            result = entityCache.getProcedure(procedureName);
+            result = mappingCache.getProcedure(procedureName);
         }
 
         return result;
@@ -603,13 +610,13 @@ public class EntityResolver implements M
      * Returns a named query or null if no query exists for a given name.
      */
     public Query lookupQuery(String name) {
-        Query result = entityCache.getQuery(name);
+        Query result = mappingCache.getQuery(name);
 
         if (result == null) {
             // reconstruct cache just in case some of the datamaps
             // have changed and now contain the required information
             refreshMappingCache();
-            result = entityCache.getQuery(name);
+            result = mappingCache.getQuery(name);
         }
         return result;
     }

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/MappingCache.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/MappingCache.java?rev=1495760&r1=1495759&r2=1495760&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/MappingCache.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/MappingCache.java Sat Jun 22 17:23:55 2013
@@ -18,187 +18,23 @@
  ****************************************************************/
 package org.apache.cayenne.map;
 
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.query.Query;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 
-/**
- * @since 3.2
- */
-class MappingCache {
-
-    private static final ObjEntity OBJ_DUPLICATE_MARKER = new ObjEntity();
-
-    protected static final Log logger = LogFactory.getLog(MappingCache.class);
-
-    protected Map<String, Query> queryCache;
-    protected Map<String, Embeddable> embeddableCache;
-    protected Map<String, SQLResult> resultsCache;
-    protected Map<String, DbEntity> dbEntityCache;
-    protected Map<String, ObjEntity> objEntityCache;
-    protected Map<String, Procedure> procedureCache;
-    protected Map<String, EntityInheritanceTree> entityInheritanceCache;
-
-    MappingCache(Collection<DataMap> maps) {
-        this.embeddableCache = new HashMap<String, Embeddable>();
-        this.queryCache = new HashMap<String, Query>();
-        this.dbEntityCache = new HashMap<String, DbEntity>();
-        this.objEntityCache = new HashMap<String, ObjEntity>();
-        this.procedureCache = new HashMap<String, Procedure>();
-        this.entityInheritanceCache = new HashMap<String, EntityInheritanceTree>();
-        this.resultsCache = new HashMap<String, SQLResult>();
-
-        index(maps);
-    }
-
-    private void index(Collection<DataMap> maps) {
-
-        // index DbEntities separately and before ObjEntities to avoid infinite
-        // loops when looking up DbEntities during ObjEntity index op
-
-        for (DataMap map : maps) {
-            for (DbEntity de : map.getDbEntities()) {
-                dbEntityCache.put(de.getName(), de);
-            }
-        }
-
-        for (DataMap map : maps) {
-
-            // index ObjEntities
-            for (ObjEntity oe : map.getObjEntities()) {
-
-                // index by name
-                objEntityCache.put(oe.getName(), oe);
-
-                // index by class.. use class name as a key to avoid class
-                // loading here...
-                String className = oe.getJavaClassName();
-                if (className == null) {
-                    continue;
-                }
-
-                String classKey = classKey(className);
-
-                // allow duplicates, but put a special marker indicating
-                // that this entity can't be looked up by class
-                Object existing = objEntityCache.get(classKey);
-                if (existing != null) {
-
-                    if (existing != OBJ_DUPLICATE_MARKER) {
-                        objEntityCache.put(classKey, OBJ_DUPLICATE_MARKER);
-                    }
-                } else {
-                    objEntityCache.put(classKey, oe);
-                }
-            }
-
-            // index stored procedures
-            for (Procedure proc : map.getProcedures()) {
-                procedureCache.put(proc.getName(), proc);
-            }
-
-            // index embeddables
-            embeddableCache.putAll(map.getEmbeddableMap());
-
-            // index queries
-            for (Query query : map.getQueries()) {
-                String name = query.getName();
-                Object existingQuery = queryCache.put(name, query);
-
-                if (existingQuery != null && query != existingQuery) {
-                    throw new CayenneRuntimeException("More than one Query for name" + name);
-                }
-            }
-        }
-
-        // restart the map iterator to index inheritance
-        for (DataMap map : maps) {
-
-            // index ObjEntity inheritance
-            for (ObjEntity oe : map.getObjEntities()) {
-
-                // build inheritance tree
-                EntityInheritanceTree node = entityInheritanceCache.get(oe.getName());
-                if (node == null) {
-                    node = new EntityInheritanceTree(oe);
-                    entityInheritanceCache.put(oe.getName(), node);
-                }
-
-                String superOEName = oe.getSuperEntityName();
-                if (superOEName != null) {
-                    EntityInheritanceTree superNode = entityInheritanceCache.get(superOEName);
-
-                    if (superNode == null) {
-                        // do direct entity lookup to avoid recursive cache
-                        // rebuild
-                        ObjEntity superOE = objEntityCache.get(superOEName);
-                        if (superOE != null) {
-                            superNode = new EntityInheritanceTree(superOE);
-                            entityInheritanceCache.put(superOEName, superNode);
-                        } else {
-                            // bad mapping? Or most likely some classloader
-                            // issue
-                            logger.warn("No super entity mapping for '" + superOEName + "'");
-                            continue;
-                        }
-                    }
-
-                    superNode.addChildNode(node);
-                }
-            }
-        }
-    }
-
-    /**
-     * Generates a map key for the object class.
-     */
-    private String classKey(String className) {
-        // need to ensure that there is no conflict with entity names... I guess
-        // such prefix is enough to guarantee that:
-        return "^cl^" + className;
-    }
-
-    Embeddable getEmbeddable(String className) {
-        return embeddableCache.get(className);
-    }
-
-    SQLResult getResult(String name) {
-        return resultsCache.get(name);
-    }
-
-    EntityInheritanceTree getInheritanceTree(String entityName) {
-        return entityInheritanceCache.get(entityName);
-    }
-
-    Procedure getProcedure(String procedureName) {
-        return procedureCache.get(procedureName);
-    }
-
-    Query getQuery(String queryName) {
-        return queryCache.get(queryName);
-    }
-
-    DbEntity getDbEntity(String name) {
-        return dbEntityCache.get(name);
-    }
-
-    ObjEntity getObjEntity(Class<?> entityClass) {
-        return getObjEntity(classKey(entityClass.getName()));
-    }
-
-    ObjEntity getObjEntity(String name) {
-        ObjEntity entity = objEntityCache.get(name);
-
-        if (entity == OBJ_DUPLICATE_MARKER) {
-            throw new CayenneRuntimeException("Can't perform lookup. There is more than one ObjEntity mapped to "
-                    + name);
-        }
+interface MappingCache {
+
+    Embeddable getEmbeddable(String className);
+
+    SQLResult getResult(String name);
+
+    EntityInheritanceTree getInheritanceTree(String entityName);
+
+    Procedure getProcedure(String procedureName);
+
+    Query getQuery(String queryName);
+
+    DbEntity getDbEntity(String name);
+
+    ObjEntity getObjEntity(Class<?> entityClass);
 
-        return entity;
-    }
+    ObjEntity getObjEntity(String name);
 }

Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/ProxiedMappingCache.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/ProxiedMappingCache.java?rev=1495760&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/ProxiedMappingCache.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/ProxiedMappingCache.java Sat Jun 22 17:23:55 2013
@@ -0,0 +1,78 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.map;
+
+import org.apache.cayenne.query.Query;
+
+/**
+ * A proxy for lazy on-demand initialization of the mapping cache.
+ */
+abstract class ProxiedMappingCache implements MappingCache {
+
+    private volatile MappingCache delegate;
+
+    MappingCache getDelegate() {
+
+        if (delegate == null) {
+
+            synchronized (this) {
+                if (delegate == null) {
+                    delegate = createDelegate();
+                }
+            }
+        }
+
+        return delegate;
+    }
+
+    protected abstract MappingCache createDelegate();
+
+    public Embeddable getEmbeddable(String className) {
+        return getDelegate().getEmbeddable(className);
+    }
+
+    public SQLResult getResult(String name) {
+        return getDelegate().getResult(name);
+    }
+
+    public EntityInheritanceTree getInheritanceTree(String entityName) {
+        return getDelegate().getInheritanceTree(entityName);
+    }
+
+    public Procedure getProcedure(String procedureName) {
+        return getDelegate().getProcedure(procedureName);
+    }
+
+    public Query getQuery(String queryName) {
+        return getDelegate().getQuery(queryName);
+    }
+
+    public DbEntity getDbEntity(String name) {
+        return getDelegate().getDbEntity(name);
+    }
+
+    public ObjEntity getObjEntity(Class<?> entityClass) {
+        return getDelegate().getObjEntity(entityClass);
+    }
+
+    public ObjEntity getObjEntity(String name) {
+        return getDelegate().getObjEntity(name);
+    }
+
+}