openjpa-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "David Ezzio (JIRA)" <j...@apache.org>
Subject [jira] Issue Comment Edited: (OPENJPA-453) Evicting embedded object nullifies statemanager
Date Thu, 04 Jun 2009 20:31:07 GMT

    [ https://issues.apache.org/jira/browse/OPENJPA-453?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12716390#action_12716390
] 

David Ezzio edited comment on OPENJPA-453 at 6/4/09 1:31 PM:
-------------------------------------------------------------

Use of synchronized(this) is problematic.  We end up with two locks.  Some
threads will come to own the pc lock and then seek to own the sm lock.  Other
threads will come to own the sm lock and then seek to own the pc lock.

In the OpenJPA that I examined, it creates only one use of "synchronized" in the
enhanced code, on the pcReplaceStateManager method. Addition of synchronization
to the Page.getName() method (application code) leads to immediate deadlock in
the test case. With proper locking of the sm prior to its use by enhancement
added code, there is no need for a synchronized on the pcReplaceStateManager method
because only the state manager will call that method and the state manager will
be locked by that point.

In my view, to make it safe to multithread persistence contexts and to achieve
the high scaling that such a use case is normally striving for, we need the
following changes. Put on your hard hat for these renovations!

1. an atomic BitSet (which doesn't exist yet) to track which fields are
    loaded.

2. freeze optimistic versus pessimistic transactions to the creation of the
    persistence context. This is to allow each persistent object to know whether
    it will be participating in pessimistic or optimistic transactions.

3. no use of unlocked state managers.  In other words, something like this:

    protected StateManager pcLockStateManager()
        {
        StateManager sm = pcStateManager;
        if (sm == null)
            return null;
        sm.lock();
        
        // before we got the lock, did some other thread change the pcStateManager?
        if (sm != pcStateManager)
            {
            sm.unlock();
            ... repeat from the top
            }
            
        // returned locked state manager for this pc
        return sm;
        }
        
    pcSomeMethodThatCannotAssumeExistingStateManager(...)
        {
        StateManager sm = pcLockStateMangaer()
        if (sm == null)
            {
            ... use local values
            }
        else
            {
            try
                {
                ... use state manager
                }
            finally
                {
                sm.unlock()
                }
            }
        }
        
4. All pcGetXXX methods check the AtomicBitSet to determine whether they can
    use an already loaded value or need to use a locked state manager
    
    private static final String pcGetXXX(UserClass obj)
        {
        int i = pcInheritedFieldCount + ?;
        
        // are we in an opt transaction and is the field loaded?
        if (pcAtomicBitSet != null && pcAtomicBitSet.get(i))
            {
            return obj.XXX;
            }
            
        StateManager sm = pcLockStateManager()
        if (sm == null)
            {
            return obj.XXX;
            }
        try
            {
            sm.accessingField(i);
            return obj.XXX;
            }
        finally
            {
            sm.unlock()
            }
        }

5. Only a locked state manager can initiate changes to the pcAtomicBitSet
   field. If it is non-null, the context will only use opt transactions,
   otherwise, it will only use pessimistic transactions.  The choice is 
   invariant for the lifetime of the persistence context.

6. Enhancement no longer makes the pcReplaceStateManager method
    synchronized, so that we avoid deadlocking with a possible application lock.

In this fashion, we still have only one lock that is context wide, but for
read-only in a mostly loaded persistence context with optimistic transactions,
we get fast multithreaded reads because the context lock is used infrequently.
The potential for scaling is huge, when we consider multi-CPU, huge memory
hardware platforms. Not only do we by-pass a lot of code when using the state
manager, but we by-pass the context wide lock that now effectively serializes
all reading threads.

The only fly in the ointment is that the application code when performing a fast
read does not cross a memory barrier in the enhancement added code to access the
XXX field. Consequently, the application may be reading the value from a
register or from main memory. To handle this, and other issues such as orphaned
SCOs, the application code needs to acquire a reader/writer lock before using the
shared persistence context.


      was (Author: dezzio):
    Use of synchronized(this) is problematic.  We end up with two locks.  Some
threads will come to own the pc lock and then seek to own the sm lock.  Other
threads will come to own the sm lock and then seek to own the pc lock.

In the OpenJPA that I examined, it creates only one use of "synchronized" in the
enhanced code, on the pcReplaceStateManager method. Addition of synchronization
to the Page.getName() method (application code) leads to immediate deadlock in
the test case. With proper locking of the sm prior to its use by enhancement
added code, there is no need for a synchronized on the pcReplaceStateManager method
because only the state manager will call that method and the state manager will
be locked by that point.

In my view, to make it safe to multithread persistence contexts and to achieve
the high scaling that such a use case is normally striving for, we need the
following changes. Put on your hard hat for these renovations!

1. an atomic BitSet (which doesn't exist yet) to track which fields are
    loaded.

2. freeze optimistic versus pessimistic transactions to the creation of the
    persistence context. This is to allow each persistent object to know whether
    it will be participating in pessimistic or optimistic transactions.

3. no use of unlocked state managers.  In other words, something like this:

    protected StateManager pcLockStateManager()
        {
        StateManager sm = pcStateManager;
        if (sm == null)
            return null;
        sm.lock();
        
        // before we got the lock, did some other thread change the pcStateManager?
        if (sm != pcStateManager)
            {
            sm.unlock();
            ... repeat from the top
            }
            
        // returned locked state manager for this pc
        return sm;
        }
        
    pcSomeMethodThatCannotAssumeExistingStateManager(...)
        {
        StateManager sm = pcLockStateMangaer()
        if (sm == null)
            {
            ... use local values
            }
        else
            {
            try
                {
                ... use state manager
                }
            finally
                {
                sm.unlock()
                }
            }
        }
        
4. All pcGetXXX methods check the AtomicBitSet to determine whether they can
    use an already loaded value or need to use a locked state manager
    
    private static final String pcGetXXX(UserClass obj)
        {
        int i = pcInheritedFieldCount + ?;
        
        // are we in an opt transaction and is the field loaded?
        if (pcAtomicBitSet != null && pcAtomicBitSet.get(i))
            {
            return obj.XXX;
            }
            
        StateManager sm = pcLockStateManager()
        if (sm == null)
            {
            return obj.XXX;
            }
        try
            {
            sm.accessingField(i);
            return obj.XXX;
            }
        finally
            {
            sm.unlock()
            }
        }

5. Only a locked state manager can initiate changes to the pcAtomicBitSet
   field. If it is non-null, the context will only use opt transactions,
   otherwise, it will only use pessimistic transactions.  The choice is 
   invariant for the lifetime of the persistence context.

6. Enhancement no longer makes the pcReplaceStateManager method
    synchronized, so that we avoid deadlocking with a possible application lock.

In this fashion, we still have only one lock that is context wide, but for
read-only in a mostly loaded persistence context with optimistic transactions,
we get fast multithreaded reads because the context lock is used infrequently.
The potential for scaling is huge, when we consider multi-CPU, huge memory
hardware platforms. Not only do we by-pass a lot of code when using the state
manager, but we by-pass the context wide lock that now effectively serializes
all reading threads.

The only fly in the ointment is that the application code when performing a fast
read does not cross a memory barrier in the enhancement added code to access the
XXX field. Consequently, the application may be reading the value from a
register or from main memory. To handle this, and other issues such as orphaned
SCOs, the application code needs to use a reader/writer lock before using the
shared persistence context.

  
> Evicting embedded object nullifies statemanager
> -----------------------------------------------
>
>                 Key: OPENJPA-453
>                 URL: https://issues.apache.org/jira/browse/OPENJPA-453
>             Project: OpenJPA
>          Issue Type: Bug
>         Environment: Kodo 4.1.4, Ms sql server 2005, jTDS 1.2, jdk 1.6
>            Reporter: Christiaan
>            Assignee: Ravi P Palacherla
>         Attachments: OpenJPABug453Embedded.zip, openJPATestCase.zip, TestCaseEvictEmbedded.zip
>
>
> I am noticing the following behaviour: If evict() is called on an embedded
> object the statemanager is nullified which is in contrast to non-embedded
> objects. Subsequently, calling JDOHelper.getPersistenceManager() on the
> evicted embedded object returns null. Is this the correct behaviour?

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


Mime
View raw message