blob: c89da07d7f45fea7886f2836215caa396efb00e2 [file] [log] [blame]
/*
* Copyright (c) 2011-2014 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
* Simon McDuff - bug 201266
* Simon McDuff - bug 230832
*/
package org.eclipse.emf.cdo.internal.common.revision;
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.id.CDOID;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
import org.eclipse.emf.cdo.internal.common.bundle.OM;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionCache;
import org.eclipse.net4j.util.CheckUtil;
import org.eclipse.net4j.util.om.trace.ContextTracer;
import org.eclipse.emf.ecore.EClass;
import java.lang.ref.Reference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
/**
* @author Eike Stepper
*/
public class CDORevisionCacheAuditing extends AbstractCDORevisionCache
{
private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_REVISION, CDORevisionCacheAuditing.class);
protected Map<Object, RevisionList> revisionLists = new HashMap<Object, RevisionList>();
public CDORevisionCacheAuditing()
{
}
public InternalCDORevisionCache instantiate(CDORevision revision)
{
return new CDORevisionCacheAuditing();
}
public EClass getObjectType(CDOID id)
{
synchronized (revisionLists)
{
RevisionList revisionList = revisionLists.get(id);
if (revisionList != null && !revisionList.isEmpty())
{
Reference<InternalCDORevision> ref = revisionList.getFirst();
InternalCDORevision revision = ref.get();
if (revision != null)
{
return revision.getEClass();
}
}
return null;
}
}
public InternalCDORevision getRevision(CDOID id, CDOBranchPoint branchPoint)
{
checkBranch(branchPoint.getBranch());
RevisionList revisionList = getRevisionList(id, branchPoint.getBranch());
if (revisionList != null)
{
return revisionList.getRevision(branchPoint.getTimeStamp());
}
return null;
}
public InternalCDORevision getRevisionByVersion(CDOID id, CDOBranchVersion branchVersion)
{
CDOBranch branch = branchVersion.getBranch();
checkBranch(branch);
RevisionList revisionList = getRevisionList(id, branch);
if (revisionList != null)
{
return revisionList.getRevisionByVersion(branchVersion.getVersion());
}
return null;
}
public List<CDORevision> getCurrentRevisions()
{
List<CDORevision> currentRevisions = new ArrayList<CDORevision>();
synchronized (revisionLists)
{
for (RevisionList revisionList : revisionLists.values())
{
InternalCDORevision revision = revisionList.getRevision(CDORevision.UNSPECIFIED_DATE);
if (revision != null)
{
currentRevisions.add(revision);
}
}
}
return currentRevisions;
}
public Map<CDOBranch, List<CDORevision>> getAllRevisions()
{
Map<CDOBranch, List<CDORevision>> result = new HashMap<CDOBranch, List<CDORevision>>();
synchronized (revisionLists)
{
for (RevisionList list : revisionLists.values())
{
list.getAllRevisions(result);
}
}
return result;
}
public void getAllRevisions(List<InternalCDORevision> result)
{
synchronized (revisionLists)
{
for (RevisionList list : revisionLists.values())
{
list.getAllRevisions(result);
}
}
}
public List<CDORevision> getRevisions(CDOBranchPoint branchPoint)
{
CDOBranch branch = branchPoint.getBranch();
checkBranch(branch);
List<CDORevision> result = new ArrayList<CDORevision>();
synchronized (revisionLists)
{
for (Map.Entry<Object, RevisionList> entry : revisionLists.entrySet())
{
if (isKeyInBranch(entry.getKey(), branch))
{
RevisionList list = entry.getValue();
InternalCDORevision revision = list.getRevision(branchPoint.getTimeStamp());
if (revision != null)
{
result.add(revision);
}
}
}
}
return result;
}
public void addRevision(CDORevision revision)
{
CheckUtil.checkArg(revision, "revision");
CDOBranch branch = revision.getBranch();
checkBranch(branch);
CDOID id = revision.getID();
Object key = createKey(id, branch);
synchronized (revisionLists)
{
RevisionList list = revisionLists.get(key);
if (list == null)
{
list = new RevisionList();
revisionLists.put(key, list);
}
if (list.addRevision((InternalCDORevision)revision, createReference(revision)))
{
typeRefIncrease(id, revision.getEClass());
}
}
}
public InternalCDORevision removeRevision(CDOID id, CDOBranchVersion branchVersion)
{
CDOBranch branch = branchVersion.getBranch();
checkBranch(branch);
Object key = createKey(id, branch);
synchronized (revisionLists)
{
RevisionList list = revisionLists.get(key);
if (list != null)
{
list.removeRevision(branchVersion.getVersion());
if (list.isEmpty())
{
revisionLists.remove(key);
typeRefDecrease(id);
if (TRACER.isEnabled())
{
TRACER.format("Removed cache list of {0}", key); //$NON-NLS-1$
}
}
}
}
return null;
}
public void clear()
{
synchronized (revisionLists)
{
revisionLists.clear();
typeRefDispose();
}
}
protected void typeRefIncrease(CDOID id, EClass type)
{
// Do nothing
}
protected void typeRefDecrease(CDOID id)
{
// Do nothing
}
protected void typeRefDispose()
{
// Do nothing
}
protected Object createKey(CDOID id, CDOBranch branch)
{
return id;
}
protected boolean isKeyInBranch(Object key, CDOBranch branch)
{
return true;
}
protected RevisionList getRevisionList(CDOID id, CDOBranch branch)
{
Object key = createKey(id, branch);
synchronized (revisionLists)
{
return revisionLists.get(key);
}
}
/**
* @author Eike Stepper
*/
protected static final class RevisionList extends LinkedList<Reference<InternalCDORevision>>
{
private static final long serialVersionUID = 1L;
public RevisionList()
{
}
public synchronized InternalCDORevision getRevision(long timeStamp)
{
if (timeStamp == CDORevision.UNSPECIFIED_DATE)
{
Reference<InternalCDORevision> ref = isEmpty() ? null : getFirst();
if (ref != null)
{
InternalCDORevision revision = ref.get();
if (revision != null)
{
if (!revision.isHistorical())
{
return revision;
}
}
else
{
removeFirst();
}
}
return null;
}
for (Iterator<Reference<InternalCDORevision>> it = iterator(); it.hasNext();)
{
Reference<InternalCDORevision> ref = it.next();
InternalCDORevision revision = ref.get();
if (revision != null)
{
long created = revision.getTimeStamp();
if (created <= timeStamp)
{
long revised = revision.getRevised();
if (timeStamp <= revised || revised == CDORevision.UNSPECIFIED_DATE)
{
return revision;
}
break;
}
}
else
{
it.remove();
}
}
return null;
}
public synchronized InternalCDORevision getRevisionByVersion(int version)
{
for (Iterator<Reference<InternalCDORevision>> it = iterator(); it.hasNext();)
{
Reference<InternalCDORevision> ref = it.next();
InternalCDORevision revision = ref.get();
if (revision != null)
{
int v = revision.getVersion();
if (v == version)
{
return revision;
}
else if (v < version)
{
break;
}
}
else
{
it.remove();
}
}
return null;
}
public synchronized boolean addRevision(InternalCDORevision revision, Reference<InternalCDORevision> reference)
{
int version = revision.getVersion();
for (ListIterator<Reference<InternalCDORevision>> it = listIterator(); it.hasNext();)
{
Reference<InternalCDORevision> ref = it.next();
InternalCDORevision foundRevision = ref.get();
if (foundRevision != null)
{
CDORevisionKey key = (CDORevisionKey)ref;
int v = key.getVersion();
if (v == version)
{
return false;
}
if (v < version)
{
it.previous();
it.add(reference);
return true;
}
}
else
{
it.remove();
}
}
addLast(reference);
return true;
}
public synchronized void removeRevision(int version)
{
for (Iterator<Reference<InternalCDORevision>> it = iterator(); it.hasNext();)
{
Reference<InternalCDORevision> ref = it.next();
CDORevisionKey key = (CDORevisionKey)ref;
int v = key.getVersion();
if (v == version)
{
it.remove();
if (TRACER.isEnabled())
{
TRACER.format("Removed version {0} from cache list of {1}", version, key.getID()); //$NON-NLS-1$
}
break;
}
else if (v < version)
{
break;
}
}
}
@Override
public String toString()
{
StringBuffer buffer = new StringBuffer();
for (Iterator<Reference<InternalCDORevision>> it = iterator(); it.hasNext();)
{
Reference<InternalCDORevision> ref = it.next();
InternalCDORevision revision = ref.get();
if (buffer.length() == 0)
{
buffer.append("{");
}
else
{
buffer.append(", ");
}
buffer.append(revision);
}
buffer.append("}");
return buffer.toString();
}
public void getAllRevisions(Map<CDOBranch, List<CDORevision>> result)
{
for (Iterator<Reference<InternalCDORevision>> it = iterator(); it.hasNext();)
{
Reference<InternalCDORevision> ref = it.next();
InternalCDORevision revision = ref.get();
if (revision != null)
{
CDOBranch branch = revision.getBranch();
List<CDORevision> resultList = result.get(branch);
if (resultList == null)
{
resultList = new ArrayList<CDORevision>(1);
result.put(branch, resultList);
}
resultList.add(revision);
}
}
}
public void getAllRevisions(List<InternalCDORevision> result)
{
for (Iterator<Reference<InternalCDORevision>> it = iterator(); it.hasNext();)
{
Reference<InternalCDORevision> ref = it.next();
InternalCDORevision revision = ref.get();
if (revision != null)
{
result.add(revision);
}
}
}
}
}