Jody Grassel created OPENJPA-2726:
-------------------------------------

             Summary: Under certain conditions an Embeddable can be directly 
admitted into the Datacache map
                 Key: OPENJPA-2726
                 URL: https://issues.apache.org/jira/browse/OPENJPA-2726
             Project: OpenJPA
          Issue Type: Bug
          Components: kernel
    Affects Versions: 2.2.2
            Reporter: Jody Grassel
            Assignee: Jody Grassel
             Fix For: 2.2.3


A certain sequence of events can result in an Embeddable object instance, with 
a null identity, being admitted to the DataCache.  This has a number of 
consequences, ranging from errors by third party datacache implementations 
which cannot accept a null key value (which the native OpenJPA datacache impl 
can), to possible data integrity issues since a null key can refer to any kind 
of object type (since the regular key includes both
identity and identity type in its information.)

Consider the following entities:

@Entity
public class LeftHand {
    @Id private long id;   
    private String strData;
    @OneToMany private Collection<RightHand> rhList; 
    ...

@Entity
public class RightHand {
    @Id private long id; 
    @Basic private String strData;    
    @Embedded private EmbeddableData emb;
    ...
    
@Embeddable
public class EmbeddableData {
    @Basic private String embeddedString;   
    @Basic(fetch=FetchType.LAZY) private String lazyEmbeddedString;

After committing the above entities with filled data, the contents of the L2 
datacache is as follows:

this    TestDataCache  (id=42)  
cm      ConcurrentDataCache$1  (id=43)  
        [0]     ConcurrentHashMap$Entry  (id=68)        
                key     LongId  (id=73) 
                value   DataCachePCDataImpl  (id=74)    
                        _cache  "default" (id=85)       
                        _data   Object[4]  (id=88)      
                                [0]     Long  (id=102)  
                                [1]     AbstractPCData$ProxyDataList  (id=104)  
                                [2]     "left hand" (id=110)    
                                [3]     Long  (id=111)  
                        _exp    -1      
                        _fieldImpl      null    
                        _impl   null    
                        _loaded BitSet  (id=91) 
                        _oid    LongId  (id=73) 
                        _type   Class<T> 
(org.apache.openjpa.persistence.cache.jpa.model.LeftHand) (id=94)      
                        _version        Integer  (id=99)        
        [1]     ConcurrentHashMap$Entry  (id=69)        
                key     LongId  (id=116)        
                value   DataCachePCDataImpl  (id=117)   
                        _cache  "default" (id=85)       
                        _data   Object[3]  (id=120)     
                                [0]     DataCachePCDataImpl  (id=125)   
                                        _cache  "default" (id=85)       
                                        _data   Object[2]  (id=128)     
                                                [0]     "Embedded String" 
(id=130)      
                                                [1]     "Lazy String" (id=131)  
                                        _exp    -1      
                                        _fieldImpl      null    
                                        _impl   null    
                                        _loaded BitSet  (id=129)        
                                        _oid    BrokerImpl$StateManagerId  
(id=3611)    
                                        _type   Class<T> 
(org.apache.openjpa.persistence.cache.jpa.model.EmbeddableData) (id=2336)      
                                        _version        null    
                                [1]     Long  (id=126)  
                                [2]     "right hand" (id=127)   
                        _exp    -1      
                        _fieldImpl      null    
                        _impl   null    
                        _loaded BitSet  (id=121)        
                        _oid    LongId  (id=116)        
                        _type   Class<T> 
(org.apache.openjpa.persistence.cache.jpa.model.RightHand) (id=122)    
                        _version        null    

Here we see that the datacache contains two entries, one for LeftHand, one for 
RightHand.  Completely expected, and at this point Life is Good.

After purging the persistence context and L2 cache, a query "SELECT lh from 
LeftHand lh" is executed, and iterating through its result list yields the 
following L2 datacache state:

this    TestDataCache  (id=42)  
cm      ConcurrentDataCache$1  (id=43)  
        [0]     ConcurrentHashMap$Entry  (id=3657)      
                key     LongId  (id=3660)       
                value   DataCachePCDataImpl  (id=3661)  
                        _cache  "default" (id=85)       
                        _data   Object[4]  (id=3662)    
                                [0]     Long  (id=3665) 
                                [1]     null    
                                [2]     "left hand" (id=3666)   
                                [3]     Long  (id=111)  
                        _exp    -1      
                        _fieldImpl      null    
                        _impl   null    
                        _loaded BitSet  (id=3667)       
                        _oid    LongId  (id=3660)       
                        _type   Class<T> 
(org.apache.openjpa.persistence.cache.jpa.model.LeftHand) (id=94)      
                        _version        Long  (id=111)  
        [1]     ConcurrentHashMap$Entry  (id=3658)      
                key     null    
                value   DataCachePCDataImpl  (id=3670)  
                        _cache  "default" (id=85)       
                        _data   Object[2]  (id=3671)    
                                [0]     "Embedded String" (id=3673)     
                                [1]     "Lazy String" (id=3674) 
                        _exp    -1      
                        _fieldImpl      null    
                        _impl   null    
                        _loaded BitSet  (id=3675)       
                        _oid    null    
                        _type   Class<T> 
(org.apache.openjpa.persistence.cache.jpa.model.EmbeddableData) (id=2336)      
                        _version        null    
        [2]     ConcurrentHashMap$Entry  (id=3659)      
                key     LongId  (id=3682)       
                value   DataCachePCDataImpl  (id=3683)  
                        _cache  "default" (id=85)       
                        _data   Object[3]  (id=3686)    
                                [0]     DataCachePCDataImpl  (id=3688)  
                                        _cache  "default" (id=85)       
                                        _data   Object[2]  (id=3691)    
                                                [0]     "Embedded String" 
(id=3673)     
                                                [1]     "Lazy String" (id=3674) 
                                        _exp    -1      
                                        _fieldImpl      null    
                                        _impl   null    
                                        _loaded BitSet  (id=3694)       
                                        _oid    BrokerImpl$StateManagerId  
(id=3695)    
                                        _type   Class<T> 
(org.apache.openjpa.persistence.cache.jpa.model.EmbeddableData) (id=2336)      
                                        _version        null    
                                [1]     Long  (id=3689) 
                                [2]     "right hand" (id=3690)  
                        _exp    -1      
                        _fieldImpl      null    
                        _impl   null    
                        _loaded BitSet  (id=3687)       
                        _oid    LongId  (id=3682)       
                        _type   Class<T> 
(org.apache.openjpa.persistence.cache.jpa.model.RightHand) (id=122)    
                        _version        null    

A specific sequence of events, requiring the embeddable to contain a lazy 
loaded field (which forces a ROPStoreManager.load() in the 
AbstractPCData.toEmbeddedData() path results in the 
DataCacheStoreManager.load() operation attempting to admit the embeddable into 
the Datacache as if it was an entity type (object 
ConcurrentHashMap$Entry(id=3658) at index [1].)  The embeddable has no identity 
of its own, so is inserted into the cache with a null key value.  The OpenJPA 
datacache impl replaces the null value with an object that represents the null 
value -- while other datacache implementations attempt to add the key to a 
regular map instance which results in a NullPointerException.

The attached patch looks for the attempt to insert a new (embeddable) item into 
the datacache at updateDataCache() - admission into the datacache is rejected 
if this condition is met.  I've further modified cacheStateManager() to reject 
any attempt to admit an entry into the datacache that has a null entity to 
guard against other unidentified paths which could lead to a similar issue, as 
a null key identity in a datacache is meaningless.  A unit test has been added 
to verify that the fix corrects the issue.




--
This message was sent by Atlassian JIRA
(v6.4.14#64029)

Reply via email to