| /* |
| * 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); |
| } |
| } |
| } |
| } |
| } |