summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Stepper2007-12-18 06:57:00 (EST)
committerEike Stepper2007-12-18 06:57:00 (EST)
commitc55189e3852dbeaf0511d0cf28a003a43b167357 (patch)
treeb79fe4e27be18ec7d8482f8e312524f56f76eefe
parent31bc13ad1648aa594520b4fdc5b6fa6c965c9c52 (diff)
downloadcdo-c55189e3852dbeaf0511d0cf28a003a43b167357.zip
cdo-c55189e3852dbeaf0511d0cf28a003a43b167357.tar.gz
cdo-c55189e3852dbeaf0511d0cf28a003a43b167357.tar.bz2
[209490] Put purging mechanism in CDOViewIMpl::objects to avoid OutOfMemory
https://bugs.eclipse.org/bugs/show_bug.cgi?id=209490
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java4
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/protocol/InvalidationNotification.java (renamed from plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/protocol/InvalidationRequest.java)6
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOViewImpl.java117
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ref/ReferenceValueMap.java75
4 files changed, 128 insertions, 74 deletions
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java
index 771bc76..f295a5e 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java
@@ -18,7 +18,7 @@ import org.eclipse.emf.cdo.internal.protocol.revision.CDOIDProvider;
import org.eclipse.emf.cdo.internal.protocol.revision.CDORevisionImpl;
import org.eclipse.emf.cdo.internal.server.bundle.OM;
import org.eclipse.emf.cdo.internal.server.protocol.CDOServerProtocol;
-import org.eclipse.emf.cdo.internal.server.protocol.InvalidationRequest;
+import org.eclipse.emf.cdo.internal.server.protocol.InvalidationNotification;
import org.eclipse.emf.cdo.protocol.CDOID;
import org.eclipse.emf.cdo.protocol.CDOProtocolConstants;
import org.eclipse.emf.cdo.protocol.model.CDOClassRef;
@@ -164,7 +164,7 @@ public class Session extends Container<IView> implements ISession, CDOIDProvider
{
try
{
- new InvalidationRequest(protocol.getChannel(), timeStamp, dirtyIDs).send();
+ new InvalidationNotification(protocol.getChannel(), timeStamp, dirtyIDs).send();
}
catch (Exception ex)
{
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/protocol/InvalidationRequest.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/protocol/InvalidationNotification.java
index b0b2085..59d41e1 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/protocol/InvalidationRequest.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/protocol/InvalidationNotification.java
@@ -26,15 +26,15 @@ import java.io.IOException;
/**
* @author Eike Stepper
*/
-public class InvalidationRequest extends Request
+public class InvalidationNotification extends Request
{
- private static final ContextTracer PROTOCOL = new ContextTracer(OM.DEBUG_PROTOCOL, InvalidationRequest.class);
+ private static final ContextTracer PROTOCOL = new ContextTracer(OM.DEBUG_PROTOCOL, InvalidationNotification.class);
private long timeStamp;
private CDOID[] dirtyIDs;
- public InvalidationRequest(IChannel channel, long timeStamp, CDOID[] dirtyIDs)
+ public InvalidationNotification(IChannel channel, long timeStamp, CDOID[] dirtyIDs)
{
super(channel);
this.timeStamp = timeStamp;
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOViewImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOViewImpl.java
index 8699112..485ad40 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOViewImpl.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOViewImpl.java
@@ -102,7 +102,7 @@ public class CDOViewImpl extends org.eclipse.net4j.internal.util.event.Notifier
protected ConcurrentMap<CDOID, InternalCDOObject> createObjectsMap()
{
- return new ReferenceValueMap.Soft<CDOID, InternalCDOObject>();
+ return new ReferenceValueMap.Weak<CDOID, InternalCDOObject>();
}
public int getViewID()
@@ -271,39 +271,47 @@ public class CDOViewImpl extends org.eclipse.net4j.internal.util.event.Notifier
}
lastLookupID = id;
- lastLookupObject = objects.get(id);
- if (lastLookupObject == null)
+ synchronized (objects)
{
- if (id.isMeta())
+ lastLookupObject = objects.get(id);
+ if (lastLookupObject == null)
{
- lastLookupObject = createMetaObject(id);
- }
- else
- {
- if (loadOnDemand)
+ if (id.isMeta())
{
- lastLookupObject = createObject(id);
+ lastLookupObject = createMetaObject(id);
}
else
{
- lastLookupObject = createProxy(id);
+ if (loadOnDemand)
+ {
+ lastLookupObject = createObject(id);
+ }
+ else
+ {
+ lastLookupObject = createProxy(id);
+ }
}
- }
- registerObject(lastLookupObject);
+ registerObject(lastLookupObject);
+ }
}
-
return lastLookupObject;
}
public boolean isObjectRegistered(CDOID id)
{
- return objects.containsKey(id);
+ synchronized (objects)
+ {
+ return objects.containsKey(id);
+ }
}
public InternalCDOObject removeObject(CDOID id)
{
- return objects.remove(id);
+ synchronized (objects)
+ {
+ return objects.remove(id);
+ }
}
/**
@@ -475,7 +483,12 @@ public class CDOViewImpl extends org.eclipse.net4j.internal.util.event.Notifier
TRACER.format("Registering {0}", object);
}
- InternalCDOObject old = objects.put(object.cdoID(), object);
+ InternalCDOObject old;
+ synchronized (objects)
+ {
+ old = objects.put(object.cdoID(), object);
+ }
+
if (old != null)
{
throw new IllegalStateException("Duplicate ID: " + object);
@@ -489,7 +502,12 @@ public class CDOViewImpl extends org.eclipse.net4j.internal.util.event.Notifier
TRACER.format("Deregistering {0}", object);
}
- InternalCDOObject old = objects.remove(object.cdoID());
+ InternalCDOObject old;
+ synchronized (objects)
+ {
+ old = objects.remove(object.cdoID());
+ }
+
if (old == null)
{
throw new IllegalStateException("Unknown ID: " + object);
@@ -498,47 +516,20 @@ public class CDOViewImpl extends org.eclipse.net4j.internal.util.event.Notifier
public void remapObject(CDOID oldID)
{
- InternalCDOObject object = objects.remove(oldID);
- CDOID newID = object.cdoID();
- objects.put(newID, object);
+ CDOID newID;
+ synchronized (objects)
+ {
+ InternalCDOObject object = objects.remove(oldID);
+ newID = object.cdoID();
+ objects.put(newID, object);
+ }
+
if (TRACER.isEnabled())
{
TRACER.format("Remapping {0} --> {1}", oldID, newID);
}
}
- // public final class HistoryEntryImpl implements HistoryEntry, Comparable
- // {
- // private String resourcePath;
- //
- // private HistoryEntryImpl(String resourcePath)
- // {
- // this.resourcePath = resourcePath;
- // }
- //
- // public CDOView getView()
- // {
- // return CDOViewImpl.this;
- // }
- //
- // public String getResourcePath()
- // {
- // return resourcePath;
- // }
- //
- // public int compareTo(Object o)
- // {
- // HistoryEntry that = (HistoryEntry)o;
- // return resourcePath.compareTo(that.getResourcePath());
- // }
- //
- // @Override
- // public String toString()
- // {
- // return resourcePath;
- // }
- // }
-
/**
* Turns registered objects into proxies and synchronously delivers invalidation events to registered event listeners.
* <p>
@@ -558,15 +549,20 @@ public class CDOViewImpl extends org.eclipse.net4j.internal.util.event.Notifier
List<InternalCDOObject> dirtyObjects = enableInvalidationNotifications ? new ArrayList<InternalCDOObject>() : null;
for (CDOID dirtyOID : dirtyOIDs)
{
- InternalCDOObject dirtyObject = objects.get(dirtyOID);
- if (dirtyObject != null)
+ InternalCDOObject dirtyObject;
+ synchronized (objects)
{
- CDOStateMachine.INSTANCE.invalidate(dirtyObject, timeStamp);
- if (dirtyObjects != null && dirtyObject.eNotificationRequired())
+ dirtyObject = objects.get(dirtyOID);
+ if (dirtyObject != null)
{
- dirtyObjects.add(dirtyObject);
+ CDOStateMachine.INSTANCE.invalidate(dirtyObject, timeStamp);
}
}
+
+ if (dirtyObject != null && dirtyObjects != null && dirtyObject.eNotificationRequired())
+ {
+ dirtyObjects.add(dirtyObject);
+ }
}
if (dirtyObjects != null)
@@ -595,7 +591,10 @@ public class CDOViewImpl extends org.eclipse.net4j.internal.util.event.Notifier
}
else
{
- internalObjects = this.objects.values();
+ synchronized (objects)
+ {
+ internalObjects = new ArrayList<InternalCDOObject>(this.objects.values());
+ }
}
int result = internalObjects.size();
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ref/ReferenceValueMap.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ref/ReferenceValueMap.java
index dc605dd..d9fd2ed 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ref/ReferenceValueMap.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ref/ReferenceValueMap.java
@@ -10,7 +10,6 @@
**************************************************************************/
package org.eclipse.net4j.util.ref;
-import org.eclipse.net4j.util.ObjectUtil;
import org.eclipse.net4j.util.collection.MapEntry;
import java.lang.ref.ReferenceQueue;
@@ -18,11 +17,22 @@ import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Iterator;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
+ * A {@link ConcurrentMap} implementation that uses {@link KeyedReference} instances ({@link KeyedReference#Strong Strong},
+ * {@link KeyedReference#Soft Soft}, {@link KeyedReference#Weak Weak} or {@link KeyedReference#Phantom Phantom}) as
+ * its values.
+ * <p>
+ * A <code>ReferenceValueMap</code> can be used to cache mappings until the <em>value</em> of the mapping is no
+ * longer reachable from outside of the map
+ * <p>
+ * <b>Note:</b> This map is not synchronized. If it is to be used by multiple threads concurrently the user is
+ * responsible for applying proper external synchronization!
+ *
* @author Eike Stepper
*/
public abstract class ReferenceValueMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
@@ -69,9 +79,9 @@ public abstract class ReferenceValueMap<K, V> extends AbstractMap<K, V> implemen
KeyedReference<K, V> ref = map.get(key);
if (ref != null)
{
- if (ref.isEnqueued())
+ if (ref.get() == null)
{
- map.remove(key);
+ ref.enqueue();
return false;
}
@@ -91,7 +101,14 @@ public abstract class ReferenceValueMap<K, V> extends AbstractMap<K, V> implemen
for (KeyedReference<K, V> ref : map.values())
{
- if (!ref.isEnqueued() && ObjectUtil.equals(value, dereference(ref)))
+ V v = ref.get();
+ if (v == null)
+ {
+ ref.enqueue();
+ return false;
+ }
+
+ if (value.equals(v))
{
return true;
}
@@ -221,7 +238,13 @@ public abstract class ReferenceValueMap<K, V> extends AbstractMap<K, V> implemen
return null;
}
- return ref.get();
+ V value = ref.get();
+ if (value == null)
+ {
+ ref.enqueue();
+ }
+
+ return value;
}
protected abstract KeyedReference<K, V> createReference(K key, V value, ReferenceQueue<V> queue);
@@ -413,6 +436,8 @@ public abstract class ReferenceValueMap<K, V> extends AbstractMap<K, V> implemen
{
private Iterator<Entry<K, KeyedReference<K, V>>> it = map.entrySet().iterator();
+ private MapEntry<K, V> nextEntry;
+
private K lastKey;
public EntrySetIterator()
@@ -421,15 +446,44 @@ public abstract class ReferenceValueMap<K, V> extends AbstractMap<K, V> implemen
public boolean hasNext()
{
- return it.hasNext();
+ if (nextEntry != null)
+ {
+ return true;
+ }
+
+ while (it.hasNext())
+ {
+ Entry<K, KeyedReference<K, V>> entry = it.next();
+ lastKey = entry.getKey();
+ V value = dereference(entry.getValue());
+ if (value != null)
+ {
+ nextEntry = new MapEntry<K, V>(lastKey, value);
+ return true;
+ }
+ }
+
+ return false;
}
public Entry<K, V> next()
{
- Entry<K, KeyedReference<K, V>> entry = it.next();
- lastKey = entry.getKey();
- V value = dereference(entry.getValue());
- return new MapEntry<K, V>(lastKey, value);
+ if (nextEntry == null)
+ {
+ if (!hasNext())
+ {
+ throw new NoSuchElementException();
+ }
+ }
+
+ try
+ {
+ return nextEntry;
+ }
+ finally
+ {
+ nextEntry = null;
+ }
}
public void remove()
@@ -441,6 +495,7 @@ public abstract class ReferenceValueMap<K, V> extends AbstractMap<K, V> implemen
map.remove(lastKey);
lastKey = null;
+ nextEntry = null;
}
}
}