Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 336590 - CDOConflictResolver2 receives spurious delta in case of remote removal + local add
Summary: CDOConflictResolver2 receives spurious delta in case of remote removal + loca...
Status: CLOSED FIXED
Alias: None
Product: EMF
Classification: Modeling
Component: cdo.core (show other bugs)
Version: 4.0   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Caspar D. CLA
QA Contact: Eike Stepper CLA
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-02-08 03:10 EST by Caspar D. CLA
Modified: 2011-06-23 03:40 EDT (History)
2 users (show)

See Also:
stepper: review+
stepper: review+


Attachments
Testcase (as patch) (4.94 KB, patch)
2011-02-08 03:11 EST, Caspar D. CLA
no flags Details | Diff
Patch (including testcase) (7.27 KB, patch)
2011-02-08 06:01 EST, Caspar D. CLA
no flags Details | Diff
Patch v2 - ready to be committed (7.33 KB, patch)
2011-02-10 00:24 EST, Eike Stepper CLA
no flags Details | Diff
Patch v3 (7.39 KB, patch)
2011-02-10 01:47 EST, Caspar D. CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Caspar D. CLA 2011-02-08 03:10:01 EST
Say object x has an isMany feature x.zz = {a,b,c}.

In session1 with passiveUpdates=false and a resolver configured
which implements CDOConflictResolver2, we load this object
and add child 'd', so that x.zz = {a,b,c,d}. In another
session, we load x also, remove 'a', and commit. Then we call
refresh in session 1.

The resolver in session 1 receives 1 CDORevDelta (correct), 
containing 1 CDOFeatDelta (correct), which is a CDOListFeatDelta
containing 2 (incorrect) CDORemoveFeatDeltas. The superfluous
CDORemoveFeatDelta seems to pertain to 'd'.

Btw, I'm aware that we have vague plans to make CDOConflictResolver2
obsolete, but as long as those plans aren't executed (which I'm not
sure is a good idea anyway), this bug stands...
Comment 1 Caspar D. CLA 2011-02-08 03:11:26 EST
Created attachment 188498 [details]
Testcase (as patch)
Comment 2 Pascal Lehmann CLA 2011-02-08 04:14:36 EST
When refreshing the session manually the delta is computed using the remote and local revision. However if you have already changed something locally the delta will not be correct as the ancestor should have been used to compute the delta.
Comment 3 Caspar D. CLA 2011-02-08 04:35:53 EST
Yeah I realized that, thanks.

We could fetch the 'clean' revision from the transaction instead.
That would prevent local changes from being included.

But that clean revision is not necessarily the same as the
remote 'ancestor' -- especially if passiveUpdates=false, it's
likely that it's not the ancestor...
Comment 4 Caspar D. CLA 2011-02-08 06:01:39 EST
Created attachment 188506 [details]
Patch (including testcase)
Comment 5 Caspar D. CLA 2011-02-08 06:03:14 EST
Simple patch that allows a transaction to insert the clean,
loaded revision into the viewedRevisions collection, instead
of the revision actually backing the object.

Perhaps viewedRevisions should be renamed 'loadedRevisions'.
Comment 6 Eike Stepper CLA 2011-02-10 00:24:49 EST
Created attachment 188647 [details]
Patch v2 - ready to be committed

I've moved the super call to the end of getViewedRevision() so that it is not unnecessarily (?) executed before cleanRevisions.get().

Do you think the string conversion here is needed?
  assertEquals(removedID.toString(), removedValue.toString());
Comment 7 Caspar D. CLA 2011-02-10 01:42:46 EST
(In reply to comment #6)
> I've moved the super call to the end of getViewedRevision() so that it is not
> unnecessarily (?) executed before cleanRevisions.get().

I'm wondering if we should check first whether getViewedRevision returns
null from the readNoLoad call.

> Do you think the string conversion here is needed?
> assertEquals(removedID.toString(), removedValue.toString());

No idea. Depends on the equals() of a particular ID implementation
I suppose. The String comparison seemed like the safest way.
Comment 8 Caspar D. CLA 2011-02-10 01:47:57 EST
Created attachment 188653 [details]
Patch v3
Comment 9 Eike Stepper CLA 2011-02-10 01:48:25 EST
(In reply to comment #7)
> (In reply to comment #6)
> > I've moved the super call to the end of getViewedRevision() so that it is not
> > unnecessarily (?) executed before cleanRevisions.get().
> 
> I'm wondering if we should check first whether getViewedRevision returns
> null from the readNoLoad call.

What would that change? What problem do you foresee otherwise?

> > Do you think the string conversion here is needed?
> > assertEquals(removedID.toString(), removedValue.toString());
> 
> No idea. Depends on the equals() of a particular ID implementation
> I suppose. The String comparison seemed like the safest way.

Not too important, but the toString() contract does not explicitely require the result to be unique. But all CDOIDs have an equals() method.
Comment 10 Caspar D. CLA 2011-02-10 01:52:33 EST
Committed to trunk, rev. 7043
Comment 11 Eike Stepper CLA 2011-06-23 03:40:01 EDT
Available in R20110608-1407