This is an automated email from the ASF dual-hosted git repository.

ntimofeev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git


The following commit(s) were added to refs/heads/master by this push:
     new 2ff64413d Revert "CAY-2876 Memory leak in the ObjectStore"
2ff64413d is described below

commit 2ff64413d4a7c7d1f98ac59f74770e166545ed21
Author: Nikita Timofeev <stari...@gmail.com>
AuthorDate: Mon Mar 10 16:13:34 2025 +0400

    Revert "CAY-2876 Memory leak in the ObjectStore"
    
    This reverts commit bf344662776351b64deb1fdf0bbe0676db86c92e.
---
 RELEASE-NOTES.txt                                  |   1 -
 .../commitlog/CommitLogFilter_All_FlattenedIT.java |  10 +-
 .../access/DefaultObjectMapRetainStrategy.java     |   4 +-
 .../apache/cayenne/access/NoSyncObjectStore.java   |   4 +-
 .../java/org/apache/cayenne/access/ObjectDiff.java |  43 ++---
 .../cayenne/access/ObjectMapRetainStrategy.java    |   4 +-
 .../org/apache/cayenne/access/ObjectStore.java     | 195 ++++++++++-----------
 .../apache/cayenne/access/ObjectStoreEntry.java    |  70 --------
 .../cayenne/access/ObjectStoreGraphDiff.java       |   7 +-
 .../access/DataContextPrefetchMultistepIT.java     |   2 +-
 .../cayenne/access/DataContextSerializationIT.java |   4 +-
 .../org/apache/cayenne/access/ObjectStoreTest.java |   2 +-
 12 files changed, 127 insertions(+), 219 deletions(-)

diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 52ab66e33..f964462b3 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -21,7 +21,6 @@ Bug Fixes:
 CAY-2701 MySQL DST-related LocalDateTime issues
 CAY-2871 QualifierTranslator breaks on a relationship with a compound FK
 CAY-2872 CayenneModeler "Documentation" link is broken
-CAY-2876 Memory leak in the ObjectStore
 CAY-2879 Negative number for non parameterized ObjectSelect query not 
processed correctly
 
 ----------------------------------
diff --git 
a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/CommitLogFilter_All_FlattenedIT.java
 
b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/CommitLogFilter_All_FlattenedIT.java
index 63c0f1a6e..7a755890a 100644
--- 
a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/CommitLogFilter_All_FlattenedIT.java
+++ 
b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/CommitLogFilter_All_FlattenedIT.java
@@ -27,8 +27,6 @@ import org.apache.cayenne.commitlog.model.ObjectChange;
 import org.apache.cayenne.commitlog.model.ObjectChangeType;
 import org.apache.cayenne.commitlog.model.ToManyRelationshipChange;
 import org.apache.cayenne.commitlog.unit.FlattenedRuntimeCase;
-import org.apache.cayenne.configuration.Constants;
-import org.apache.cayenne.configuration.runtime.CoreModule;
 import org.apache.cayenne.query.SelectById;
 import org.apache.cayenne.runtime.CayenneRuntimeBuilder;
 import org.junit.Before;
@@ -50,8 +48,6 @@ public class CommitLogFilter_All_FlattenedIT extends 
FlattenedRuntimeCase {
        protected CayenneRuntimeBuilder configureCayenne() {
                this.mockListener = mock(CommitLogListener.class);
                return super.configureCayenne()
-                               .addModule(b -> CoreModule.extend(b)
-                                               
.setProperty(Constants.OBJECT_RETAIN_STRATEGY_PROPERTY, "soft"))
                                .addModule(b -> 
CommitLogModule.extend(b).addListener(mockListener));
        }
 
@@ -67,9 +63,9 @@ public class CommitLogFilter_All_FlattenedIT extends 
FlattenedRuntimeCase {
                e4.insert(12);
                e34.insert(1, 11);
 
-               E3 e3 = SelectById.queryId(E3.class, 1).selectOne(context);
-               E4 e4_1 = SelectById.queryId(E4.class, 11).selectOne(context);
-               E4 e4_2 = SelectById.queryId(E4.class, 12).selectOne(context);
+               E3 e3 = SelectById.query(E3.class, 1).selectOne(context);
+               E4 e4_1 = SelectById.query(E4.class, 11).selectOne(context);
+               E4 e4_2 = SelectById.query(E4.class, 12).selectOne(context);
 
                doAnswer((Answer<Object>) invocation -> {
 
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/DefaultObjectMapRetainStrategy.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/DefaultObjectMapRetainStrategy.java
index 8fcbf42db..05f248ed8 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/DefaultObjectMapRetainStrategy.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/DefaultObjectMapRetainStrategy.java
@@ -22,7 +22,7 @@ import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.Persistent;
 import org.apache.cayenne.configuration.Constants;
 import org.apache.cayenne.configuration.RuntimeProperties;
 import org.apache.cayenne.di.Inject;
@@ -46,7 +46,7 @@ public class DefaultObjectMapRetainStrategy implements 
ObjectMapRetainStrategy {
         this.runtimeProperties = runtimeProperties;
     }
 
-    public Map<ObjectId, ObjectStoreEntry> createObjectMap() {
+    public Map<Object, Persistent> createObjectMap() {
         String strategy = 
runtimeProperties.get(Constants.OBJECT_RETAIN_STRATEGY_PROPERTY);
 
         if (strategy == null || WEAK_RETAIN_STRATEGY.equals(strategy)) {
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/NoSyncObjectStore.java 
b/cayenne/src/main/java/org/apache/cayenne/access/NoSyncObjectStore.java
index 914543a23..9358c08d2 100644
--- a/cayenne/src/main/java/org/apache/cayenne/access/NoSyncObjectStore.java
+++ b/cayenne/src/main/java/org/apache/cayenne/access/NoSyncObjectStore.java
@@ -20,7 +20,7 @@ package org.apache.cayenne.access;
 
 import java.util.Map;
 
-import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.Persistent;
 
 /**
  * An {@link ObjectStore} which doesn't receive notifications 
@@ -30,7 +30,7 @@ import org.apache.cayenne.ObjectId;
  */
 public class NoSyncObjectStore extends ObjectStore {
     
-    public NoSyncObjectStore(DataRowStore dataRowCache, Map<ObjectId, 
ObjectStoreEntry> objectMap) {
+    public NoSyncObjectStore(DataRowStore dataRowCache, Map<Object, 
Persistent> objectMap) {
         super(dataRowCache, objectMap);
     }
     
diff --git a/cayenne/src/main/java/org/apache/cayenne/access/ObjectDiff.java 
b/cayenne/src/main/java/org/apache/cayenne/access/ObjectDiff.java
index 6ae2df6d3..9b2b68de4 100644
--- a/cayenne/src/main/java/org/apache/cayenne/access/ObjectDiff.java
+++ b/cayenne/src/main/java/org/apache/cayenne/access/ObjectDiff.java
@@ -65,22 +65,23 @@ public class ObjectDiff extends NodeDiff {
     private Map<ArcOperation, ArcOperation> flatIds;
     private Map<ArcOperation, ArcOperation> phantomFks;
 
-    private final ObjectStoreEntry entry;
+    private Persistent object;
 
-    ObjectDiff(final ObjectStoreEntry entry) {
+    ObjectDiff(final Persistent object) {
 
-        super(entry.persistent().getObjectId());
+        super(object.getObjectId());
 
-        // retain the object, as ObjectStore may have weak references to 
registered objects,
-        // and we can't allow it to deallocate dirty objects.
-        this.entry = entry;
+        // retain the object, as ObjectStore may have weak references to
+        // registered
+        // objects and we can't allow it to deallocate dirty objects.
+        this.object = object;
 
-        EntityResolver entityResolver = 
object().getObjectContext().getEntityResolver();
+        EntityResolver entityResolver = 
object.getObjectContext().getEntityResolver();
 
-        this.entityName = object().getObjectId().getEntityName();
+        this.entityName = object.getObjectId().getEntityName();
         this.classDescriptor = entityResolver.getClassDescriptor(entityName);
 
-        int state = object().getPersistenceState();
+        int state = object.getPersistenceState();
 
         // take snapshot of simple properties and arcs used for optimistic
         // locking..
@@ -98,7 +99,7 @@ public class ObjectDiff extends NodeDiff {
 
                 @Override
                 public boolean visitAttribute(AttributeProperty property) {
-                    snapshot.put(property.getName(), 
property.readProperty(object()));
+                    snapshot.put(property.getName(), 
property.readProperty(object));
                     return true;
                 }
 
@@ -113,8 +114,8 @@ public class ObjectDiff extends NodeDiff {
                     
                     // eagerly resolve optimistically locked relationships
                     Object target = (lock && isUsedForLocking)
-                            ? property.readProperty(object())
-                            : property.readPropertyDirectly(object());
+                            ? property.readProperty(object)
+                            : property.readPropertyDirectly(object);
 
                     if (target instanceof Persistent) {
                         target = ((Persistent) target).getObjectId();
@@ -128,15 +129,15 @@ public class ObjectDiff extends NodeDiff {
         }
     }
 
-    Persistent object() {
-        return entry.persistent();
+    Object getObject() {
+        return object;
     }
 
     ClassDescriptor getClassDescriptor() {
         // class descriptor is initiated in constructor, but is nullified on
         // serialization
         if (classDescriptor == null) {
-            EntityResolver entityResolver = 
object().getObjectContext().getEntityResolver();
+            EntityResolver entityResolver = 
object.getObjectContext().getEntityResolver();
             this.classDescriptor = 
entityResolver.getClassDescriptor(entityName);
         }
 
@@ -151,7 +152,7 @@ public class ObjectDiff extends NodeDiff {
         Object value = arcSnapshot != null ? arcSnapshot.get(propertyName) : 
null;
 
         if (value instanceof Fault) {
-            Persistent target = (Persistent) ((Fault) 
value).resolveFault(object(), propertyName);
+            Persistent target = (Persistent) ((Fault) 
value).resolveFault(object, propertyName);
 
             value = target != null ? target.getObjectId() : null;
             arcSnapshot.put(propertyName, value);
@@ -166,7 +167,7 @@ public class ObjectDiff extends NodeDiff {
     public ObjectId getCurrentArcSnapshotValue(String propertyName) {
         Object value = currentArcSnapshot != null ? 
currentArcSnapshot.get(propertyName) : null;
         if (value instanceof Fault) {
-            Persistent target = (Persistent) ((Fault) 
value).resolveFault(object(), propertyName);
+            Persistent target = (Persistent) ((Fault) 
value).resolveFault(object, propertyName);
 
             value = target != null ? target.getObjectId() : null;
             currentArcSnapshot.put(propertyName, value);
@@ -327,7 +328,7 @@ public class ObjectDiff extends NodeDiff {
             return false;
         }
 
-        int state = object().getPersistenceState();
+        int state = object.getPersistenceState();
         if (state == PersistenceState.NEW || state == 
PersistenceState.DELETED) {
             return false;
         }
@@ -341,7 +342,7 @@ public class ObjectDiff extends NodeDiff {
             public boolean visitAttribute(AttributeProperty property) {
 
                 Object oldValue = snapshot.get(property.getName());
-                Object newValue = property.readProperty(object());
+                Object newValue = property.readProperty(object);
 
                 if (!property.equals(oldValue, newValue)) {
                     modFound[0] = true;
@@ -362,7 +363,7 @@ public class ObjectDiff extends NodeDiff {
                     return true;
                 }
 
-                Object newValue = property.readPropertyDirectly(object());
+                Object newValue = property.readPropertyDirectly(object);
                 if (newValue instanceof Fault) {
                     return true;
                 }
@@ -410,7 +411,7 @@ public class ObjectDiff extends NodeDiff {
             @Override
             public boolean visitAttribute(AttributeProperty property) {
 
-                Object newValue = property.readProperty(object());
+                Object newValue = property.readProperty(object);
 
                 // no baseline to compare
                 if (snapshot == null) {
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/ObjectMapRetainStrategy.java 
b/cayenne/src/main/java/org/apache/cayenne/access/ObjectMapRetainStrategy.java
index 3749298d0..8d1e4fbb9 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/ObjectMapRetainStrategy.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/ObjectMapRetainStrategy.java
@@ -20,7 +20,7 @@ package org.apache.cayenne.access;
 
 import java.util.Map;
 
-import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.Persistent;
 
 /**
  * A strategy for retaining objects in {@link ObjectStore}. The strategy can 
be weak, soft
@@ -30,5 +30,5 @@ import org.apache.cayenne.ObjectId;
  */
 public interface ObjectMapRetainStrategy {
 
-    Map<ObjectId, ObjectStoreEntry> createObjectMap();
+    Map<Object, Persistent> createObjectMap();
 }
diff --git a/cayenne/src/main/java/org/apache/cayenne/access/ObjectStore.java 
b/cayenne/src/main/java/org/apache/cayenne/access/ObjectStore.java
index ff7f2facd..0dcdc7aa1 100644
--- a/cayenne/src/main/java/org/apache/cayenne/access/ObjectStore.java
+++ b/cayenne/src/main/java/org/apache/cayenne/access/ObjectStore.java
@@ -53,7 +53,7 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * ObjectStore stores objects using their ObjectId as a key. It works as a 
dedicated
@@ -65,16 +65,14 @@ import java.util.concurrent.atomic.AtomicInteger;
  */
 public class ObjectStore implements Serializable, SnapshotEventListener, 
GraphManager {
 
-    protected Map<ObjectId, ObjectStoreEntry> objectMap;
+    protected Map<Object, Persistent> objectMap;
     protected Map<Object, ObjectDiff> changes;
 
     /**
      * Map that tracks flattened paths for given object Id that is present in 
db.
      * Presence of path in this map is used to separate insert from update 
case of flattened records.
      * @since 4.1
-     * @deprecated since 5.0 unused
      */
-    @Deprecated
     protected Map<Object, Map<CayennePath, ObjectId>> trackedFlattenedPaths;
 
     // a sequential id used to tag GraphDiffs so that they can later be sorted 
in the
@@ -108,7 +106,7 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
      * 
      * @since 3.0
      */
-    public ObjectStore(DataRowStore dataRowCache, Map<ObjectId, 
ObjectStoreEntry> objectMap) {
+    public ObjectStore(DataRowStore dataRowCache, Map<Object, Persistent> 
objectMap) {
         setDataRowCache(dataRowCache);
         if (objectMap != null) {
             this.objectMap = objectMap;
@@ -139,7 +137,7 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
     Collection<GraphDiff> getLifecycleEventInducedChanges() {
         return lifecycleEventInducedChanges != null
                 ? lifecycleEventInducedChanges
-                : Collections.emptyList();
+                : Collections.<GraphDiff>emptyList();
     }
 
     void registerLifecycleEventInducedChange(GraphDiff diff) {
@@ -167,13 +165,11 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
 
         if (objectDiff == null) {
 
-            ObjectStoreEntry entry = objectMap.get((ObjectId)nodeId);
-            if (entry == null || !entry.hasObject()) {
+            Persistent object = objectMap.get(nodeId);
+            if (object == null) {
                 throw new CayenneRuntimeException("No object is registered in 
context with Id %s", nodeId);
             }
 
-            Persistent object = entry.persistent();
-
             if (object.getPersistenceState() == PersistenceState.COMMITTED) {
                 object.setPersistenceState(PersistenceState.MODIFIED);
 
@@ -200,7 +196,7 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
                 }
             }
 
-            objectDiff = new ObjectDiff(entry);
+            objectDiff = new ObjectDiff(object);
             objectDiff.setDiffId(++currentDiffId);
             changes.put(nodeId, objectDiff);
         }
@@ -218,13 +214,7 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
      * @since 1.2
      */
     public int registeredObjectsCount() {
-        AtomicInteger counter = new AtomicInteger();
-        objectMap.forEach((id, obj) -> {
-            if(obj.hasObject()){
-                counter.incrementAndGet();
-            }
-        });
-        return counter.get();
+        return objectMap.size();
     }
 
     /**
@@ -293,7 +283,7 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
      */
     // this method is exactly the same as "objectsInvalidated", only 
additionally it
     // throws out registered objects
-    public synchronized void objectsUnregistered(Collection<?> objects) {
+    public synchronized void objectsUnregistered(Collection objects) {
         if (objects.isEmpty()) {
             return;
         }
@@ -308,6 +298,9 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
             // remove object but not snapshot
             objectMap.remove(id);
             changes.remove(id);
+            if(id != null && trackedFlattenedPaths != null) {
+                trackedFlattenedPaths.remove(id);
+            }
             ids.add(id);
 
             object.setObjectContext(null);
@@ -321,10 +314,10 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
             // send an event for removed snapshots
             getDataRowCache().processSnapshotChanges(
                     this,
-                    Collections.emptyMap(),
-                    Collections.emptyList(),
+                    Collections.<ObjectId, DataRow>emptyMap(),
+                    Collections.<ObjectId>emptyList(),
                     ids,
-                    Collections.emptyList());
+                    Collections.<ObjectId>emptyList());
         }
     }
 
@@ -393,11 +386,11 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
 
         for (Object id : changes.keySet()) {
 
-            ObjectStoreEntry object = objectMap.get((ObjectId)id);
+            Persistent object = objectMap.get(id);
 
             // assume that no new or deleted objects are present (as otherwise 
commit
             // wouldn't have been phantom).
-            
object.persistent().setPersistenceState(PersistenceState.COMMITTED);
+            object.setPersistenceState(PersistenceState.COMMITTED);
         }
 
         // clear caches
@@ -412,10 +405,8 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
     public void postprocessAfterCommit(GraphDiff parentChanges) {
 
         // scan through changed objects, set persistence state to committed
-        for (Object key : changes.keySet()) {
-            ObjectId id = (ObjectId) key;
-            // persistent object for the diff should always exist
-            Persistent object = objectMap.get(id).persistent();
+        for (Object id : changes.keySet()) {
+            Persistent object = objectMap.get(id);
 
             switch (object.getPersistenceState()) {
                 case PersistenceState.DELETED:
@@ -512,7 +503,7 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
      * Returns an iterator over the registered objects.
      */
     public synchronized Iterator<Persistent> getObjectIterator() {
-        return new EntryIterator(objectMap.values().iterator());
+        return objectMap.values().iterator();
     }
 
     /**
@@ -533,9 +524,9 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
     public synchronized List<Persistent> objectsInState(int state) {
         List<Persistent> filteredObjects = new ArrayList<>();
 
-        for (ObjectStoreEntry entry : objectMap.values()) {
-            if (entry.hasObject() && entry.persistent().getPersistenceState() 
== state) {
-                filteredObjects.add(entry.persistent());
+        for (Persistent object : objectMap.values()) {
+            if (object.getPersistenceState() == state) {
+                filteredObjects.add(object);
             }
         }
 
@@ -595,21 +586,11 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
     }
 
     void processIdChange(Object nodeId, Object newId) {
-        ObjectStoreEntry entry = objectMap.remove((ObjectId)nodeId);
-
-        if (entry != null) {
-            ObjectId id = (ObjectId) newId;
-            entry.persistent().setObjectId(id);
-            objectMap.merge(id, entry, (oldValue, newValue) -> {
-                if(oldValue.trackedFlattenedPaths != null) {
-                    if(newValue.trackedFlattenedPaths != null) {
-                        
newValue.trackedFlattenedPaths.putAll(oldValue.trackedFlattenedPaths);
-                    } else {
-                        newValue.trackedFlattenedPaths = 
oldValue.trackedFlattenedPaths;
-                    }
-                }
-                return newValue;
-            });
+        Persistent object = objectMap.remove(nodeId);
+
+        if (object != null) {
+            object.setObjectId((ObjectId) newId);
+            objectMap.put(newId, object);
 
             ObjectDiff change = changes.remove(nodeId);
             if (change != null) {
@@ -617,6 +598,12 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
             }
         }
 
+        if(trackedFlattenedPaths != null) {
+            Map<CayennePath, ObjectId> paths = 
trackedFlattenedPaths.remove(nodeId);
+            if(paths != null) {
+                trackedFlattenedPaths.put(newId, paths);
+            }
+        }
     }
 
     /**
@@ -627,10 +614,9 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
     void processDeletedID(ObjectId nodeId) {
 
         // access object map directly - the method should be called in a 
synchronized context...
-        ObjectStoreEntry entry = objectMap.get(nodeId);
+        Persistent object = objectMap.get(nodeId);
 
-        if (entry != null && entry.hasObject()) {
-            Persistent object = entry.persistent();
+        if (object != null) {
             DataContextDelegate delegate;
 
             switch (object.getPersistenceState()) {
@@ -726,14 +712,11 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
     void processIndirectlyModifiedIDs(Collection<ObjectId> 
indirectlyModifiedIDs) {
         for (ObjectId oid : indirectlyModifiedIDs) {
             // access object map directly - the method should be called in a 
synchronized context...
-            ObjectStoreEntry entry = objectMap.get(oid);
+            final Persistent object = objectMap.get(oid);
 
-            if (entry == null
-                    || !entry.hasObject()
-                    || entry.persistent().getPersistenceState() != 
PersistenceState.COMMITTED) {
+            if (object == null || object.getPersistenceState() != 
PersistenceState.COMMITTED) {
                 continue;
             }
-            Persistent object = entry.persistent();
 
             // for now break all "independent" object relationships...
             // in the future we may want to be more precise and go after 
modified
@@ -783,12 +766,11 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
     void processUpdatedSnapshot(ObjectId nodeId, DataRow diff) {
 
         // access object map directly - the method should be called in a 
synchronized context...
-        ObjectStoreEntry entry = objectMap.get(nodeId);
+        Persistent object = objectMap.get(nodeId);
 
         // no object, or HOLLOW object require no processing
-        if (entry != null && entry.hasObject()) {
+        if (object != null) {
 
-            Persistent object = entry.persistent();
             int state = object.getPersistenceState();
             if (state != PersistenceState.HOLLOW) {
 
@@ -862,12 +844,13 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
      * @since 1.2
      */
     @Override
-    public synchronized Persistent getNode(Object nodeId) {
-        ObjectStoreEntry entry = objectMap.get((ObjectId) nodeId);
-        if(entry == null) {
-            return null;
-        }
-        return entry.persistent();
+    public synchronized Object getNode(Object nodeId) {
+        return objectMap.get(nodeId);
+    }
+
+    // non-synchronized version of getNode for private use
+    final Object getNodeNoSync(Object nodeId) {
+        return objectMap.get(nodeId);
     }
 
     /**
@@ -878,13 +861,7 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
      */
     @Override
     public synchronized Collection<Object> registeredNodes() {
-        List<Object> values = new ArrayList<>(objectMap.size());
-        objectMap.forEach((id, entry) -> {
-            if(entry.hasObject()) {
-                values.add(entry.persistent());
-            }
-        });
-        return values;
+        return new ArrayList<Object>(objectMap.values());
     }
 
     /**
@@ -892,15 +869,15 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
      */
     @Override
     public synchronized void registerNode(Object nodeId, Object nodeObject) {
-        objectMap.put((ObjectId)nodeId, new ObjectStoreEntry((Persistent) 
nodeObject));
+        objectMap.put(nodeId, (Persistent) nodeObject);
     }
 
     /**
      * @since 1.2
      */
     @Override
-    public synchronized Persistent unregisterNode(Object nodeId) {
-        Persistent object = getNode(nodeId);
+    public synchronized Object unregisterNode(Object nodeId) {
+        Object object = getNode(nodeId);
         if (object != null) {
             objectsUnregistered(Collections.singleton(object));
         }
@@ -998,28 +975,52 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
         registerDiff(nodeId, diff);
     }
 
+    /**
+     * Check that flattened path for given object ID has data row in DB.
+     * @since 4.1
+     */
+    boolean hasFlattenedPath(ObjectId objectId, CayennePath path) {
+        if(trackedFlattenedPaths == null) {
+            return false;
+        }
+        return trackedFlattenedPaths
+                .getOrDefault(objectId, 
Collections.emptyMap()).containsKey(path);
+    }
+
     /**
      * @since 4.2
      */
     public ObjectId getFlattenedId(ObjectId objectId, CayennePath path) {
-        ObjectStoreEntry entry = objectMap.get(objectId);
-        return entry == null ? null : entry.getFlattenedId(path);
+        if(trackedFlattenedPaths == null) {
+            return null;
+        }
+
+        return trackedFlattenedPaths
+                .getOrDefault(objectId, Collections.emptyMap()).get(path);
     }
 
     /**
      * @since 4.2
      */
     public Collection<ObjectId> getFlattenedIds(ObjectId objectId) {
-        ObjectStoreEntry entry = objectMap.get(objectId);
-        return entry == null ? null : entry.getFlattenedIds();
+        if(trackedFlattenedPaths == null) {
+            return Collections.emptyList();
+        }
+
+        return trackedFlattenedPaths
+                .getOrDefault(objectId, Collections.emptyMap()).values();
     }
 
     /**
      * @since 5.0
      */
-    public Map<CayennePath, ObjectId> getFlattenedPathIdMap(ObjectId objectId) 
{
-        ObjectStoreEntry entry = objectMap.get(objectId);
-        return entry == null ? null : entry.getFlattenedPathIdMap();
+    public Map<CayennePath,ObjectId> getFlattenedPathIdMap(ObjectId objectId) {
+        if(trackedFlattenedPaths == null) {
+            return Collections.emptyMap();
+        }
+
+        return trackedFlattenedPaths
+                .getOrDefault(objectId, Collections.emptyMap());
     }
 
     /**
@@ -1027,8 +1028,12 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
      * @since 4.1
      */
     public void markFlattenedPath(ObjectId objectId, CayennePath path, 
ObjectId id) {
-        objectMap.computeIfAbsent(objectId, objId -> new 
ObjectStoreEntry(null))
-                .markFlattenedPath(path, id);
+        if(trackedFlattenedPaths == null) {
+            trackedFlattenedPaths = new ConcurrentHashMap<>();
+        }
+        trackedFlattenedPaths
+                .computeIfAbsent(objectId, o -> new ConcurrentHashMap<>())
+                .put(path, id);
     }
 
     // an ObjectIdQuery optimized for retrieval of multiple snapshots - it can 
be reset
@@ -1072,28 +1077,4 @@ public class ObjectStore implements Serializable, 
SnapshotEventListener, GraphMa
             throw new UnsupportedOperationException();
         }
     }
-
-    static class EntryIterator implements Iterator<Persistent> {
-
-        final Iterator<ObjectStoreEntry> iterator;
-
-        EntryIterator(Iterator<ObjectStoreEntry> iterator) {
-            this.iterator = iterator;
-        }
-
-        @Override
-        public boolean hasNext() {
-            return iterator.hasNext();
-        }
-
-        @Override
-        public Persistent next() {
-            return iterator.next().persistent();
-        }
-
-        @Override
-        public void remove() {
-            iterator.remove();
-        }
-    }
 }
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/ObjectStoreEntry.java 
b/cayenne/src/main/java/org/apache/cayenne/access/ObjectStoreEntry.java
deleted file mode 100644
index 8aa0a3261..000000000
--- a/cayenne/src/main/java/org/apache/cayenne/access/ObjectStoreEntry.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*****************************************************************
- *   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
- *
- *    https://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.access;
-
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.Persistent;
-import org.apache.cayenne.exp.path.CayennePath;
-
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * @since 5.0
- */
-public class ObjectStoreEntry implements Serializable {
-
-    final protected Persistent persistent;
-    protected Map<CayennePath, ObjectId> trackedFlattenedPaths;
-
-    public ObjectStoreEntry(Persistent persistent) {
-        this.persistent = persistent;
-    }
-
-    public Persistent persistent() {
-        return persistent;
-    }
-
-    public boolean hasObject() {
-        return persistent != null;
-    }
-
-    public void markFlattenedPath(CayennePath path, ObjectId objectId) {
-        if (trackedFlattenedPaths == null) {
-            trackedFlattenedPaths = new ConcurrentHashMap<>();
-        }
-        trackedFlattenedPaths.put(path, objectId);
-    }
-
-    public ObjectId getFlattenedId(CayennePath path) {
-        return trackedFlattenedPaths == null ? null : 
trackedFlattenedPaths.get(path);
-    }
-
-    public Collection<ObjectId> getFlattenedIds() {
-        return trackedFlattenedPaths == null ? Collections.emptyList() : 
trackedFlattenedPaths.values();
-    }
-
-    public Map<CayennePath, ObjectId> getFlattenedPathIdMap() {
-        return trackedFlattenedPaths == null ? Collections.emptyMap() : 
trackedFlattenedPaths;
-    }
-}
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/ObjectStoreGraphDiff.java 
b/cayenne/src/main/java/org/apache/cayenne/access/ObjectStoreGraphDiff.java
index 0208cf5ea..3043fa403 100644
--- a/cayenne/src/main/java/org/apache/cayenne/access/ObjectStoreGraphDiff.java
+++ b/cayenne/src/main/java/org/apache/cayenne/access/ObjectStoreGraphDiff.java
@@ -70,7 +70,8 @@ public class ObjectStoreGraphDiff implements GraphDiff {
         boolean noop = true;
 
         // build a new collection for validation as validation methods may
-        // result in ObjectStore modifications
+        // result in
+        // ObjectStore modifications
 
         Collection<Validating> objectsToValidate = null;
 
@@ -80,12 +81,12 @@ public class ObjectStoreGraphDiff implements GraphDiff {
 
                 noop = false;
 
-                if (diff.object() instanceof Validating) {
+                if (diff.getObject() instanceof Validating) {
                     if (objectsToValidate == null) {
                         objectsToValidate = new ArrayList<>();
                     }
 
-                    objectsToValidate.add((Validating) diff.object());
+                    objectsToValidate.add((Validating) diff.getObject());
                 }
 
             }
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/access/DataContextPrefetchMultistepIT.java
 
b/cayenne/src/test/java/org/apache/cayenne/access/DataContextPrefetchMultistepIT.java
index 897d60f53..7bc9eab7b 100644
--- 
a/cayenne/src/test/java/org/apache/cayenne/access/DataContextPrefetchMultistepIT.java
+++ 
b/cayenne/src/test/java/org/apache/cayenne/access/DataContextPrefetchMultistepIT.java
@@ -113,7 +113,7 @@ public class DataContextPrefetchMultistepIT extends 
RuntimeCase {
         // get garbage collected, and we won't be able to detect them
         // so ensure ObjectStore uses a regular map just for this test
 
-        context.getObjectStore().objectMap = new HashMap<>();
+        context.getObjectStore().objectMap = new HashMap<Object, Persistent>();
 
         // Check the target ArtistExhibit objects do not exist yet
 
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/access/DataContextSerializationIT.java
 
b/cayenne/src/test/java/org/apache/cayenne/access/DataContextSerializationIT.java
index face100de..441a9f8e9 100644
--- 
a/cayenne/src/test/java/org/apache/cayenne/access/DataContextSerializationIT.java
+++ 
b/cayenne/src/test/java/org/apache/cayenne/access/DataContextSerializationIT.java
@@ -21,8 +21,8 @@ package org.apache.cayenne.access;
 
 import org.apache.cayenne.Cayenne;
 import org.apache.cayenne.ObjectContext;
-import org.apache.cayenne.ObjectId;
 import org.apache.cayenne.PersistenceState;
+import org.apache.cayenne.Persistent;
 import org.apache.cayenne.runtime.CayenneRuntime;
 import org.apache.cayenne.configuration.DefaultRuntimeProperties;
 import org.apache.cayenne.di.Inject;
@@ -152,7 +152,7 @@ public class DataContextSerializationIT extends RuntimeCase 
{
                 new DefaultRuntimeProperties(domain.getProperties()),
                 domain.getEventManager());
 
-        Map<ObjectId, ObjectStoreEntry> map = new HashMap<>();
+        Map<Object, Persistent> map = new HashMap<>();
 
         DataContext localCacheContext = new DataContext(domain, new 
ObjectStore(
                 snapshotCache,
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/access/ObjectStoreTest.java 
b/cayenne/src/test/java/org/apache/cayenne/access/ObjectStoreTest.java
index b25336196..e79770498 100644
--- a/cayenne/src/test/java/org/apache/cayenne/access/ObjectStoreTest.java
+++ b/cayenne/src/test/java/org/apache/cayenne/access/ObjectStoreTest.java
@@ -42,7 +42,7 @@ public class ObjectStoreTest {
     @Before
     public void before() {
         DataRowStore sharedCache = mock(DataRowStore.class);
-        this.objectStore = new ObjectStore(sharedCache, new HashMap<>());
+        this.objectStore = new ObjectStore(sharedCache, new HashMap<Object, 
Persistent>());
     }
 
     @Test


Reply via email to