diff options
8 files changed, 415 insertions, 238 deletions
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/Bugzilla_396804_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/Bugzilla_396804_Test.java new file mode 100644 index 0000000000..0768d7523f --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/Bugzilla_396804_Test.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Erdal Karaca - initial API and implementation + */ +package org.eclipse.emf.cdo.tests; + +import org.eclipse.emf.cdo.eresource.CDOResource; +import org.eclipse.emf.cdo.session.CDOSession; +import org.eclipse.emf.cdo.tests.model1.Model1Factory; +import org.eclipse.emf.cdo.tests.model1.Order; +import org.eclipse.emf.cdo.tests.model1.OrderDetail; +import org.eclipse.emf.cdo.transaction.CDOTransaction; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.spi.cdo.CDOMergingConflictResolver; +import org.eclipse.emf.spi.cdo.DefaultCDOMerger; + +/** + * Test cases for CDOMergingConflictResolver. See bug 396804. + * + * @author Erdal Karaca + */ +public class Bugzilla_396804_Test extends AbstractCDOTest +{ + public void testParallelADD() throws Exception + { + String path = getResourcePath("/res1"); + + { + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + transaction.createResource(path); + transaction.commit(); + session.close(); + } + + CDOSession session1 = openSession(); + CDOTransaction transaction1 = session1.openTransaction(); + transaction1.options().addConflictResolver(createConflictResolver()); + + CDOResource resource1 = transaction1.getResource(path); + transaction1.commit(); + + resource1.getContents().add(Model1Factory.eINSTANCE.createSalesOrder()); + + CDOSession session2 = openSession(); + CDOTransaction transaction2 = session2.openTransaction(); + + CDOResource resource2 = transaction2.getResource(path); + OrderDetail orderDetail = Model1Factory.eINSTANCE.createOrderDetail(); + resource2.getContents().add(orderDetail); + commitAndSync(transaction2, transaction1); + + transaction1.commit(); + } + + public void testParallelRemoveYieldsUnexpectedObjectState() throws Exception + { + String path = getResourcePath("/res1"); + + { + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + + EList<EObject> contents = transaction.createResource(path).getContents(); + contents.add(Model1Factory.eINSTANCE.createOrderDetail()); + contents.add(Model1Factory.eINSTANCE.createOrderDetail()); + + transaction.commit(); + session.close(); + } + + CDOSession session1 = openSession(); + CDOTransaction transaction1 = session1.openTransaction(); + transaction1.options().addConflictResolver(createConflictResolver()); + + EList<EObject> contents1 = transaction1.getResource(path).getContents(); + OrderDetail firstOrderDetail1 = (OrderDetail)contents1.get(0); + Order order = Model1Factory.eINSTANCE.createSalesOrder(); + order.getOrderDetails().add(firstOrderDetail1); // change2: contents1.remove(0) + contents1.add(order); // change3 + + CDOSession session2 = openSession(); + CDOTransaction transaction2 = session2.openTransaction(); + + EList<EObject> contents2 = transaction2.getResource(path).getContents(); + contents2.remove(1); // change1: lastOrderDetail2 + commitAndSync(transaction2, transaction1); + + transaction1.commit(); + } + + public void testParallelRemoveThrowsIOOBE() throws Exception + { + String path = getResourcePath("/res1"); + + { + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.createResource(path); + + resource.getContents().add(Model1Factory.eINSTANCE.createOrderDetail()); + resource.getContents().add(Model1Factory.eINSTANCE.createOrderDetail()); + + transaction.commit(); + session.close(); + } + + CDOSession session1 = openSession(); + CDOTransaction transaction1 = session1.openTransaction(); + transaction1.options().addConflictResolver(createConflictResolver()); + + CDOResource resource1 = transaction1.getResource(path); + Order order = Model1Factory.eINSTANCE.createSalesOrder(); + resource1.getContents().add(order); + + CDOSession session2 = openSession(); + CDOTransaction transaction2 = session2.openTransaction(); + + CDOResource resource2 = transaction2.getResource(path); + OrderDetail lastOrderDetail = (OrderDetail)resource2.getContents().get(resource2.getContents().size() - 1); + resource2.getContents().remove(lastOrderDetail); + commitAndSync(transaction2, transaction1); + + transaction1.commit(); + } + + private CDOMergingConflictResolver createConflictResolver() + { + return new CDOMergingConflictResolver(new DefaultCDOMerger.PerFeature.ManyValued()); + } +} diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ConflictResolverExtendedTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ConflictResolverExtendedTest.java index 255a8aefbf..01f65bc853 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ConflictResolverExtendedTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ConflictResolverExtendedTest.java @@ -25,6 +25,7 @@ import org.eclipse.emf.cdo.util.CommitException; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.notify.impl.AdapterImpl; import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.spi.cdo.CDOMergingConflictResolver; import java.util.List; @@ -35,8 +36,7 @@ public class ConflictResolverExtendedTest extends AbstractCDOTest { private static final String TEST_RESOURCE_NAME = "/test1"; - @SuppressWarnings("deprecation") - private CDOConflictResolver conflictResolver = new org.eclipse.emf.spi.cdo.CDOMergingConflictResolver(); + private CDOConflictResolver conflictResolver = new CDOMergingConflictResolver(); // --- initialize model ---------------------------------------------------- diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ConflictResolverMergingTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ConflictResolverMergingTest.java index 175cf70bf9..fd00cd1f1c 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ConflictResolverMergingTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ConflictResolverMergingTest.java @@ -20,6 +20,7 @@ import org.eclipse.emf.cdo.util.CDOUtil; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.spi.cdo.CDOMergingConflictResolver; /** * @author Simon McDuff @@ -102,40 +103,47 @@ public class ConflictResolverMergingTest extends ConflictResolverTest msg("Opening session"); CDOSession session = openSession(); + // CLIENT-1 creates sales order CDOTransaction transaction1 = session.openTransaction(); transaction1.options().addConflictResolver(createConflictResolver()); EList<EObject> contents1 = transaction1.getOrCreateResource(getResourcePath("/res1")).getContents(); - SalesOrder c1 = getModel1Factory().createSalesOrder(); - contents1.add(c1); + SalesOrder salesOrder1 = getModel1Factory().createSalesOrder(); + EList<OrderDetail> orderDetails1 = salesOrder1.getOrderDetails(); + + contents1.add(salesOrder1); transaction1.commit(); + // CLIENT-2 loads sales order CDOTransaction transaction2 = session.openTransaction(); transaction2.options().addConflictResolver(createConflictResolver()); EList<EObject> contents2 = transaction2.getOrCreateResource(getResourcePath("/res1")).getContents(); - SalesOrder c2 = (SalesOrder)contents2.get(0); + SalesOrder salesOrder2 = (SalesOrder)contents2.get(0); + EList<OrderDetail> orderDetails2 = salesOrder2.getOrderDetails(); - OrderDetail s1 = getModel1Factory().createOrderDetail(); - c1.getOrderDetails().add(s1); + // CLIENT-1 adds order detail + OrderDetail orderDetail1 = getModel1Factory().createOrderDetail(); + orderDetails1.add(orderDetail1); - OrderDetail s2 = getModel1Factory().createOrderDetail(); - c2.getOrderDetails().add(s2); + // CLIENT-2 adds order detail + OrderDetail orderDetail2 = getModel1Factory().createOrderDetail(); + orderDetails2.add(orderDetail2); + // CLIENT-1 commits and waits for CLIENT-2's conflict resolver commitAndSync(transaction1, transaction2); + + // CLIENT-2 commits and waits for CLIENT-1's conflict resolver (nothing to do there) commitAndSync(transaction2, transaction1); - EList<OrderDetail> list = c1.getOrderDetails(); - System.out.println(list); - assertEquals(2, list.size()); - assertEquals(CDOUtil.getCDOObject(s2).cdoID(), CDOUtil.getCDOObject(list.get(0)).cdoID()); - assertEquals(CDOUtil.getCDOObject(s1).cdoID(), CDOUtil.getCDOObject(list.get(1)).cdoID()); + assertEquals(2, orderDetails1.size()); + assertEquals(CDOUtil.getCDOObject(orderDetail2).cdoID(), CDOUtil.getCDOObject(orderDetails1.get(0)).cdoID()); + assertEquals(CDOUtil.getCDOObject(orderDetail1).cdoID(), CDOUtil.getCDOObject(orderDetails1.get(1)).cdoID()); } - @SuppressWarnings("deprecation") @Override protected CDOConflictResolver createConflictResolver() { - return new org.eclipse.emf.spi.cdo.CDOMergingConflictResolver(); + return new CDOMergingConflictResolver(); } } diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java index a6b38604a7..bf7ce48068 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java @@ -91,7 +91,6 @@ import org.eclipse.emf.internal.cdo.util.DefaultLocksChangedEvent; import org.eclipse.net4j.util.ObjectUtil; import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump; import org.eclipse.net4j.util.WrappedException; -import org.eclipse.net4j.util.collection.Pair; import org.eclipse.net4j.util.concurrent.IRWLockManager; import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; import org.eclipse.net4j.util.concurrent.IRWOLockManager; @@ -909,7 +908,6 @@ public abstract class CDOSessionImpl extends CDOTransactionContainerImpl impleme Map<CDOID, InternalCDORevision> oldRevisions = null; CDOBranch newBranch = commitInfo.getBranch(); long timeStamp = commitInfo.getTimeStamp(); - InternalCDORevisionManager revisionManager = getRevisionManager(); // Cache new revisions for (CDOIDAndVersion key : commitInfo.getNewObjects()) @@ -924,96 +922,37 @@ public abstract class CDOSessionImpl extends CDOTransactionContainerImpl impleme // Apply deltas and cache the resulting new revisions, if possible... for (CDORevisionKey key : commitInfo.getChangedObjects()) { - // Add old values to revision deltas. + CDOID id = key.getID(); if (key instanceof CDORevisionDelta) { - final CDORevisionDelta revisionDelta = (CDORevisionDelta)key; - final CDORevision oldRevision = revisionManager.getRevisionByVersion(revisionDelta.getID(), revisionDelta, - CDORevision.UNCHUNKED, false); + CDORevisionDelta revisionDelta = (CDORevisionDelta)key; + InternalCDORevision oldRevision = revisionManager.getRevisionByVersion(id, revisionDelta, + CDORevision.UNCHUNKED, false); if (oldRevision != null) { - CDOFeatureDeltaVisitor visitor = new CDOFeatureDeltaVisitorImpl() - { - private List<Object> workList; - - @Override - public void visit(CDOAddFeatureDelta delta) - { - workList.add(delta.getIndex(), delta.getValue()); - } - - @Override - public void visit(CDOClearFeatureDelta delta) - { - workList.clear(); - } - - @Override - public void visit(CDOListFeatureDelta deltas) - { - @SuppressWarnings("unchecked") - List<Object> list = (List<Object>)((InternalCDORevision)oldRevision).getValue(deltas.getFeature()); - if (list != null) - { - workList = new ArrayList<Object>(list); - super.visit(deltas); - } - } - - @Override - public void visit(CDOMoveFeatureDelta delta) - { - Object value = workList.get(delta.getOldPosition()); - ((CDOMoveFeatureDeltaImpl)delta).setValue(value); - ECollections.move(workList, delta.getNewPosition(), delta.getOldPosition()); - } + addOldValuesToDelta(oldRevision, revisionDelta); - @Override - public void visit(CDORemoveFeatureDelta delta) - { - Object oldValue = workList.remove(delta.getIndex()); - ((CDOSingleValueFeatureDeltaImpl)delta).setValue(oldValue); - } + InternalCDORevision newRevision = oldRevision.copy(); + newRevision.adjustForCommit(commitInfo.getBranch(), commitInfo.getTimeStamp()); - @Override - public void visit(CDOSetFeatureDelta delta) - { - EStructuralFeature feature = delta.getFeature(); - Object value = null; - if (feature.isMany()) - { - value = workList.set(delta.getIndex(), delta.getValue()); - } - else - { - value = ((InternalCDORevision)oldRevision).getValue(feature); - } + CDORevisable target = revisionDelta.getTarget(); + if (target != null) + { + newRevision.setVersion(target.getVersion()); + } - ((CDOSetFeatureDeltaImpl)delta).setOldValue(value); - } - }; + revisionDelta.apply(newRevision); + newRevision.freeze(); - for (CDOFeatureDelta featureDelta : revisionDelta.getFeatureDeltas()) + revisionManager.addRevision(newRevision); + if (oldRevisions == null) { - featureDelta.accept(visitor); + oldRevisions = new HashMap<CDOID, InternalCDORevision>(); } - } - } - CDOID id = key.getID(); - Pair<InternalCDORevision, InternalCDORevision> pair = createNewRevision(key, commitInfo); - if (pair != null) - { - InternalCDORevision newRevision = pair.getElement2(); - revisionManager.addRevision(newRevision); - if (oldRevisions == null) - { - oldRevisions = new HashMap<CDOID, InternalCDORevision>(); + oldRevisions.put(id, oldRevision); } - - InternalCDORevision oldRevision = pair.getElement1(); - oldRevisions.put(id, oldRevision); } else { @@ -1035,35 +974,78 @@ public abstract class CDOSessionImpl extends CDOTransactionContainerImpl impleme return oldRevisions; } - private Pair<InternalCDORevision, InternalCDORevision> createNewRevision(CDORevisionKey potentialDelta, - CDOCommitInfo commitInfo) + /** + * Computes/adjusts CDOMoveFeatureDelta.value, CDORemoveFeatureDelta.value and CDOSetFeatureDelta.oldValue. + * <p> + * Implicitely adjusts the underlying CDORevisionDelta. + */ + private void addOldValuesToDelta(final CDORevision oldRevision, CDORevisionDelta revisionDelta) { - if (potentialDelta instanceof CDORevisionDelta) + CDOFeatureDeltaVisitor visitor = new CDOFeatureDeltaVisitorImpl() { - CDORevisionDelta delta = (CDORevisionDelta)potentialDelta; - CDOID id = delta.getID(); + private List<Object> workList; - InternalCDORevisionManager revisionManager = getRevisionManager(); - InternalCDORevision oldRevision = revisionManager.getRevisionByVersion(id, potentialDelta, CDORevision.UNCHUNKED, - false); - if (oldRevision != null) + @Override + public void visit(CDOAddFeatureDelta delta) { - InternalCDORevision newRevision = oldRevision.copy(); - newRevision.adjustForCommit(commitInfo.getBranch(), commitInfo.getTimeStamp()); + workList.add(delta.getIndex(), delta.getValue()); + } - CDORevisable target = delta.getTarget(); - if (target != null) + @Override + public void visit(CDOClearFeatureDelta delta) + { + workList.clear(); + } + + @Override + public void visit(CDOListFeatureDelta deltas) + { + @SuppressWarnings("unchecked") + List<Object> list = (List<Object>)((InternalCDORevision)oldRevision).getValue(deltas.getFeature()); + if (list != null) { - newRevision.setVersion(target.getVersion()); + workList = new ArrayList<Object>(list); + super.visit(deltas); } + } - delta.apply(newRevision); - newRevision.freeze(); - return new Pair<InternalCDORevision, InternalCDORevision>(oldRevision, newRevision); + @Override + public void visit(CDOMoveFeatureDelta delta) + { + Object value = workList.get(delta.getOldPosition()); + ((CDOMoveFeatureDeltaImpl)delta).setValue(value); // Adjust delta + ECollections.move(workList, delta.getNewPosition(), delta.getOldPosition()); } - } - return null; + @Override + public void visit(CDORemoveFeatureDelta delta) + { + Object oldValue = workList.remove(delta.getIndex()); + ((CDOSingleValueFeatureDeltaImpl)delta).setValue(oldValue); // Adjust delta + } + + @Override + public void visit(CDOSetFeatureDelta delta) + { + EStructuralFeature feature = delta.getFeature(); + Object value = null; + if (feature.isMany()) + { + value = workList.set(delta.getIndex(), delta.getValue()); + } + else + { + value = ((InternalCDORevision)oldRevision).getValue(feature); + } + + ((CDOSetFeatureDeltaImpl)delta).setOldValue(value); // Adjust delta + } + }; + + for (CDOFeatureDelta featureDelta : revisionDelta.getFeatureDeltas()) + { + featureDelta.accept(visitor); + } } @Deprecated diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/AbstractChangeSetsConflictResolver.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/AbstractChangeSetsConflictResolver.java index 0da5bcdc0d..20f38f0f32 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/AbstractChangeSetsConflictResolver.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/AbstractChangeSetsConflictResolver.java @@ -46,7 +46,7 @@ public abstract class AbstractChangeSetsConflictResolver extends AbstractConflic if (getTransaction() == transaction) { adapter.reset(); - aggregator.reset(); + remoteInvalidationEvents.reset(); } } @@ -57,14 +57,14 @@ public abstract class AbstractChangeSetsConflictResolver extends AbstractConflic if (getTransaction() == transaction && transaction.getLastSavepoint().getPreviousSavepoint() == null) { adapter.reset(); - aggregator.reset(); + remoteInvalidationEvents.reset(); } } }; private CDOChangeSubscriptionAdapter adapter; - private RemoteAggregator aggregator; + private RemoteInvalidationEventQueue remoteInvalidationEvents; public AbstractChangeSetsConflictResolver() { @@ -77,19 +77,19 @@ public abstract class AbstractChangeSetsConflictResolver extends AbstractConflic public CDOChangeSet getLocalChangeSet() { - CDOTransaction transaction = getTransaction(); - return CDORevisionUtil.createChangeSet(transaction, transaction, getLocalChangeSetData()); + CDOChangeSetData changeSetData = getLocalChangeSetData(); + return createChangeSet(changeSetData); } public CDOChangeSetData getRemoteChangeSetData() { - return aggregator.getChangeSetData(); + return remoteInvalidationEvents.getChangeSetData(); } public CDOChangeSet getRemoteChangeSet() { - CDOTransaction transaction = getTransaction(); - return CDORevisionUtil.createChangeSet(transaction, transaction, getRemoteChangeSetData()); + CDOChangeSetData changeSetData = remoteInvalidationEvents.getChangeSetData(); + return createChangeSet(changeSetData); } @Override @@ -97,14 +97,14 @@ public abstract class AbstractChangeSetsConflictResolver extends AbstractConflic { transaction.addTransactionHandler(handler); adapter = new CDOChangeSubscriptionAdapter(getTransaction()); - aggregator = new RemoteAggregator(); + remoteInvalidationEvents = new RemoteInvalidationEventQueue(); } @Override protected void unhookTransaction(CDOTransaction transaction) { - aggregator.dispose(); - aggregator = null; + remoteInvalidationEvents.dispose(); + remoteInvalidationEvents = null; adapter.dispose(); adapter = null; @@ -112,12 +112,18 @@ public abstract class AbstractChangeSetsConflictResolver extends AbstractConflic transaction.removeTransactionHandler(handler); } + private CDOChangeSet createChangeSet(CDOChangeSetData changeSetData) + { + CDOTransaction transaction = getTransaction(); + return CDORevisionUtil.createChangeSet(transaction, transaction, changeSetData); + } + /** * @author Eike Stepper */ - private final class RemoteAggregator extends CDOSessionInvalidationAggregator + private final class RemoteInvalidationEventQueue extends CDOSessionInvalidationEventQueue { - public RemoteAggregator() + public RemoteInvalidationEventQueue() { super(getTransaction().getSession()); } @@ -125,10 +131,20 @@ public abstract class AbstractChangeSetsConflictResolver extends AbstractConflic @Override protected void handleEvent(CDOSessionInvalidationEvent event) throws Exception { - if (event.getBranch() == getTransaction().getBranch()) + CDOTransaction transaction = getTransaction(); + if (event.getLocalTransaction() == transaction) { - super.handleEvent(event); + // Don't handle own changes + return; } + + if (event.getBranch() != transaction.getBranch()) + { + // Don't handle changes in other branches + return; + } + + super.handleEvent(event); } } } diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOMergingConflictResolver.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOMergingConflictResolver.java index 27964731b0..c7d3022a9b 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOMergingConflictResolver.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOMergingConflictResolver.java @@ -15,17 +15,14 @@ import org.eclipse.emf.cdo.CDOState; import org.eclipse.emf.cdo.common.commit.CDOChangeSet; import org.eclipse.emf.cdo.common.commit.CDOChangeSetData; import org.eclipse.emf.cdo.common.id.CDOID; -import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.common.revision.CDORevisionKey; import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta; -import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager; import org.eclipse.emf.cdo.transaction.CDOMerger; import org.eclipse.emf.cdo.transaction.CDOMerger.ConflictException; -import org.eclipse.net4j.util.CheckUtil; - +import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -34,9 +31,7 @@ import java.util.Set; * * @author Eike Stepper * @since 4.0 - * @deprecated This conflict resolver is still under development. It's not safe to use it. */ -@Deprecated public class CDOMergingConflictResolver extends AbstractChangeSetsConflictResolver { private CDOMerger merger; @@ -58,14 +53,13 @@ public class CDOMergingConflictResolver extends AbstractChangeSetsConflictResolv public void resolveConflicts(Set<CDOObject> conflicts) { + CDOChangeSet localChangeSet = getLocalChangeSet(); + CDOChangeSet remoteChangeSet = getRemoteChangeSet(); CDOChangeSetData result; try { - CDOChangeSet target = getLocalChangeSet(); - CDOChangeSet source = getRemoteChangeSet(); - - result = merger.merge(target, source); + result = merger.merge(localChangeSet, remoteChangeSet); } catch (ConflictException ex) { @@ -73,45 +67,54 @@ public class CDOMergingConflictResolver extends AbstractChangeSetsConflictResolv } InternalCDOTransaction transaction = (InternalCDOTransaction)getTransaction(); - InternalCDORevisionManager revisionManager = transaction.getSession().getRevisionManager(); + Map<InternalCDOObject, InternalCDORevision> cleanRevisions = transaction.getCleanRevisions(); + Map<CDOID, CDORevisionDelta> localDeltas = transaction.getLastSavepoint().getRevisionDeltas2(); + Map<CDOID, CDORevisionDelta> remoteDeltas = getRemoteDeltas(remoteChangeSet); for (CDORevisionKey key : result.getChangedObjects()) { - InternalCDORevisionDelta delta = (InternalCDORevisionDelta)key; - CDOID id = delta.getID(); + InternalCDORevisionDelta resultDelta = (InternalCDORevisionDelta)key; + CDOID id = resultDelta.getID(); InternalCDOObject object = (InternalCDOObject)transaction.getObject(id, false); if (object != null) { - CDOState state = object.cdoState(); - if (state == CDOState.CLEAN || state == CDOState.PROXY) - { - InternalCDORevision revision = revisionManager.getRevision(id, transaction, CDORevision.UNCHUNKED, - CDORevision.DEPTH_NONE, false); - CheckUtil.checkState(revision, "revision"); - - object.cdoInternalSetRevision(revision); - object.cdoInternalSetState(CDOState.CLEAN); - } - else if (state == CDOState.CONFLICT) - { - int newVersion = delta.getVersion() + 1; - - InternalCDORevision revision = transaction.getCleanRevisions().get(object).copy(); - revision.setVersion(newVersion); - delta.apply(revision); - - object.cdoInternalSetRevision(revision); - object.cdoInternalSetState(CDOState.DIRTY); - - InternalCDORevisionDelta localDelta = (InternalCDORevisionDelta)localDeltas.get(id); - localDelta.setVersion(newVersion); - } - else - { - throw new IllegalStateException("Unexpected objects state: " + state); - } + // Compute new version + InternalCDORevision localRevision = object.cdoRevision(); + int newVersion = localRevision.getVersion() + 1; + + // Compute new local revision + InternalCDORevision cleanRevision = cleanRevisions.get(object); + InternalCDORevision newLocalRevision = cleanRevision.copy(); + newLocalRevision.setVersion(newVersion); + resultDelta.apply(newLocalRevision); + + object.cdoInternalSetRevision(newLocalRevision); + object.cdoInternalSetState(CDOState.DIRTY); + + // Compute new clean revision + CDORevisionDelta remoteDelta = remoteDeltas.get(id); + InternalCDORevision newCleanRevision = cleanRevision.copy(); + newCleanRevision.setVersion(newVersion); + remoteDelta.apply(newCleanRevision); + cleanRevisions.put(object, newCleanRevision); + + // Compute new local delta + InternalCDORevisionDelta newLocalDelta = newLocalRevision.compare(newCleanRevision); + newLocalDelta.setTarget(null); + localDeltas.put(id, newLocalDelta); } } } + + private Map<CDOID, CDORevisionDelta> getRemoteDeltas(CDOChangeSet remoteChangeSet) + { + Map<CDOID, CDORevisionDelta> remoteDeltas = new HashMap<CDOID, CDORevisionDelta>(); + for (CDORevisionKey key : remoteChangeSet.getChangedObjects()) + { + remoteDeltas.put(key.getID(), (CDORevisionDelta)key); + } + + return remoteDeltas; + } } diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionInvalidationAggregator.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionInvalidationAggregator.java index 5be7dd7967..70c701c560 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionInvalidationAggregator.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionInvalidationAggregator.java @@ -10,86 +10,22 @@ */ package org.eclipse.emf.spi.cdo; -import org.eclipse.emf.cdo.common.commit.CDOChangeSetData; import org.eclipse.emf.cdo.session.CDOSession; -import org.eclipse.emf.cdo.session.CDOSessionInvalidationEvent; - -import org.eclipse.emf.internal.cdo.bundle.OM; - -import org.eclipse.net4j.util.event.IEvent; -import org.eclipse.net4j.util.event.IListener; /** * If the meaning of this type isn't clear, there really should be more of a description here... * * @author Eike Stepper * @since 4.0 + * @deprecated As of 4.2 use {@link CDOSessionInvalidationEventQueue}. * @noextend This interface is not intended to be extended by clients. * @noinstantiate This class is not intended to be instantiated by clients. */ -public class CDOSessionInvalidationAggregator +@Deprecated +public class CDOSessionInvalidationAggregator extends CDOSessionInvalidationEventQueue { - private CDOSession session; - - private IListener sessionListener = new IListener() - { - public void notifyEvent(IEvent event) - { - try - { - if (event instanceof CDOSessionInvalidationEvent) - { - CDOSessionInvalidationEvent e = (CDOSessionInvalidationEvent)event; - handleEvent(e); - } - } - catch (Exception ex) - { - OM.LOG.error(ex); - } - } - }; - - private CDOChangeSetData changeSetData; - public CDOSessionInvalidationAggregator(CDOSession session) { - this.session = session; - session.addListener(sessionListener); - } - - public void dispose() - { - reset(); - session.removeListener(sessionListener); - session = null; - } - - public CDOSession getSession() - { - return session; - } - - public CDOChangeSetData getChangeSetData() - { - return changeSetData; - } - - public void reset() - { - changeSetData = null; - } - - protected void handleEvent(CDOSessionInvalidationEvent event) throws Exception - { - CDOChangeSetData copy = event.copy(); - if (changeSetData == null) - { - changeSetData = copy; - } - else - { - changeSetData.merge(copy); - } + super(session); } } diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionInvalidationEventQueue.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionInvalidationEventQueue.java new file mode 100644 index 0000000000..2690bd9c64 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionInvalidationEventQueue.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.emf.spi.cdo; + +import org.eclipse.emf.cdo.common.commit.CDOChangeSetData; +import org.eclipse.emf.cdo.session.CDOSession; +import org.eclipse.emf.cdo.session.CDOSessionInvalidationEvent; + +import org.eclipse.emf.internal.cdo.bundle.OM; + +import org.eclipse.net4j.util.event.IEvent; +import org.eclipse.net4j.util.event.IListener; + +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * If the meaning of this type isn't clear, there really should be more of a description here... + * + * @author Eike Stepper + * @since 4.2 + * @noextend This interface is not intended to be extended by clients. + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class CDOSessionInvalidationEventQueue +{ + private CDOSession session; + + private IListener sessionListener = new IListener() + { + public void notifyEvent(IEvent event) + { + try + { + if (event instanceof CDOSessionInvalidationEvent) + { + CDOSessionInvalidationEvent e = (CDOSessionInvalidationEvent)event; + handleEvent(e); + } + } + catch (Exception ex) + { + OM.LOG.error(ex); + } + } + }; + + private Queue<CDOChangeSetData> queue = new ConcurrentLinkedQueue<CDOChangeSetData>(); + + public CDOSessionInvalidationEventQueue(CDOSession session) + { + this.session = session; + session.addListener(sessionListener); + } + + public void dispose() + { + reset(); + session.removeListener(sessionListener); + session = null; + } + + public CDOSession getSession() + { + return session; + } + + /** + * Removes and returns the first event from this queue. + */ + public CDOChangeSetData getChangeSetData() + { + return queue.poll(); + } + + public void reset() + { + queue.clear(); + } + + protected void handleEvent(CDOSessionInvalidationEvent event) throws Exception + { + queue.offer(event); + } +} |