You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pp...@apache.org on 2009/10/16 07:07:57 UTC

svn commit: r825768 - in /openjpa/trunk: openjpa-kernel/src/main/java/org/apache/openjpa/conf/ openjpa-kernel/src/main/java/org/apache/openjpa/datacache/ openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ openjpa-kernel/src/main/resources/org/apac...

Author: ppoddar
Date: Fri Oct 16 05:07:56 2009
New Revision: 825768

URL: http://svn.apache.org/viewvc?rev=825768&view=rev
Log:
OPENJPA-1334: Support partitioned cache with instance-level distribution policy

Added:
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/CacheDistributionPolicy.java   (with props)
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/PartitionedDataCache.java   (with props)
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestPartionedDataCache.java   (with props)
Modified:
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/AbstractDataCache.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/ConcurrentDataCache.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCache.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheManager.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheManagerImpl.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCachePCDataImpl.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DelegatingDataCache.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/InverseManager.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PCData.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PCDataImpl.java
    openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/datacache/localizer.properties
    openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_caching.xml

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java?rev=825768&r1=825767&r2=825768&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java Fri Oct 16 05:07:56 2009
@@ -28,6 +28,7 @@
 import org.apache.openjpa.datacache.DataCacheManager;
 import org.apache.openjpa.datacache.DataCacheManagerImpl;
 import org.apache.openjpa.datacache.DataCacheMode;
+import org.apache.openjpa.datacache.PartitionedDataCache;
 import org.apache.openjpa.ee.ManagedRuntime;
 import org.apache.openjpa.enhance.RuntimeUnenhancedClassesModes;
 import org.apache.openjpa.event.BrokerFactoryEventManager;
@@ -238,7 +239,8 @@
         aliases = new String[] { 
             "false", null, 
             "true", ConcurrentDataCache.class.getName(), 
-            "concurrent", ConcurrentDataCache.class.getName(), 
+            "concurrent", ConcurrentDataCache.class.getName(),
+            "partitioned", PartitionedDataCache.class.getName(),
         };
         dataCachePlugin.setAliases(aliases);
         dataCachePlugin.setDefault(aliases[0]);

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/AbstractDataCache.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/AbstractDataCache.java?rev=825768&r1=825767&r2=825768&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/AbstractDataCache.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/AbstractDataCache.java Fri Oct 16 05:07:56 2009
@@ -22,6 +22,7 @@
 import java.util.Arrays;
 import java.util.BitSet;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -475,6 +476,20 @@
     public Set<String> getExcludedTypes() {
         return _excludedTypes;
     }
+    
+    public boolean isExcludedType(String type) {
+        if (_excludedTypes != null) {
+            if (_excludedTypes.contains(type)) {
+                return true;
+            }
+        }
+        if (_includedTypes != null) {
+             if (!_includedTypes.contains(type)) {
+                 return true;
+             }
+        }
+        return false;
+    }
 
     public void setTypes(Set<String> types) {
         _includedTypes = types;
@@ -495,4 +510,25 @@
             StringUtils.isEmpty(types) ? null : new HashSet<String>(Arrays
                 .asList(Strings.split(types, ";", 0)));
     }
+    
+    /**
+     * 
+     */
+    public DataCache getPartition(String name, boolean create) {
+        if (StringUtils.equals(_name, name))
+            return this;
+        return null;
+    }
+
+    /**
+     * 
+     */
+    public Set<String> getPartitionNames() {
+        return Collections.emptySet();
+    }
+    
+    public boolean isPartitioned() {
+        return false;
+    }
+
 }

Added: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/CacheDistributionPolicy.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/CacheDistributionPolicy.java?rev=825768&view=auto
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/CacheDistributionPolicy.java (added)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/CacheDistributionPolicy.java Fri Oct 16 05:07:56 2009
@@ -0,0 +1,38 @@
+package org.apache.openjpa.datacache;
+
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.meta.ClassMetaData;
+
+/**
+ * A policy determines the name of the cache where a given entity state will be cached.
+ * 
+ * @author Pinaki Poddar
+ * 
+ * @since 2.0.0
+ *
+ */
+public interface CacheDistributionPolicy {
+    /**
+     * Selects the name of the cache where the given managed proxy object state be cached.
+     * 
+     * @param sm the managed proxy object to be cached
+     * @param context the context of invocation. No specific semantics is 
+     * attributed currently. Can be null.
+     *  
+     * @return name of the cache or null if the managed instance need not be cached.
+     */
+    String selectCache(OpenJPAStateManager sm, Object context);
+    
+    /**
+     * A default implementation that selects the cache by the type of the given
+     * managed instance.
+     * 
+     * @see ClassMetaData#getDataCacheName()
+     *
+     */
+    public static class Default implements CacheDistributionPolicy {
+        public String selectCache(OpenJPAStateManager sm, Object context) {
+            return sm.getMetaData().getDataCacheName();
+        }
+    }
+}

Propchange: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/CacheDistributionPolicy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/ConcurrentDataCache.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/ConcurrentDataCache.java?rev=825768&r1=825767&r2=825768&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/ConcurrentDataCache.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/ConcurrentDataCache.java Fri Oct 16 05:07:56 2009
@@ -18,6 +18,8 @@
  */
 package org.apache.openjpa.datacache;
 
+import java.util.List;
+
 import org.apache.openjpa.event.RemoteCommitListener;
 import org.apache.openjpa.lib.util.Localizer;
 import org.apache.openjpa.util.CacheMap;

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCache.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCache.java?rev=825768&r1=825767&r2=825768&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCache.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCache.java Fri Oct 16 05:07:56 2009
@@ -22,6 +22,7 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.openjpa.lib.util.Closeable;
 
@@ -36,6 +37,7 @@
  * @see DataCachePCData#isTimedOut
  * @author Patrick Linskey
  * @author Abe White
+ * @author Pinaki Poddar
  */
 public interface DataCache
     extends Closeable {
@@ -270,6 +272,34 @@
     public Map<Object,DataCachePCData> getAll(List<Object> keys);
     
     /**
+     * Gets the named partition. Note that a partition itself is another cache.
+     *  
+     * @param name name of the given partition. 
+     * 
+     * @param create if true optionally create a new partition. 
+     * 
+     * @return a partition of the given name. Or null, if either no such partition exists or can not be created.
+     * @since 2.0.0
+     */
+    public DataCache getPartition(String name, boolean create);
+    
+    /**
+     * Gets the name of the known partitions. 
+     * 
+     * @return empty set if no partition exists.
+     * 
+     * @since 2.0.0
+     */
+    public Set<String> getPartitionNames();
+        
+    /**
+     * Affirms if this cache maintains partitions.
+     * 
+     * @since 2.0.0
+     */
+    public boolean isPartitioned();
+    
+    /**
      * Returns number of read/write request and cache hit ratio data.
      */
     public CacheStatistics getStatistics();

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheManager.java?rev=825768&r1=825767&r2=825768&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheManager.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheManager.java Fri Oct 16 05:07:56 2009
@@ -19,6 +19,7 @@
 package org.apache.openjpa.datacache;
 
 import org.apache.openjpa.conf.OpenJPAConfiguration;
+import org.apache.openjpa.kernel.OpenJPAStateManager;
 import org.apache.openjpa.lib.conf.ObjectValue;
 
 /**
@@ -69,6 +70,24 @@
      * Return the runnable which schedules evictions.
      */
     public DataCacheScheduler getDataCacheScheduler();
+    
+    /**
+     * Select the cache where the given managed proxy instance should be cached.
+     * This decision <em>may</em> override the cache returned by 
+     * {@link CacheDistributionPolicy#selectCache(OpenJPAStateManager, Object) policy}
+     * as specified by the user.  
+     *  
+     * @param sm the managed proxy instance
+     * @return the cache that will store the state of the given managed instance.
+     * @since 2.0.0
+     */
+    public DataCache selectCache(OpenJPAStateManager sm);
+    
+    /**
+     * Return the policy that suggests the cache where a managed entity state is stored.  
+     * @since 2.0.0
+     */
+    public CacheDistributionPolicy getDistributionPolicy();
 
     /**
      * Close all caches.

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheManagerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheManagerImpl.java?rev=825768&r1=825767&r2=825768&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheManagerImpl.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheManagerImpl.java Fri Oct 16 05:07:56 2009
@@ -19,6 +19,7 @@
 package org.apache.openjpa.datacache;
 
 import org.apache.openjpa.conf.OpenJPAConfiguration;
+import org.apache.openjpa.kernel.OpenJPAStateManager;
 import org.apache.openjpa.lib.conf.ObjectValue;
 import org.apache.openjpa.lib.util.Closeable;
 import org.apache.openjpa.util.ImplHelper;
@@ -36,21 +37,20 @@
     private QueryCache _queryCache = null;
     private DataCachePCDataGenerator _pcGenerator = null;
     private DataCacheScheduler _scheduler = null;
+    private CacheDistributionPolicy _policy = new CacheDistributionPolicy.Default();
 
-    public void initialize(OpenJPAConfiguration conf, ObjectValue dataCache,
-        ObjectValue queryCache) {
+    public void initialize(OpenJPAConfiguration conf, ObjectValue dataCache, ObjectValue queryCache) {
         _cache = (DataCache) dataCache.instantiate(DataCache.class, conf);
         if (_cache == null)
             return;
-
+         
         // create helpers before initializing caches
         if (conf.getDynamicDataStructs())
             _pcGenerator = new DataCachePCDataGenerator(conf);
         _scheduler = new DataCacheScheduler(conf);
 
         _cache.initialize(this);
-        _queryCache = (QueryCache) queryCache.instantiate(QueryCache.class,
-            conf);
+        _queryCache = (QueryCache) queryCache.instantiate(QueryCache.class, conf);
         if (_queryCache != null)
             _queryCache.initialize(this);
     }
@@ -63,9 +63,14 @@
         return getDataCache(name, false);
     }
 
+    /**
+     * Returns the named cache. 
+     */
     public DataCache getDataCache(String name, boolean create) {
         if (name == null || (_cache != null && name.equals(_cache.getName())))
             return _cache;
+        if (_cache != null)
+            return _cache.getPartition(name, create);
         return null;
     }
 
@@ -87,4 +92,22 @@
         if (_scheduler != null)
             _scheduler.stop();
     }
+
+    public DataCache selectCache(OpenJPAStateManager sm) {
+        if (sm == null)
+            return null;
+        if (_cache instanceof AbstractDataCache 
+        && ((AbstractDataCache)_cache).isExcludedType(sm.getMetaData().getDescribedType().getName()))
+            return null;
+        String name = _policy.selectCache(sm, null);
+        return name == null ? null : getDataCache(name);
+    }
+    
+    public CacheDistributionPolicy getDistributionPolicy() {
+        return _policy;
+    }
+    
+    public void setDistributionPolicy(CacheDistributionPolicy policy) {
+        _policy = policy;
+    }
 }

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCachePCDataImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCachePCDataImpl.java?rev=825768&r1=825767&r2=825768&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCachePCDataImpl.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCachePCDataImpl.java Fri Oct 16 05:07:56 2009
@@ -37,6 +37,7 @@
  *
  * @author Patrick Linskey
  */
+@SuppressWarnings("serial")
 public class DataCachePCDataImpl
     extends PCDataImpl
     implements DataCachePCData {
@@ -46,8 +47,8 @@
     /**
      * Constructor.
      */
-    public DataCachePCDataImpl(Object oid, ClassMetaData meta) {
-        super(oid, meta);
+    public DataCachePCDataImpl(Object oid, ClassMetaData meta, String name) {
+        super(oid, meta, name);
 
         int timeout = meta.getDataCacheTimeout();
         if (timeout > 0)
@@ -130,7 +131,7 @@
      * order.
      */
     protected void storeField(OpenJPAStateManager sm, FieldMetaData fmd) {
-        if (fmd.getManagement() != fmd.MANAGE_PERSISTENT)
+        if (fmd.getManagement() != FieldMetaData.MANAGE_PERSISTENT)
             return;
         int index = fmd.getIndex();
 
@@ -160,25 +161,22 @@
      * in inverse relation. If it is, clear the other field cache because it
      * could be out of order.
      */
-    protected void clearInverseRelationCache(OpenJPAStateManager sm,
-        FieldMetaData fmd) {
+    protected void clearInverseRelationCache(OpenJPAStateManager sm, FieldMetaData fmd) {
+        DataCache cache = sm.getMetaData().getDataCache();
+        if (cache == null)
+            return;
         ClassMetaData cmd = sm.getMetaData();
         FieldMetaData[] fields = cmd.getFields();
         for (int i = 0; i < fields.length; i++) {
             FieldMetaData[] inverses = fields[i].getInverseMetaDatas();
             if (inverses.length == 0)
                 continue;
-            for (int j = 0; j < inverses.length; j++) {
-                if (inverses[j].getOrderDeclaration()
-                    .indexOf(fmd.getName()) != -1) {
-                    DataCache cache = sm.getMetaData().getDataCache();
+            for (FieldMetaData inverse : inverses) {
+                if (inverse.getOrderDeclaration().indexOf(fmd.getName()) != -1) {
                     Object oid = sm.getContext().getObjectId(sm.fetch(i));
-                    DataCachePCData data = cache == null ? null
-                        : cache.get(oid);
-                    if ((data != null) &&
-                        (data instanceof DataCachePCDataImpl)) {
-                        ((DataCachePCDataImpl) data)
-                            .clearData(inverses[j].getIndex());
+                    DataCachePCData data = cache.get(oid);
+                    if (data instanceof DataCachePCDataImpl) {
+                        ((DataCachePCDataImpl) data).clearData(inverse.getIndex());
                     }
                 }
             }
@@ -209,6 +207,6 @@
     }
 
     public AbstractPCData newEmbeddedPCData(OpenJPAStateManager sm) {
-        return new DataCachePCDataImpl(sm.getId(), sm.getMetaData());
+        return new DataCachePCDataImpl(sm.getId(), sm.getMetaData(), getCache());
     }
 }

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java?rev=825768&r1=825767&r2=825768&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java Fri Oct 16 05:07:56 2009
@@ -34,6 +34,7 @@
 import org.apache.openjpa.kernel.DataCacheStoreMode;
 import org.apache.openjpa.kernel.DelegatingStoreManager;
 import org.apache.openjpa.kernel.FetchConfiguration;
+import org.apache.openjpa.kernel.FindCallbacks;
 import org.apache.openjpa.kernel.LockLevels;
 import org.apache.openjpa.kernel.OpenJPAStateManager;
 import org.apache.openjpa.kernel.PCState;
@@ -62,7 +63,7 @@
 
     // the owning context
     private StoreContext _ctx = null;
-
+    private DataCacheManager _mgr = null;
     // pc data generator
     private PCDataGenerator _gen = null;
 
@@ -77,7 +78,8 @@
 
     public void setContext(StoreContext ctx) {
         _ctx = ctx;
-        _gen = ctx.getConfiguration().getDataCacheManagerInstance().getPCDataGenerator();
+        _mgr = ctx.getConfiguration().getDataCacheManagerInstance();
+        _gen = _mgr.getPCDataGenerator();
         super.setContext(ctx);
     }
 
@@ -113,8 +115,7 @@
         if (classes.isEmpty())
             return;
 
-        MetaDataRepository mdr = _ctx.getConfiguration().
-            getMetaDataRepositoryInstance();
+        MetaDataRepository mdr = _ctx.getConfiguration().getMetaDataRepositoryInstance();
         ClassLoader loader = _ctx.getClassLoader();
 
         DataCache cache;
@@ -141,7 +142,7 @@
             // create pc datas for inserts
             if (_ctx.getPopulateDataCache() && _inserts != null) {
                 for (OpenJPAStateManager sm : _inserts) {
-                    cache = sm.getMetaData().getDataCache();
+                    cache = _mgr.selectCache(sm);
                     if (cache == null)
                         continue;
 
@@ -160,7 +161,7 @@
                     sm = entry.getKey();
                     fields = entry.getValue();
 
-                    cache = sm.getMetaData().getDataCache();
+                    cache = _mgr.selectCache(sm);
                     if (cache == null) {
                         continue;
                     }
@@ -190,7 +191,7 @@
             // remove pcdatas for deletes
             if (_deletes != null) {
                 for (OpenJPAStateManager sm : _deletes) { 
-                    cache = sm.getMetaData().getDataCache();
+                    cache = _mgr.selectCache(sm);
                     if (cache == null)
                         continue;
 
@@ -290,7 +291,7 @@
     }
 
     public boolean exists(OpenJPAStateManager sm, Object edata) {
-        DataCache cache = sm.getMetaData().getDataCache();
+        DataCache cache = _mgr.selectCache(sm); 
         if (cache != null && !isLocking(null)
             && cache.contains(sm.getObjectId()))
             return true;
@@ -298,7 +299,7 @@
     }
 
     public boolean syncVersion(OpenJPAStateManager sm, Object edata) {
-        DataCache cache = sm.getMetaData().getDataCache();
+        DataCache cache = _mgr.selectCache(sm);
         if (cache == null || sm.isEmbedded())
             return super.syncVersion(sm, edata);
 
@@ -323,7 +324,7 @@
 
     public boolean initialize(OpenJPAStateManager sm, PCState state, FetchConfiguration fetch, Object edata) {
         boolean fromDatabase; 
-        DataCache cache = sm.getMetaData().getDataCache();
+        DataCache cache = _mgr.selectCache(sm);
         DataCachePCData data = null;
         boolean updateCache = _ctx.getCacheStoreMode() != DataCacheStoreMode.BYPASS && _ctx.getPopulateDataCache();
         if (cache == null || sm.isEmbedded() || _ctx.getCacheRetrieveMode() == DataCacheRetrieveMode.BYPASS
@@ -353,7 +354,7 @@
     }
     
     private void cacheStateManager(DataCache cache, OpenJPAStateManager sm, DataCachePCData data) {
-        if(sm.isFlushed()) { 
+        if (sm.isFlushed()) { 
             return;
         }
         // make sure that we're not trying to cache an old version
@@ -383,7 +384,7 @@
 
     public boolean load(OpenJPAStateManager sm, BitSet fields,
         FetchConfiguration fetch, int lockLevel, Object edata) {
-        DataCache cache = sm.getMetaData().getDataCache();
+        DataCache cache = _mgr.selectCache(sm);
         if (cache == null || sm.isEmbedded() || _ctx.getCacheRetrieveMode() == DataCacheRetrieveMode.BYPASS)
             return super.load(sm, fields, fetch, lockLevel, edata);
 
@@ -421,7 +422,7 @@
         BitSet fields;
 
         for (OpenJPAStateManager sm : sms) {
-            cache = sm.getMetaData().getDataCache();
+            cache = _mgr.selectCache(sm);
             if (cache == null || sm.isEmbedded()) {
                 unloaded = addUnloaded(sm, null, unloaded);
                 continue;
@@ -494,7 +495,7 @@
             OpenJPAStateManager sm = entry.getKey();
             fields = entry.getValue();
 
-            cache = sm.getMetaData().getDataCache();
+            cache = _mgr.selectCache(sm);
             if (cache == null || sm.isEmbedded() || (failed != null
                 && failed.contains(sm.getId())))
                 continue;
@@ -607,8 +608,7 @@
         // this logic could be more efficient -- we could aggregate
         // all the cache->oid changes, and then use DataCache.removeAll() 
         // and less write locks to do the mutation.
-        ClassMetaData meta = sm.getMetaData();
-        DataCache cache = meta.getDataCache();
+        DataCache cache = _mgr.selectCache(sm);
         if (cache == null)
             return;
 
@@ -684,7 +684,7 @@
         ClassMetaData meta = sm.getMetaData();
         if (_gen != null)
             return (DataCachePCData) _gen.generatePCData(sm.getObjectId(), meta);
-        return new DataCachePCDataImpl(sm.fetchObjectId(), meta);
+        return new DataCachePCDataImpl(sm.fetchObjectId(), meta, _mgr.selectCache(sm).getName());
     }
 
     /**
@@ -694,8 +694,8 @@
         if (fetch == null)
             fetch = _ctx.getFetchConfiguration();
         return fetch.getReadLockLevel() > LockLevels.LOCK_NONE;
-    }
-
+    }  
+    
     /**
      * Structure used during the commit process to track cache modifications.
      */

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DelegatingDataCache.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DelegatingDataCache.java?rev=825768&r1=825767&r2=825768&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DelegatingDataCache.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DelegatingDataCache.java Fri Oct 16 05:07:56 2009
@@ -22,6 +22,7 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.commons.lang.ObjectUtils;
 import org.apache.openjpa.util.RuntimeExceptionTranslator;
@@ -125,8 +126,8 @@
         }
     }
 
-    public void commit(Collection additions, Collection newUpdates,
-        Collection existingUpdates, Collection deletes) {
+    public void commit(Collection<DataCachePCData> additions, Collection<DataCachePCData> newUpdates,
+        Collection<DataCachePCData> existingUpdates, Collection<Object> deletes) {
         if (_cache == null)
             return;
         try {
@@ -146,7 +147,7 @@
         }
     }
 
-    public BitSet containsAll(Collection oids) {
+    public BitSet containsAll(Collection<Object> oids) {
         if (_cache == null)
             return EMPTY_BITSET;
         try {
@@ -196,7 +197,7 @@
         }
     }
 
-    public BitSet removeAll(Collection oids) {
+    public BitSet removeAll(Collection<Object> oids) {
         if (_cache == null)
             return EMPTY_BITSET;
         try {
@@ -206,7 +207,7 @@
         }
     }
 
-    public void removeAll(Class cls, boolean subclasses) {
+    public void removeAll(Class<?> cls, boolean subclasses) {
         if (_cache == null)
             return;
         try {
@@ -236,7 +237,7 @@
         }
     }
 
-    public BitSet pinAll(Collection oids) {
+    public BitSet pinAll(Collection<Object> oids) {
         if (_cache == null)
             return EMPTY_BITSET;
         try {
@@ -246,7 +247,7 @@
         }
     }
 
-    public void pinAll(Class cls, boolean subs) {
+    public void pinAll(Class<?> cls, boolean subs) {
         if (_cache == null)
             return;
         try {
@@ -266,7 +267,7 @@
         }
     }
 
-    public BitSet unpinAll(Collection oids) {
+    public BitSet unpinAll(Collection<Object> oids) {
         if (_cache == null)
             return EMPTY_BITSET;
         try {
@@ -276,7 +277,7 @@
         }
     }
 
-    public void unpinAll(Class cls, boolean subs) {
+    public void unpinAll(Class<?> cls, boolean subs) {
         if (_cache == null)
             return;
         try {
@@ -336,7 +337,7 @@
 		}
 	}
 
-    public Map getAll(List keys) {
+    public Map<Object,DataCachePCData> getAll(List<Object> keys) {
         if (_cache == null)
             return null;
         try {
@@ -349,4 +350,35 @@
     public CacheStatistics getStatistics() {
     	return (_cache == null) ? null : _cache.getStatistics();
     }
+
+    
+    public DataCache getPartition(String name, boolean create) {
+        if (_cache == null)
+            return null;
+        try {
+            return _cache.getPartition(name, create);
+        } catch (RuntimeException re) {
+            throw translate(re);
+        }
+    }
+
+    public Set<String> getPartitionNames() {
+        if (_cache == null)
+            return null;
+        try {
+            return _cache.getPartitionNames();
+        } catch (RuntimeException re) {
+            throw translate(re);
+        }
+    }
+
+    public boolean isPartitioned() {
+        if (_cache == null)
+            return false;
+        try {
+            return _cache.isPartitioned();
+        } catch (RuntimeException re) {
+            throw translate(re);
+        }
+    }
 }

Added: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/PartitionedDataCache.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/PartitionedDataCache.java?rev=825768&view=auto
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/PartitionedDataCache.java (added)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/PartitionedDataCache.java Fri Oct 16 05:07:56 2009
@@ -0,0 +1,179 @@
+/*
+ * 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.openjpa.datacache;
+
+import java.lang.reflect.Array;
+import java.security.AccessController;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.openjpa.lib.conf.PluginListValue;
+import org.apache.openjpa.lib.conf.Value;
+import org.apache.openjpa.lib.util.J2DoPrivHelper;
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.util.UserException;
+
+/**
+ * A partitioned data cache maintains a set of partitions that are DataCache themselves.
+ * Each of the partitioned DataCaches can be individually configured. 
+ * However, all partitions must be of the same type. By default, this cache uses 
+ * {@linkplain ConcurrentDataCache} as its partitions.
+ * <br>
+ * This cache can be configured as a plug-in as follows:
+ * <br>
+ * <code>&lt;property name='openjpa.DataCache" 
+ *         value="partitioned(name=X, PartitionType=concurrent,Partitions='(name=a,cacheSize=100),
+ *         (name=b,cacheSize=200)')</code>
+ * <br>
+ * Notice that the individual partition properties are enclosed parentheses, separated by comma
+ * and finally the whole property string is enclosed in single quote.
+ * Each partition must have a non-empty name that are unique among the partitions. 
+ * The {@linkplain CacheDistributionPolicy policy} can return
+ * the name of a partition to distribute the managed instances to be cached in respective partition.
+ *  
+ * The above configuration will configure a partitioned cache named <code>X</code> with two partitions named
+ * <code>a</code> and <code>b</code> with cache size <code>100</code> and <code>200</code> respectively.
+ * Besides the two partitions, this cache instance itself can store data and referred by its own name
+ * (<code>X</code> in the above example).
+ * <br>
+ * 
+ * @author Pinaki Poddar
+ * 
+ * @since 2.0.0
+ */
+@SuppressWarnings("serial")
+public class PartitionedDataCache extends ConcurrentDataCache {
+    private static final Localizer _loc = Localizer.forPackage(PartitionedDataCache.class);
+    private Class<? extends DataCache> _type = ConcurrentDataCache.class;
+    private final List<String> _partProperties = new ArrayList<String>();
+    private final Map<String, DataCache> _partitions = new HashMap<String, DataCache>();
+    
+    /**
+     * Sets the type of the partitions. 
+     * Each partition is a DataCache itself.
+     * 
+     * @param type the name of the type that implements {@linkplain DataCache} interface.
+     * Aliases such as <code>"concurrent"</code> is also recognized.
+     * 
+     * @throws Exception if the given type is not resolvable to a loadable type.
+     */
+    public void setPartitionType(String type) throws Exception {
+        Value value = conf.getValue("DataCache");
+        ClassLoader ctxLoader = AccessController.doPrivileged(J2DoPrivHelper.getContextClassLoaderAction());
+        ClassLoader loader = conf.getClassResolverInstance().getClassLoader(null, ctxLoader);
+        _type = (Class<? extends DataCache>) AccessController.doPrivileged(
+                J2DoPrivHelper.getForNameAction(value.unalias(type), true, loader));
+    }
+    
+    /**
+     * Set partitions from a String configuration.
+     * 
+     * @param parts a String of the form <code>(p1, p2, p3)</code> where p1, p2 etc. itself are plug-in strings
+     * for individual Data Cache configuration.
+     */
+    public void setPartitions(String parts) {
+        _partProperties.clear();
+        parsePartitionProperties(parts);
+        PluginListValue partitions = new PluginListValue("partitions");
+        String[] types = (String[])Array.newInstance(String.class, _partProperties.size());
+        Arrays.fill(types, _type.getName());
+        partitions.setClassNames(types);
+        partitions.setProperties(_partProperties.toArray(new String[_partProperties.size()]));
+        DataCache[] array = (DataCache[])partitions.instantiate(_type, conf);
+        for (DataCache part : array) {
+            if (part.getName() == null)
+                throw new UserException(_loc.get("partition-cache-null-partition", parts));
+            if (_partitions.containsKey(part.getName()))
+                throw new UserException(_loc.get("partition-cache-duplicate-partition", part.getName(), parts));
+            if (part.getName().equals(DataCache.NAME_DEFAULT))
+                throw new UserException(_loc.get("partition-cache-default-partition", part.getName(), parts));
+            _partitions.put(part.getName(), part);
+        }
+    }
+    
+    /**
+     * Returns the individual partition configuration properties.
+     */
+    public List<String> getPartitions() {
+        return _partProperties;
+    }
+    
+    public DataCache getPartition(String name, boolean create) {
+        return _partitions.get(name);
+    }
+    
+    /**
+     * Gets the name of the configured partitions.
+     */
+    public Set<String> getPartitionNames() {
+        return _partitions.keySet();
+    }
+    
+    /**
+     * Always returns true.
+     */
+    public final boolean isPartitioned() {
+        return !_partitions.isEmpty();
+    }
+    
+    public void endConfiguration() {
+        if (!isPartitioned())
+            conf.getConfigurationLog().warn(_loc.get("partition-cache-no-config"));
+    }
+    
+    /**
+     * Parses property string of the form <code>(p1),(p2),(p3)</code> to produce a list of 
+     * <code>p1</code>, <code>p2</code> and <code>p3</code>. The component strings 
+     * <code>p1</code> etc. must be enclosed in parentheses and separated by comma.
+     * plug-in string to produce a list of 
+     * 
+     * @param properties property string of the form <code>(p1),(p2),(p3)</code>
+     */
+    private void parsePartitionProperties(String full) {
+        String properties = new String(full);
+        while (true) {
+            if (properties == null)
+                break;
+            properties = properties.trim();
+            if (properties.length() == 0)
+                break;
+            if (properties.startsWith(",")) {
+                properties = properties.substring(1);
+            } else if (!_partProperties.isEmpty()) {
+                throw new UserException(_loc.get("partition-cache-parse-error-comma", full, properties));
+            }
+            if (properties.startsWith("(") && properties.endsWith(")")) {
+                int i = properties.indexOf(")");
+                String p = properties.substring(1,i); // exclude the end parentheses
+                _partProperties.add(p);
+                 if (i < properties.length()-1) {
+                    properties = properties.substring(i+1);
+                 } else {
+                     break;
+                 }
+            } else {
+                throw new UserException(_loc.get("partition-cache-parse-error-paren", full, properties));
+            }
+        }
+    }
+}

Propchange: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/PartitionedDataCache.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java?rev=825768&r1=825767&r2=825768&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java Fri Oct 16 05:07:56 2009
@@ -3212,7 +3212,7 @@
 
             sm.evict();
             if (_evictDataCache && sm.getObjectId() != null) {
-                DataCache cache = sm.getMetaData().getDataCache();
+                DataCache cache = _conf.getDataCacheManagerInstance().selectCache(sm);
                 if (cache != null)
                     cache.remove(sm.getObjectId());
             }

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/InverseManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/InverseManager.java?rev=825768&r1=825767&r2=825768&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/InverseManager.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/InverseManager.java Fri Oct 16 05:07:56 2009
@@ -25,6 +25,7 @@
 
 import org.apache.openjpa.conf.OpenJPAConfiguration;
 import org.apache.openjpa.datacache.DataCache;
+import org.apache.openjpa.datacache.DataCacheManager;
 import org.apache.openjpa.lib.conf.Configurable;
 import org.apache.openjpa.lib.conf.Configuration;
 import org.apache.openjpa.lib.log.Log;
@@ -43,10 +44,11 @@
  */
 public class InverseManager implements Configurable {
 
-    private static final Localizer _loc = Localizer.forPackage
-        (InverseManager.class);
+    private static final Localizer _loc = Localizer.forPackage(InverseManager.class);
 
     protected static final Object NONE = new Object();
+    
+    protected DataCacheManager _mgr;
 
     /**
      * Constant representing the {@link #ACTION_MANAGE} action
@@ -121,6 +123,7 @@
 
     public void setConfiguration(Configuration conf) {
         _log = conf.getLog(OpenJPAConfiguration.LOG_RUNTIME);
+        _mgr = ((OpenJPAConfiguration)conf).getDataCacheManagerInstance();
     }
 
     /**
@@ -214,7 +217,7 @@
         // if the field isn't loaded in the state manager, it still might be
         // loaded in the data cache, in which case we still have to correct
         // it to keep the cache in sync
-        DataCache cache = sm.getMetaData().getDataCache();
+        DataCache cache = _mgr.selectCache(sm);
         if (cache == null)
             return false;
 

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PCData.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PCData.java?rev=825768&r1=825767&r2=825768&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PCData.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PCData.java Fri Oct 16 05:07:56 2009
@@ -104,4 +104,9 @@
      * Whether the given field index has stored data.
      */
     public boolean isLoaded(int i);
+    
+    /**
+     * Get the name of the cache where this data is stored.
+     */
+    public String getCache();
 }

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PCDataImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PCDataImpl.java?rev=825768&r1=825767&r2=825768&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PCDataImpl.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PCDataImpl.java Fri Oct 16 05:07:56 2009
@@ -34,7 +34,8 @@
     extends AbstractPCData {
 
     private final Object _oid;
-    private final Class _type;
+    private final Class<?> _type;
+    private final String _cache;
     private final Object[] _data;
     private final BitSet _loaded;
     private Object _version = null;
@@ -44,9 +45,10 @@
     /**
      * Constructor.
      */
-    public PCDataImpl(Object oid, ClassMetaData meta) {
+    public PCDataImpl(Object oid, ClassMetaData meta, String name) {
         _oid = oid;
         _type = meta.getDescribedType();
+        _cache = name;
 
         int len = meta.getFields().length;
         _data = new Object[len];
@@ -57,7 +59,7 @@
         return _oid;
     }
 
-    public Class getType() {
+    public Class<?> getType() {
         return _type;
     }
 
@@ -317,6 +319,10 @@
      * embedded instances. Returns a {@link PCDataImpl} by default.
      */
     public AbstractPCData newEmbeddedPCData(OpenJPAStateManager sm) {
-        return new PCDataImpl(sm.getId (), sm.getMetaData ());
+        return new PCDataImpl(sm.getId (), sm.getMetaData (), _cache);
 	}
+
+    public String getCache() {
+        return _cache;
+    }
 }

Modified: openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/datacache/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/datacache/localizer.properties?rev=825768&r1=825767&r2=825768&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/datacache/localizer.properties (original)
+++ openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/datacache/localizer.properties Fri Oct 16 05:07:56 2009
@@ -83,4 +83,33 @@
 	configuration string "{0}" are configured to be the default data cache. \
 	There must be one and only one cache whose name is "{1}", or whose name is \
 	not specified.
-	
+partition-cache-no-config: You have specified a partitioned cache but have not \
+	configured any partition. Consult OpenJPA documentation at \
+	http://openjpa.apache.org/builds/latest/docs/manual/manual.html on how to \
+	configure partitioned cache. 	
+partition-cache-parse-error-paren: Failed to configure cache partitions from the \
+	supplied configuration "{0}" while parsing the part "{1}" because this part \
+	is not enclosed by parentheses. The proper \
+	configuration string for cache partitions is '(p1),(p2),(p3)' i.e. each \
+	partition plug-in is enclosed in parentheses, separated by comma and the \
+	final string is enclosed by single quote.
+partition-cache-parse-error-comma: Failed to configure cache partitions from the \
+	supplied configuration "{0}" while parsing the part "{1}" because this part \
+	is not separated by comma. The proper \
+	configuration string for cache partitions is '(p1),(p2),(p3)' i.e. each \
+	partition plug-in is enclosed in parentheses, separated by comma and the \
+	final string is enclosed by single quote.	
+partition-cache-null-partition: You have not specified any name for a partition in \
+	the configuration "{0}". Each partition must have a name. \
+	Consult OpenJPA documentation at \
+	http://openjpa.apache.org/builds/latest/docs/manual/manual.html \
+	on how to configure partitioned cache. 
+partition-cache-duplicate-partition: You have specified duplicate name "{0}" for \
+    partitions in the configuration "{0}". The partition names must be unique. \
+	Consult OpenJPA documentation at \
+	http://openjpa.apache.org/builds/latest/docs/manual/manual.html \
+	on how to configure partitioned cache. 
+partition-cache-default-partition: You have specified name "{0}" for a \
+    partition in the configuration "{0}". The partition name matches the default \
+    name reserved by OpenJPA for internal use and hence can not be used.
+	
\ No newline at end of file

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestPartionedDataCache.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestPartionedDataCache.java?rev=825768&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestPartionedDataCache.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestPartionedDataCache.java Fri Oct 16 05:07:56 2009
@@ -0,0 +1,92 @@
+package org.apache.openjpa.persistence.datacache;
+
+import org.apache.openjpa.datacache.CacheDistributionPolicy;
+import org.apache.openjpa.datacache.ConcurrentDataCache;
+import org.apache.openjpa.datacache.DataCache;
+import org.apache.openjpa.datacache.PartitionedDataCache;
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.persistence.StoreCacheImpl;
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+import org.apache.openjpa.util.UserException;
+
+public class TestPartionedDataCache extends SingleEMFTestCase {
+    public void setUp() {
+        super.setUp("openjpa.DataCache", "partitioned(PartitionType=concurrent,partitions="+
+                "'(name=a,cacheSize=100),(name=b,cacheSize=200)')",
+                    "openjpa.RemoteCommitProvider", "sjvm",
+        "openjpa.DataCacheManager", 
+        "DistributionPolicy=org.apache.openjpa.persistence.datacache.TestPartionedDataCache$TestPolicy");
+    }
+    
+    public void testPropertyParsing() {
+        PartitionedDataCache cache = new PartitionedDataCache();
+        String badProperty = "(name=a,cacheSize=100),(name=b,cacheSize=200";// missing last bracket
+        try {
+            cache.setPartitions(badProperty);
+            fail("Expected parse error on " + badProperty);
+        } catch (UserException e) {
+            System.err.println(e);
+        }
+        badProperty = "(name=a,cacheSize=100)(name=b,cacheSize=200)";// missing comma
+        try {
+            cache.setPartitions(badProperty);
+            fail("Expected parse error on " + badProperty);
+        } catch (UserException e) {
+            System.err.println(e);
+        }
+        badProperty = "(cacheSize=100),(name=b,cacheSize=200)";// missing name
+        try {
+            cache.setPartitions(badProperty);
+            fail("Expected parse error on " + badProperty);
+        } catch (UserException e) {
+            System.err.println(e);
+        }
+        badProperty = "(name=a,cacheSize=100),(name=a,cacheSize=200)";// duplicate name
+        try {
+            cache.setPartitions(badProperty);
+            fail("Expected parse error on " + badProperty);
+        } catch (UserException e) {
+            System.err.println(e);
+        }
+        badProperty = "(name=default,cacheSize=100),(name=a,cacheSize=200)";// default name
+        try {
+            cache.setPartitions(badProperty);
+            fail("Expected parse error on " + badProperty);
+        } catch (UserException e) {
+            System.err.println(e);
+        }
+        
+    }
+    
+    public void testPolicy() {
+        CacheDistributionPolicy policy = emf.getConfiguration().getDataCacheManagerInstance().getDistributionPolicy();
+        assertNotNull(policy);
+        assertTrue(policy.getClass() + " not TestPolicy", policy instanceof TestPolicy);
+        
+    }
+    public void testPluginConfiguration() {
+        DataCache cache = ((StoreCacheImpl)emf.getStoreCache()).getDelegate();
+        assertTrue(cache instanceof PartitionedDataCache);
+        assertFalse(cache.getPartitionNames().isEmpty());
+        assertNotNull(cache.getPartition("a", false));
+        assertNotNull(cache.getPartition("b", false));
+        assertNull(cache.getPartition("c", false));
+        assertCacheConfiguration("a", 100);
+        assertCacheConfiguration("b", 200);
+    }
+    
+    void assertCacheConfiguration(String name, int size) {
+        DataCache cache = emf.getConfiguration().getDataCacheManagerInstance().getDataCache(name);
+        assertNotNull(cache);
+        assertTrue(cache instanceof ConcurrentDataCache);
+        assertEquals(size, ((ConcurrentDataCache)cache).getCacheSize());
+    }
+    
+    public static class TestPolicy implements CacheDistributionPolicy {
+
+        public String selectCache(OpenJPAStateManager sm, Object context) {
+            return "a";
+        }
+        
+    }
+}

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

Modified: openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_caching.xml
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_caching.xml?rev=825768&r1=825767&r2=825768&view=diff
==============================================================================
--- openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_caching.xml (original)
+++ openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_caching.xml Fri Oct 16 05:07:56 2009
@@ -151,6 +151,44 @@
 </programlisting>
             </example>
             <para>
+OpenJPA also supports a partitioned cache configuration where the cached
+instances can be distributed across partitions by a application-defined
+policy. Each partition is a data cache by itself, identified by its name and can
+configured individually. The distribution policy 
+determines the specific partition that stores the state of a managed instance.
+The default distribution policy distributes the instances by their type
+as specified by the <literal>name</literal> attribute in <literal>@DataCache</literal> 
+annotation. Cache distribution policy is a simple interface that can be implemented
+by an application to distribute among the partitions per instance basis.               
+To enable a partitioned cache set the <literal>openjpa.DataCache</literal>
+property to <literal>partitioned</literal>, and configure individual partitions
+as follows:
+            </para>
+            <example id="ref_guide_cache_conf_partition">
+                <title>
+                    Partitioned Data Cache
+                </title>
+<programlisting>
+&lt;property name="openjpa.DataCacheManager" value="DistributionPolicy=org.acme.foo.DistributionPolicy"/&gt;
+&lt;property name="openjpa.DataCache" value="partitioned(PartitionType=concurrent,partitions=
+                '(name=a,cacheSize=100),(name=b,cacheSize=200)')"/&gt;
+</programlisting>
+            </example>
+            <para>
+The distribution policy is configured by a full-qualified class name that implements 
+<literal>org.apache.openjpa.datacahe.CacheDistributionPolicy</lietral>. The partitions
+are specified as value of <literal>partitions</literal> attribute as a series of
+individually configurable plug-in strings. As the example shows, i) each partition plug-in configuration
+must be enclosed in parentheses, ii) must be separated by comma and iii) the complete
+set be enclosed in single quote. Each individual partition is a Data Cache by itself and
+class that implements the partition can be configured via <literal>PartitionType</literal>
+attribute. The above example configuration will configure a partitioned cache with
+two partitions named <literal>a</literal> and <literal>b</literal> of cache size 100 and 200
+respectively. The partitions are of <literal>concurrent</literal> type which is a mnemonic or alias
+for <literal>org.apache.openjpa.datacache.ConcurrentDataCache</literal>. The <literal>PartitionType</literal>
+is defaulted to <literal>concurrent</literal> though explicitly mentioned in this example.         
+            </para>
+            <para>
 To configure the data cache to remain up-to-date in a distributed environment,
 set the <link linkend="openjpa.RemoteCommitProvider"><literal>
 openjpa.RemoteCommitProvider</literal></link> property appropriately, or