Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spl_object_hash conflict on Merge #1465

Closed
wants to merge 8 commits into from
Closed

Conversation

moroine
Copy link

@moroine moroine commented Jul 16, 2015

This is proper PR which was originally #1461

Hi,

First of all, this is just a proposal and I'm sure there is a better solution for the problem described here. As this is my first hack into doctrine source code I'm not sure consequences that might be cause by my modification (even all unit tests passes).

I have encounter a problem due to spl_object_hash. I have written a functional test in order to reveal my issue.

The problem is when I merge an entity, here $user, UOW keep data on the original entity identified by it's spl_object_hash. Then if I unset this $user the spl_object_hash is now available for new object. So I experimented in my case reuse of previous hash which cause a managed+dirty entity error.

So I see two solutions

UOW keep reference to the entity given as even the given variable is unset there is remaining reference in UOW so the spl_hash will not be released.
Do not store data about the given entity, as merge operation isn't supposed to modified given entity.
I tried to implement the second solution as the first may consume a much more memory.

I don't why the merge operation need to do this, so I encapsulated it to prevent unwanted bug :)

@doctrinebot
Copy link

Hello,

thank you for creating this pull request. I have automatically opened an issue
on our Jira Bug Tracker for you. See the issue link:

http://www.doctrine-project.org/jira/browse/DDC-3834

We use Jira to track the state of pull requests and the versions they got
included in.

@moroine
Copy link
Author

moroine commented Jul 16, 2015

@DHager I provided a unit test that fail on version 2.5.0 but succeed with my PR. It seems that the merge operation stores the spl_object_hash of input object in originalEntityData array.

In order to be more understandable, I will explain my use case were the bug originally appears.

I realize a bulk operations for update data from external source. To do that without consuming all my memory, I use a lot of clear / merge operations. In a special case I encounter the DoctrineException "a managed+dirty entity ...", so I cannot flush my changes. After investigating it appears that I have an entity $a detached after a clear operation. In order to re-attach it, I merge it and directly affects the result to $a = $em->merge($a);. In this case the spl_object_hash of $a change from $spl1 to $spl2. So the object of value $spl1 doesn't exist anymore and it is garbage collected. Then I create a new entity which it's spl_object_hash is $spl1 (it doesn't appear always, but it's possible according to phpdocumentation). This entity cannot be persist as the $originalData[$spl1] isn't empty.

@DHager
Copy link
Contributor

DHager commented Jul 16, 2015

OK, so if someone goes:

$foo = new Thing();
$bar = $entityManager->merge($foo);
unset($foo);

It looks like the "unreliable hash key" from $foo makes its way into UOW's $originalEntityData array here:

$this->originalEntityData[spl_object_hash($entity)][$name] = $managedCol;

What I don't know is whether this is intended/desirable behavior. If $originalEntityData is supposed to be keyed only by the official single managed copy (???) then it might be a simple fix of:

$this->originalEntityData[spl_object_hash($managedCopy)][$name] = $managedCol;

However, if $this->originalEntityData is supposed to be keyed by the originally-given-object(s), then I agree that storing a reference to the original input (to prevent garbage collection and reuse of the memory-address) is a possible solution.

@Ocramius I'm not very familiar with merge/detach. Does any of this ring a bell for you, or is there some other contributor we should ask?

@moroine
Copy link
Author

moroine commented Jul 28, 2015

Hi,

I would like to know if anyone could resolve this issue ? I think this is a bug of merge operation and it could be unsefull to integrate this pull request or resolve the issue with another solution maybe as described by @DHager ?

Thank you,

@moroine
Copy link
Author

moroine commented Nov 27, 2015

I refactor a little my PR.

Anyone could check it ?

Thanks,

bilouwan added 3 commits November 27, 2015 17:16
…(reverted from commit 0408ffd793471863de6c3f8c88f3a1cbbb0750db)
# Conflicts:
#	lib/Doctrine/ORM/UnitOfWork.php
$user = new CmsUser;
$hash = spl_object_hash($user);

$mergedUser = $this->_em->merge($user);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't self::assertSame($user, $mergedUser) here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should assert that $user and $mergedUser are two different object (by there reference) as merge operation should return a managed copy of input object but the input object has to remain unmanaged ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We couldn't assertSame as for object assertSame check if the two variables reference the same object. In the case of merge, it will return a copy so it's another object

# Conflicts:
#	lib/Doctrine/ORM/UnitOfWork.php
@moroine
Copy link
Author

moroine commented Dec 22, 2015

@Ocramius I made up the merge operation in order to resolve conflict and include changes requested.

Don't take care about all commits, I removed them (I forgot this PR use my master branch)

@moroine
Copy link
Author

moroine commented Dec 29, 2015

@Ocramius It seems that Travis is missconfigured as the composer.json requirements is not compatible with versions 5.4 and lower of php

@Ocramius
Copy link
Member

@moroine fixed in master: a rebase should give you a green build

@Ocramius Ocramius added the Bug label Dec 29, 2015
@moroine
Copy link
Author

moroine commented Dec 30, 2015

Thanks ! It works fine !

Did you seen my other related PR ? #5570

@moroine
Copy link
Author

moroine commented Feb 2, 2016

@Ocramius Is this PR schedule to be merged or I need to do something else ?

@rdevaissiere
Copy link

FWIW, this fix is also working for me, my scenario is a typical data ingestion service with a lot of merging going on and it took me a while to track it down to spl_object_hash collisions. I was hitting many random ORMInvalidArgumentException exceptions:

A managed+dirty entity [...] can not be scheduled for insertion.

Hopefully we can merge this one in. Thanks for the diligent work @moroine!

@Ocramius Ocramius added this to the 2.5.5 milestone Sep 10, 2016
@Ocramius Ocramius self-assigned this Sep 10, 2016
@Ocramius
Copy link
Member

Manually applied these tests, then checked against #5689. The issue is resolved there, therefore closing this PR as duplicate, since the approach in #5689 seems to solve the actual cause of the issue (rather than the symptom, fixed here via UnitOfWork#forgetEntity().

This is considered "fixed" in 2.5.5

@Ocramius Ocramius closed this Sep 10, 2016
@moroine moroine deleted the master branch December 15, 2016 10:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants