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

Fix performance issue when using notify tracking policy and calling flush($entity) multiple times #5579

Closed
wants to merge 1 commit into from

Conversation

xhuberty
Copy link
Contributor

Hi,

First of all I want to apologize for the poor quality of my English.

We had some performance issues in one of our project and we decide to use the Notify tracking policy.
This tracking policy is really usefull for batch and import. For your information we improved the performance of more than 80%.

During our test we discover that flush operations were cleaning the $entityChangeset of the UnitOfWork.
This is a real issue for us because we are using flush with null and entity as parameter.
Example:

$object1->setData($data);
$object2->setData($data);
$this->entityManager->flush($object1);
$this->entityManager->flush($object2);

With the notify tracking policy this code above will only save the change of the object1. All the other changes are lost.

@xhuberty xhuberty force-pushed the notifyTrackingPolicy branch from 458f64d to 6d50a66 Compare December 29, 2015 15:20
@Ocramius
Copy link
Member

@xhuberty the change looks good, but it really needs to be isolated in private API (split into private methods).

@Ocramius Ocramius added this to the 2.6.0 milestone Dec 29, 2015
if ($entity === null) {
$this->entityChangeSets = $this->scheduledForSynchronization = array();
} elseif (is_object($entity)) {
$oid = spl_object_hash($entity);
Copy link
Member

Choose a reason for hiding this comment

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

Will need separate tests to verify that the other changesets are still there

@xhuberty xhuberty force-pushed the notifyTrackingPolicy branch from 6d50a66 to f0d15df Compare December 29, 2015 17:10
@xhuberty
Copy link
Contributor Author

I think I made the modification you ask for except the one concerning the unit test.

$this->orphanRemovals = array();

if ($entity === null) {
Copy link
Member

Choose a reason for hiding this comment

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

Please reverse this (yoda)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry but I don't understand what you want. I used the exact same code as the one of the beginning of the commit method.

@Ocramius Ocramius removed this from the 2.6.0 milestone Dec 29, 2015
@Ocramius
Copy link
Member

@xhuberty we'd need tests before merging, heh

@xhuberty
Copy link
Contributor Author

@Ocramius can you please tell me exactly what unit test you need/want? I tought the unit test will already covered my modifications execpt for the 2 mtethods I have created.

@xhuberty
Copy link
Contributor Author

I made the change with the Yoda condition.

I will regroup all the commit in one when everything will be ok.

@Ocramius
Copy link
Member

@xhuberty a test should ideally have a UoW with 3 entries ($entity1, $entity2, $entity3), and then you should commit($entity1) or commit([$entity1, $entity2]) and verify that $entity2 (first case) and $entity3 changesets are still there.

@@ -3111,7 +3133,19 @@ public function registerManaged($entity, array $id, array $data)
*/
public function clearEntityChangeSet($oid)
{
$this->entityChangeSets[$oid] = array();
if (isset($this->entityChangeSets[$oid])) {
Copy link
Member

Choose a reason for hiding this comment

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

no need for an isset() check

@xhuberty xhuberty force-pushed the notifyTrackingPolicy branch from 1811e86 to a91b5bb Compare December 31, 2015 14:02
@xhuberty
Copy link
Contributor Author

xhuberty commented Jan 5, 2016

I made the unit test, and I have regroup all the commit in one.

$this->_unitOfWork->persist($entity2);

$this->_unitOfWork->commit($entity1);
$this->assertEquals(1, count($this->_unitOfWork->getEntityChangeSet($entity2)));
Copy link
Contributor

Choose a reason for hiding this comment

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

Use assertCount() instead.

@xhuberty xhuberty force-pushed the notifyTrackingPolicy branch from a91b5bb to f09689c Compare January 5, 2016 10:53
@xhuberty
Copy link
Contributor Author

xhuberty commented Jan 5, 2016

Use of assertCount and fix indentation issue.

Everything regoup in the same commit.

@xhuberty xhuberty force-pushed the notifyTrackingPolicy branch from 1073571 to 1fda01d Compare January 8, 2016 10:36
@xhuberty
Copy link
Contributor Author

Hi guys,

Just wanting to know if I need to change something else for this PR to be merged?

And if it's going to be merged when do you thing this will be released? We really need this modification for one of our projects. We are using a fork for the moment but this is not a viable option for the future.

Best regards.

@Ocramius
Copy link
Member

@xhuberty I won't get at merging/reviewing stuff for a while for now. This will likely be part of 2.6 though (adding milestone)

@Ocramius Ocramius added this to the 2.6.0 milestone Jan 11, 2016
$this->assertCount(1, $persister->getInserts());

// Create and Set first entity
$entity1 = new NotifyChangedEntity;
Copy link
Member

Choose a reason for hiding this comment

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

These assertions should be moved to their own test case, with an @group 5579 annotation to identify the issue it's related to

@xhuberty xhuberty force-pushed the notifyTrackingPolicy branch from 1fda01d to ed3a7d3 Compare January 12, 2016 14:01
@xhuberty
Copy link
Contributor Author

@Ocramius thanks a lot for your answer.

@driq
Copy link

driq commented May 9, 2016

Hi @xhuberty thank you for writing the patch and @Ocramius for reviewing it.

I'm running into the same issue. Just wanted to let you know that hoping to see this land in 2.6!

@driq
Copy link

driq commented May 9, 2016

FYI:

I noticed similar behaviour in Doctrine\ODM\MongoDB\UnitOfWork::commit($document = null, array $options = array()) on line 440.
Here, the whole state of the UnitOfWork is cleared even after only a single object is committed.

* @param $class
* @param string $oid
*/
private function clearScheduledForSynchronization($class, $oid)
Copy link
Member

Choose a reason for hiding this comment

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

Type hint needed

}

/**
* @param $class
Copy link
Member

Choose a reason for hiding this comment

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

Type hint needed, return type needed

}

/**
* @param null|object|array $entity
Copy link
Member

Choose a reason for hiding this comment

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

Oh dang, I really hate this sort of API signature :-(

/**
* @param null|object|array $entity
*/
private function postCommitClear($entity = null)
Copy link
Member

Choose a reason for hiding this comment

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

Parameter is not optional

$this->orphanRemovals = array();

if (null === $entity) {
$this->entityChangeSets = $this->scheduledForSynchronization = array();
Copy link
Member

Choose a reason for hiding this comment

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

Can use short array notation

$oid = spl_object_hash($object);
$class = $this->em->getClassMetadata(get_class($object));
$this->clearEntityChangeSet($oid);
$this->clearScheduledForSynchronization($class, $oid);
Copy link
Member

Choose a reason for hiding this comment

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

Why isn't this method call internally calling $this->clearEntityChangeSet()?

$this->_unitOfWork->persist($entity2);

$this->_unitOfWork->commit($entity1);
$this->assertCount(1, $this->_unitOfWork->getEntityChangeSet($entity2));
Copy link
Member

Choose a reason for hiding this comment

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

Why is a count used here, instead of simply comparing the changeset? After all, we're checking for a single entry, so a count() operation doesn't seem to make sense to me


$this->_unitOfWork->commit([$entity1,$entity2]);
$this->assertCount(1, $this->_unitOfWork->getEntityChangeSet($entity3));

Copy link
Member

Choose a reason for hiding this comment

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

whitespace to be removed here

$this->_unitOfWork->persist($entity3);

$this->_unitOfWork->commit([$entity1,$entity2]);
$this->assertCount(1, $this->_unitOfWork->getEntityChangeSet($entity3));
Copy link
Member

Choose a reason for hiding this comment

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

Should probably check that there's no changeset for $entity1 and $entity2 here.

$entity3->setData('thedata');
$this->_unitOfWork->persist($entity3);

$this->_unitOfWork->commit([$entity1,$entity2]);
Copy link
Member

Choose a reason for hiding this comment

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

Why committing $entity1 if it was already committed? (also, space after ,)

@Ocramius Ocramius assigned lcobucci and xhuberty and unassigned Ocramius Feb 19, 2017
@Ocramius Ocramius changed the title Fix issue when using notify tracking policy with multiple flush on entities Fix performance issue when using notify tracking policy and calling flush($entity) multiple times Aug 18, 2017
@Ocramius
Copy link
Member

Manually rebased, cleaned up some details and split the tests and packaged for master. Thanks @xhuberty!

Ocramius added a commit that referenced this pull request Aug 18, 2017
Ocramius added a commit that referenced this pull request Aug 18, 2017
…s for the tracking policy changeset clearing
Ocramius added a commit that referenced this pull request Aug 18, 2017
Ocramius added a commit that referenced this pull request Aug 18, 2017
Ocramius added a commit that referenced this pull request Aug 18, 2017
@Ocramius Ocramius closed this in 60e29b4 Aug 18, 2017
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.

5 participants