-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 9 posts ] 
Author Message
 Post subject: Why "Flush during cascade is dangerous" when Commi
PostPosted: Mon Sep 12, 2005 5:07 pm 
Beginner
Beginner

Joined: Tue May 17, 2005 11:42 am
Posts: 22
I have an object tree in which an object has several collections, mapped with cascade-delete-orphans, this object is also part of a collection.
Issuing:
Code:
session.Delete(object obj);

works ok, but when i try to commit i get an NHibernateException:
Quote:
Flush during cascade is dangerous - this might occur if an object as deleted and then re-saved by cascade

But if after this, I request a new session and issue:
Code:
session.Delete(object obj);
session.Commit();

This time the operation doesn't fail with an NHibernateException and the database executes the deletes consistently.
I've debugged the code and found:
SessionImpl.Delete(object obj)
Code:
entry.Status = Status.Deleted;

In the Delete method the entries for the deleted objects are set to Status.Deleted but
In SessionImpl.PreFlushEntities():
Code:
Status status = entry.Status;
if( status != Status.Loading && status != Status.Gone && status != Status.Deleted )
{
               object obj = me.Key;
               cascading++;
               try
               {
                  Cascades.Cascade( this, entry.Persister, obj, Cascades.CascadingAction.ActionSaveUpdate, CascadePoint.CascadeOnUpdate );
               }
               finally
               {
                  cascading--;
               }
            }

The entry.Status is Status.Loaded although it was already set to Status.Deleted by the Delete method. :?
I don't know if there might be a bug somewhere because it seems to me that I have two different instances of the same entry instead of only one.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 13, 2005 8:55 am 
Contributor
Contributor

Joined: Thu May 12, 2005 9:45 am
Posts: 593
Location: nhibernate.org
Read: Hibernate throws: Flush during cascade is dangerous.

If it doesn't help, post the code you are executing (from the creation of the session to its Close()).

Anyway, as you said, you can always work it around by using another session...

_________________
Pierre Henri Kuaté.
Get NHibernate in Action Now!


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 13, 2005 11:13 am 
Beginner
Beginner

Joined: Tue May 17, 2005 11:42 am
Posts: 22
Kpixel, you missread my thread, my problem is not the
Quote:
Flush during cascade is dangerous - this might occur if an object as deleted and then re-saved by cascade

but the fact that when I invoke Delete(object obj)
it executes:
Code:
EntityEntry entry = GetEntry( obj );

this EntityEntry is retrieved from
Code:
private IdentityMap entries; //key=Object, value=EntityEntry

The delete method then sets the entry.Status to Status.Deleted
Code:
entry.Status = Status.Deleted;

But during the PreFlushEntities()
while iterating the iterSafeCollection.
Code:
/// <summary>
      /// process cascade save/update at the start of a flush to discover
      /// any newly referenced entity that must be passed to saveOrUpdate()
      /// </summary>
      private void PreFlushEntities()
      {
         ICollection iterSafeCollection = IdentityMap.ConcurrentEntries( entries );

         // so that we can be safe from the enumerator & concurrent modifications
         foreach( DictionaryEntry me in iterSafeCollection )
         {
            EntityEntry entry = ( EntityEntry ) me.Value;
            Status status = entry.Status;

            if( status != Status.Loading && status != Status.Gone && status != Status.Deleted )
            {
               object obj = me.Key;
               cascading++;
               try
               {
                  Cascades.Cascade( this, entry.Persister, obj, Cascades.CascadingAction.ActionSaveUpdate, CascadePoint.CascadeOnUpdate );
               }
               finally
               {
                  cascading--;
               }
            }
         }
      }


The entries of the collection that I iterate aren't the same as the ones I had modified, so instead of having a Status.Deleted in the entry I still have Status.Loaded which will run the Cascades when it shouldn't (check the if clause.)


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 13, 2005 2:42 pm 
Beginner
Beginner

Joined: Tue May 17, 2005 11:42 am
Posts: 22
Kpixel, I've been debugging the NHibernate's core code and have find where the IdentityMap collection gets out of sync.
The problem can be traced to the SequencedHashMap, this class makes use of:

Code:
/// <summary>
/// Sentinel used to hold the head and tail of the list of entries
/// </summary>
private Entry _sentinel;


This _sentinel is later used by the:
Code:
private class OrderedEnumerator : IDictionaryEnumerator
      {
         private SequencedHashMap _parent;
         private ReturnType _returnType;
         private Entry _pos;
         private long _expectedModCount;

         public OrderedEnumerator( SequencedHashMap parent, ReturnType returnType )
         {
            _parent = parent;
            _returnType = returnType;
            _pos = _parent._sentinel;
            _expectedModCount = _parent._modCount;
         }
...

public bool MoveNext()
         {
            if( _parent._modCount != _expectedModCount )
            {
               throw new InvalidOperationException( "Enumerator was modified" );
            }
            if( _pos.Next == _parent._sentinel )
            {
               return false;
            }

            _pos = _pos.Next;

            return true;
         }

         public void Reset()
         {
            _pos = _parent._sentinel;
         }


For some reason the sentinel doesn't get updated with the same data as the Hashtable in SequencedHashMap class:
Code:
/// <summary>
/// Map of keys to entries
/// </summary>
private Hashtable _entries;


This produces the undesired effect of having iterations using stale data,
and makes the actual output of the IdentityMap via it's property EntryList to be wrong. (You don't get the real contents of the underlying collections).
I hope with this information you'll be able to fix the issue.
Thanks


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 13, 2005 3:39 pm 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
I will look at it, but I still doubt a bit whether there's a problem in the code. You say that your object is part of a collection, do you remove it from the collection as well as calling Delete on it?

If you open a new session, it doesn't know about the parent collection, so it doesn't complain.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 13, 2005 3:53 pm 
Beginner
Beginner

Joined: Tue May 17, 2005 11:42 am
Posts: 22
Sergey, yes I am removing the instance from the collection aswell. I tried everything i could come up with.
What catched my attention was that after calling session.Delete(object obj) the EntityEntry.Status changed to Status.Deleted.
But in session.PreFlushEntities() this EntityEntry.Status was Status.Loaded again, this made no sense, and after tracking down the code I came across what I posted above, that's why I receive the FlushDuringCascade... (It shouldn't be cascading because it's Status should be Status.Deleted.)
Thank you


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 14, 2005 3:40 pm 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
Ok I looked closer at the code of SequencedHashMap and don't see any obvious errors in there. The change of EntityEntry.Status could also occur as a part of cascade from another collection. Try putting a breakpoint in SessionImpl.AddEntry to see if this is the case.

Can you provide a test case for the problem? This means mapping files, code for the classes, and some code that exhibits the problem.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 16, 2005 9:48 am 
Beginner
Beginner

Joined: Tue May 17, 2005 11:42 am
Posts: 22
Thank you for the quick reply Sergey.
I will try to post you an example ASAP, but for the time being I'm working on a project and have a tight schedule to fulfill. I would like to put this issue on hold so we can review it in the future if that's ok with you.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 16, 2005 1:21 pm 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
Of course, just reply when you have some time.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 9 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.