Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 312503

Summary: Core: IdentityMapAccessor.invalidateClass() should invalidate a subtree when recurse is false
Product: z_Archived Reporter: Michael OBrien <michael.f.obrien>
Component: EclipselinkAssignee: Nobody - feel free to take it <nobody>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: eclipselink.foundation-inbox
Version: unspecifiedFlags: michael.f.obrien: documentation+
Target Milestone: ---   
Hardware: PC   
OS: Windows 7   
URL: http://wiki.eclipse.org/EclipseLink/Development/JPA_2.0/cache_api#DI_3:_Eviction_of_a_MappedSuperclass_also_evicts_root_Entity_Superclass
Whiteboard:
Bug Depends on:    
Bug Blocks: 312311, 248780    
Attachments:
Description Flags
IdentityMapAccessor.invalidateClass() refactor to invalidate subtree
none
IdentityMapAccessor.invalidateClass() refactor to invalidate subtree
none
IdentityMapAccessor.invalidateClass() refactor to invalidate subtree none

Description Michael OBrien CLA 2010-05-11 16:24:14 EDT
>Invalidating a cache object either invalidates the entire tree to the root (recurse=true)
or invalidates a single entity (recurse=false)
>The issue is we do not have the capability to invalidate a subtree starting at the invalidation class.
in the following code when the recurse flag is false - we

IdentityMapAccessor.java:820
    public void invalidateClass(Class myClass, boolean recurse) {
      if (recurse || ((obj != null) && myClass.isInstance(obj)){                
           key.setInvalidationState(CacheKey.CACHE_KEY_INVALID);

>Discussed this with James and we should align the code with what is done in
IdentityMapManager.invalidateObject():581
      if ((object.getClass() == theClass) || (theClass.isInstance(object))) {
          key.setInvalidationState(CacheKey.CACHE_KEY_INVALID);

>by using isInstance() instead of equals()

The following model illustrates this issue when we attempt to invalidate at different levels in the inheritance tree

Class1 (non-persistable java class)
  +---Entity2 (abstract entity)
        +--- MappedSuperclass3 (MappedSuperclass)
               +-----Entity4a (concrete entity)
                       +--- Class5 (non-persistable java class)
               +-----Entity4b (concrete entity)

>currently if we evict() any of Class1 down to Class5 
we evict the entire inheritance tree from Entity2 in all cases
- This is because getIdentityMap(Class5 or any other) will return the identityMap for the root entity (Entity2) in all cases - by design

Where the existing code becomes an issue is if we wish to invalidate only a subtree of the root descriptor by using recurse=false
Comment 1 Michael OBrien CLA 2010-05-11 16:38:45 EDT
>Existing code is 
IdentityMapAccessor.java:820
    public void invalidateClass(Class myClass, boolean recurse) {
      if(recurse || ((obj != null) && obj.getClass().equals(myClass)){                
           key.setInvalidationState(CacheKey.CACHE_KEY_INVALID);
Comment 2 Michael OBrien CLA 2010-05-11 17:02:04 EDT
Created attachment 168037 [details]
IdentityMapAccessor.invalidateClass() refactor to invalidate subtree
Comment 3 Michael OBrien CLA 2010-05-11 17:03:59 EDT
Created attachment 168038 [details]
IdentityMapAccessor.invalidateClass() refactor to invalidate subtree
Comment 4 Michael OBrien CLA 2010-05-12 09:30:17 EDT
>The following model is used to to illustrate use case behavior when invalidating non-entity classes 
(extended functionality beyond the JPA specification) in an inheritance hierarchy.

Class1 (non-persistable java class)
  +---Entity2 (abstract entity)
        +--- MappedSuperclass3 (MappedSuperclass)
               +-----Entity4a (concrete entity)
                       +--- Class5 (non-persistable java class)
               +-----Entity4b (concrete entity)

Entity4a and Entity4b are in the cache to start.
>Here is the current behavior (all evict operations evict the entire tree)
- This is because getIdentityMap(Class5 or any other) will return the identityMap for the root entity (Entity2) in all cases - by design
evict(Class1)            --> evicts E4a and E4b
evict(Entity2)           --> evicts E4a and E4b
evict(MappedSuperclass3) --> evicts E4a and E4b
evict(Entity4a)          --> evicts E4a and E4b
evict(Class5)            --> evicts E4a and E4b
evict(Entity4b)          --> evicts E4a and E4b

>I propose that we introduce more granular eviction behavior by not always evicting the root
- but by evicting the subtree
evict(Class1)            --> evicts E4a and E4b
evict(Entity2)           --> evicts E4a and E4b
evict(MappedSuperclass3) --> evicts E4a and E4b
evict(Entity4a)          --> evicts E4a only
evict(Class5)            --> evicts E4a only
evict(Entity4b)          --> evicts E4b only

>Part of the change to enable this behavior is fixing the invalidateClass() function for cases where recurse=false
See bug# 312503
- we may add a 2nd flag [recurseSubTree) to make the invalidateClass(Class) function (tri/quad state)
recurse recurseSubtree behavior
-------------------------------
false   false          :invalidate only class parameter - existing equals functionality
false   true           :invalidate subtree from Class parameter - new isAssignableFrom functionality
true    false(x)       :invalidate entire tree from root
true    true(x)        :invalidate entire tree from root
Comment 5 Michael OBrien CLA 2010-05-31 11:34:54 EDT
Created attachment 170542 [details]
IdentityMapAccessor.invalidateClass() refactor to invalidate subtree

>The test suite used by the Cache API in bug# 248780 has sufficient inheritance levels for testing this change
>The existing Project model suite passes with/without this change - as it is 1 level deep
Comment 6 Michael OBrien CLA 2010-05-31 11:40:13 EDT
>A documentation release note is required
- previously when the (non-default) recurse flag of false was used - only the single class inside the tree was invalidated
- now the entire subtree is invalidated 
- using the default behaviour of recurse=true has unaffected functionality - and removes the entire tree up to the root
Comment 7 Michael OBrien CLA 2010-06-03 10:06:49 EDT
>see SVN rev# 7447
Comment 8 Eclipse Webmaster CLA 2022-06-09 10:18:45 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink