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 2012/02/22 19:33:14 UTC
svn commit: r1292437 - in
/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access:
DataRowStore.java HierarchicalObjectResolver.java ObjectStore.java
Author: aadamchik
Date: Wed Feb 22 18:33:14 2012
New Revision: 1292437
URL: http://svn.apache.org/viewvc?rev=1292437&view=rev
Log:
CAY-1670 Non-blocking DataRowStore
switching DataRowStore to concurrentlinkedhashmap
REMOVING SYNCHRONIZATION
Modified:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataRowStore.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolver.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ObjectStore.java
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataRowStore.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataRowStore.java?rev=1292437&r1=1292436&r2=1292437&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataRowStore.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataRowStore.java Wed Feb 22 18:33:14 2012
@@ -28,6 +28,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
import org.apache.cayenne.CayenneRuntimeException;
import org.apache.cayenne.DataObject;
@@ -40,17 +41,13 @@ import org.apache.cayenne.event.EventBri
import org.apache.cayenne.event.EventBridgeFactory;
import org.apache.cayenne.event.EventManager;
import org.apache.cayenne.event.EventSubject;
+import org.apache.cayenne.util.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
import org.apache.commons.collections.ExtendedProperties;
-import org.apache.commons.collections.map.LRUMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* A fixed size cache of DataRows keyed by ObjectId.
- * <p>
- * <strong>Synchronization Note: </strong> DataRowStore synchronizes most operations on
- * its own instance.
- * </p>
*
* @since 1.1
*/
@@ -76,7 +73,8 @@ public class DataRowStore implements Ser
public static final String EVENT_BRIDGE_FACTORY_DEFAULT = "org.apache.cayenne.event.JavaGroupsBridgeFactory";
protected String name;
- protected LRUMap snapshots;
+ private int maxSize;
+ protected ConcurrentMap<ObjectId, DataRow> snapshots;
protected boolean notifyingRemoteListeners;
protected transient EventManager eventManager;
@@ -124,7 +122,7 @@ public class DataRowStore implements Ser
SNAPSHOT_EXPIRATION_PROPERTY,
SNAPSHOT_EXPIRATION_DEFAULT);
- int snapshotsCacheSize = propertiesWrapper.getInt(
+ maxSize = propertiesWrapper.getInt(
SNAPSHOT_CACHE_SIZE_PROPERTY,
SNAPSHOT_CACHE_SIZE_DEFAULT);
@@ -144,7 +142,7 @@ public class DataRowStore implements Ser
logger.debug("DataRowStore property "
+ SNAPSHOT_CACHE_SIZE_PROPERTY
+ " = "
- + snapshotsCacheSize);
+ + maxSize);
logger.debug("DataRowStore property "
+ REMOTE_NOTIFICATION_PROPERTY
+ " = "
@@ -158,8 +156,9 @@ public class DataRowStore implements Ser
// init ivars from properties
this.notifyingRemoteListeners = notifyRemote;
- // TODO: ENTRY EXPIRATION is not supported by commons LRU Map
- this.snapshots = new LRUMap(snapshotsCacheSize);
+ this.snapshots = new ConcurrentLinkedHashMap.Builder<ObjectId, DataRow>()
+ .maximumWeightedCapacity(maxSize)
+ .build();
// init event bridge only if we are notifying remote listeners
if (notifyingRemoteListeners) {
@@ -206,61 +205,59 @@ public class DataRowStore implements Ser
Map modified = null;
Object eventPostedBy = null;
- synchronized (this) {
- for (int i = 0; i < size; i++) {
- Persistent object = (Persistent) objects.get(i);
-
- // skip null objects... possible since 3.0 in some EJBQL results
- if (object == null) {
- continue;
- }
+ for (int i = 0; i < size; i++) {
+ Persistent object = (Persistent) objects.get(i);
- // skip HOLLOW objects as they likely were created from partial snapshots
- if (object.getPersistenceState() == PersistenceState.HOLLOW) {
- continue;
- }
+ // skip null objects... possible since 3.0 in some EJBQL results
+ if (object == null) {
+ continue;
+ }
+
+ // skip HOLLOW objects as they likely were created from partial snapshots
+ if (object.getPersistenceState() == PersistenceState.HOLLOW) {
+ continue;
+ }
- ObjectId oid = object.getObjectId();
+ ObjectId oid = object.getObjectId();
- // add snapshots if refresh is forced, or if a snapshot is
- // missing
+ // add snapshots if refresh is forced, or if a snapshot is
+ // missing
- DataRow cachedSnapshot = (DataRow) this.snapshots.get(oid);
- if (refresh || cachedSnapshot == null) {
+ DataRow cachedSnapshot = this.snapshots.get(oid);
+ if (refresh || cachedSnapshot == null) {
- DataRow newSnapshot = (DataRow) snapshots.get(i);
-
- if (cachedSnapshot != null) {
- // use old snapshot if no changes occurred
- if (object instanceof DataObject
- && cachedSnapshot.equals(newSnapshot)) {
- ((DataObject) object).setSnapshotVersion(cachedSnapshot
- .getVersion());
- continue;
- }
- else {
- newSnapshot.setReplacesVersion(cachedSnapshot.getVersion());
- }
- }
+ DataRow newSnapshot = (DataRow) snapshots.get(i);
- if (modified == null) {
- modified = new HashMap();
- eventPostedBy = object.getObjectContext().getGraphManager();
+ if (cachedSnapshot != null) {
+ // use old snapshot if no changes occurred
+ if (object instanceof DataObject
+ && cachedSnapshot.equals(newSnapshot)) {
+ ((DataObject) object).setSnapshotVersion(cachedSnapshot
+ .getVersion());
+ continue;
+ }
+ else {
+ newSnapshot.setReplacesVersion(cachedSnapshot.getVersion());
}
+ }
- modified.put(oid, newSnapshot);
+ if (modified == null) {
+ modified = new HashMap();
+ eventPostedBy = object.getObjectContext().getGraphManager();
}
- }
- if (modified != null) {
- processSnapshotChanges(
- eventPostedBy,
- modified,
- Collections.EMPTY_LIST,
- Collections.EMPTY_LIST,
- Collections.EMPTY_LIST);
+ modified.put(oid, newSnapshot);
}
}
+
+ if (modified != null) {
+ processSnapshotChanges(
+ eventPostedBy,
+ modified,
+ Collections.EMPTY_LIST,
+ Collections.EMPTY_LIST,
+ Collections.EMPTY_LIST);
+ }
}
/**
@@ -274,7 +271,7 @@ public class DataRowStore implements Ser
* Returns maximum allowed cache size.
*/
public int maximumSize() {
- return snapshots.maxSize();
+ return maxSize;
}
/**
@@ -327,8 +324,8 @@ public class DataRowStore implements Ser
* Returns cached snapshot or null if no snapshot is currently cached for the given
* ObjectId.
*/
- public synchronized DataRow getCachedSnapshot(ObjectId oid) {
- return (DataRow) snapshots.get(oid);
+ public DataRow getCachedSnapshot(ObjectId oid) {
+ return snapshots.get(oid);
}
/**
@@ -341,14 +338,14 @@ public class DataRowStore implements Ser
/**
* Expires and removes all stored snapshots without sending any notification events.
*/
- public synchronized void clear() {
+ public void clear() {
snapshots.clear();
}
/**
* Evicts a snapshot from cache without generating any SnapshotEvents.
*/
- public synchronized void forgetSnapshot(ObjectId id) {
+ public void forgetSnapshot(ObjectId id) {
snapshots.remove(id);
}
@@ -378,17 +375,15 @@ public class DataRowStore implements Ser
return;
}
- synchronized (this) {
- processDeletedIDs(deletedSnapshotIds);
- processInvalidatedIDs(invalidatedSnapshotIds);
- processUpdateDiffs(diffs);
- sendUpdateNotification(
- event.getPostedBy(),
- diffs,
- deletedSnapshotIds,
- invalidatedSnapshotIds,
- indirectlyModifiedIds);
- }
+ processDeletedIDs(deletedSnapshotIds);
+ processInvalidatedIDs(invalidatedSnapshotIds);
+ processUpdateDiffs(diffs);
+ sendUpdateNotification(
+ event.getPostedBy(),
+ diffs,
+ deletedSnapshotIds,
+ invalidatedSnapshotIds,
+ indirectlyModifiedIds);
}
/**
@@ -412,17 +407,15 @@ public class DataRowStore implements Ser
return;
}
- synchronized (this) {
- processDeletedIDs(deletedSnapshotIds);
- processInvalidatedIDs(invalidatedSnapshotIds);
- Map diffs = processUpdatedSnapshots(updatedSnapshots);
- sendUpdateNotification(
- postedBy,
- diffs,
- deletedSnapshotIds,
- invalidatedSnapshotIds,
- indirectlyModifiedIds);
- }
+ processDeletedIDs(deletedSnapshotIds);
+ processInvalidatedIDs(invalidatedSnapshotIds);
+ Map diffs = processUpdatedSnapshots(updatedSnapshots);
+ sendUpdateNotification(
+ postedBy,
+ diffs,
+ deletedSnapshotIds,
+ invalidatedSnapshotIds,
+ indirectlyModifiedIds);
}
private void processDeletedIDs(Collection deletedSnapshotIDs) {
@@ -456,7 +449,7 @@ public class DataRowStore implements Ser
ObjectId key = (ObjectId) entry.getKey();
DataRow newSnapshot = (DataRow) entry.getValue();
- DataRow oldSnapshot = (DataRow) snapshots.put(key, newSnapshot);
+ DataRow oldSnapshot = snapshots.put(key, newSnapshot);
// generate diff for the updated event, if this not a new
// snapshot
@@ -490,7 +483,7 @@ public class DataRowStore implements Ser
+ ", New: "
+ newSnapshot);
}
-
+
forgetSnapshot(key);
continue;
}
@@ -518,7 +511,7 @@ public class DataRowStore implements Ser
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
ObjectId key = (ObjectId) entry.getKey();
- DataRow oldSnapshot = (DataRow) snapshots.remove(key);
+ DataRow oldSnapshot = snapshots.remove(key);
if (oldSnapshot == null) {
continue;
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolver.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolver.java?rev=1292437&r1=1292436&r2=1292437&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolver.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolver.java Wed Feb 22 18:33:14 2012
@@ -68,9 +68,7 @@ class HierarchicalObjectResolver {
Map extraResultsByPath) {
synchronized (context.getObjectStore()) {
- synchronized (cache) {
- return resolveObjectTree(tree, mainResultRows, extraResultsByPath);
- }
+ return resolveObjectTree(tree, mainResultRows, extraResultsByPath);
}
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ObjectStore.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ObjectStore.java?rev=1292437&r1=1292436&r2=1292437&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ObjectStore.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ObjectStore.java Wed Feb 22 18:33:14 2012
@@ -63,10 +63,6 @@ import org.apache.commons.collections.ma
*
* @since 1.0
*/
-// Synchronization Note: There is often a need to do double synchronize on an ObjectStore
-// and an underlying DataRowCache. To avoid deadlocks, Cayenne consistently follows the
-// policy of locking an ObjectStore first, and then locking DataRowStore. This pattern
-// must be followed in any new related developments.
public class ObjectStore implements Serializable, SnapshotEventListener, GraphManager {
/**