blob: 24dce64ef249dc8b52140f2b8ad2c071139e9ae3 [file] [log] [blame]
/*
* Copyright (c) 2019 Eike Stepper (Loehne, 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.cdo.spi.server;
import org.eclipse.emf.cdo.common.branch.CDOBranch;
import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
import org.eclipse.emf.cdo.common.branch.CDOBranchVersion;
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.id.CDOIDUtil;
import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
import org.eclipse.emf.cdo.common.revision.CDORevisionUtil;
import org.eclipse.emf.cdo.server.IStoreAccessor;
import org.eclipse.emf.cdo.server.IStoreAccessor.CommitContext;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta;
import org.eclipse.emf.cdo.transaction.CDOMerger;
import org.eclipse.emf.cdo.transaction.CDOMerger.ConflictException;
import org.eclipse.emf.spi.cdo.DefaultCDOMerger;
import java.util.AbstractList;
import java.util.List;
/**
* @author Eike Stepper
* @since 4.8
*/
public interface ICommitConflictResolver
{
/**
* When this method is called, the {@link CommitContext#getOldRevisions()} map is filled with the latest valid revisions, chunks ensured.
*/
public CDOChangeSetData resolveConflicts(IStoreAccessor.CommitContext commitContext, List<InternalCDORevisionDelta> conflicts);
/**
* @author Eike Stepper
*/
public static class Merging implements ICommitConflictResolver
{
public CDOChangeSetData resolveConflicts(IStoreAccessor.CommitContext commitContext, List<InternalCDORevisionDelta> conflicts)
{
CDOBranchPoint sourceEndPoint = commitContext.getBranchPoint();
CDOBranch branch = sourceEndPoint.getBranch();
CDOBranchPoint startPoint = branch.getPoint(commitContext.getLastUpdateTime());
CDOBranchPoint targetEndPoint = branch.getPoint(commitContext.getTransaction().getRepository().getLastCommitTimeStamp());
CDOChangeSet source = createSourceChangeSet(commitContext, startPoint, sourceEndPoint);
CDOChangeSet target = createTargetChangeSet(commitContext, startPoint, targetEndPoint);
CDOMerger merger = createMerger();
try
{
CDOChangeSetData result = merger.merge(target, source);
conflicts.clear();
return result;
}
catch (ConflictException ex)
{
CDOChangeSetData result = ex.getResult();
for (CDORevisionKey revisionKey : result.getChangedObjects())
{
conflicts.remove(revisionKey);
}
}
return null;
}
protected CDOMerger createMerger()
{
return new DefaultCDOMerger.PerFeature.ManyValued();
}
private CDOChangeSet createSourceChangeSet(final IStoreAccessor.CommitContext commitContext, CDOBranchPoint startPoint, CDOBranchPoint endPoint)
{
List<CDOIDAndVersion> newObjects = new AbstractList<CDOIDAndVersion>()
{
private final InternalCDORevision[] revisions = commitContext.getNewObjects();
private final int size = revisions.length;
@Override
public int size()
{
return size;
}
@Override
public CDOIDAndVersion get(int index)
{
return revisions[index];
}
};
List<CDORevisionKey> changedObjects = new AbstractList<CDORevisionKey>()
{
private final InternalCDORevisionDelta[] revisionDeltas = commitContext.getDirtyObjectDeltas();
private final int size = revisionDeltas.length;
@Override
public int size()
{
return size;
}
@Override
public CDORevisionKey get(int index)
{
return revisionDeltas[index];
}
};
List<CDOIDAndVersion> detachedObjects = new AbstractList<CDOIDAndVersion>()
{
private final CDOID[] ids = commitContext.getDetachedObjects();
private final CDOBranchVersion[] branchVersions = commitContext.getDetachedObjectVersions();
private final int size = ids.length;
@Override
public int size()
{
return size;
}
@Override
public CDOIDAndVersion get(int index)
{
return CDOIDUtil.createIDAndVersion(ids[index], branchVersions[index].getVersion());
}
};
CDOChangeSetData sourceChangeSetData = CDORevisionUtil.createChangeSetData(newObjects, changedObjects, detachedObjects);
return CDORevisionUtil.createChangeSet(startPoint, endPoint, sourceChangeSetData);
}
private CDOChangeSet createTargetChangeSet(IStoreAccessor.CommitContext commitContext, CDOBranchPoint startPoint, CDOBranchPoint endPoint)
{
InternalRepository repository = (InternalRepository)commitContext.getTransaction().getRepository();
CDOChangeSetData targetChangeSetData = repository.getChangeSet(startPoint, endPoint);
return CDORevisionUtil.createChangeSet(startPoint, endPoint, targetChangeSetData);
}
}
}