Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java')
-rw-r--r--org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java1310
1 files changed, 1310 insertions, 0 deletions
diff --git a/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java b/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java
new file mode 100644
index 0000000000..96f26ac283
--- /dev/null
+++ b/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java
@@ -0,0 +1,1310 @@
+/**
+ * Copyright (c) 2004 - 2011 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:
+ * Simon McDuff - initial API and implementation
+ * Simon McDuff - bug 233273
+ * Eike Stepper - maintenance
+ * Andre Dietisheim - bug 256649
+ */
+package org.eclipse.emf.cdo.internal.server.mem;
+
+import org.eclipse.emf.cdo.common.CDOCommonRepository.IDGenerationLocation;
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.branch.CDOBranchHandler;
+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
+import org.eclipse.emf.cdo.common.branch.CDOBranchVersion;
+import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
+import org.eclipse.emf.cdo.common.commit.CDOCommitInfoHandler;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.id.CDOIDUtil;
+import org.eclipse.emf.cdo.common.lob.CDOLobHandler;
+import org.eclipse.emf.cdo.common.lock.CDOLockUtil;
+import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea.Handler;
+import org.eclipse.emf.cdo.common.model.CDOModelConstants;
+import org.eclipse.emf.cdo.common.protocol.CDODataInput;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+import org.eclipse.emf.cdo.common.util.CDOCommonUtil;
+import org.eclipse.emf.cdo.server.ISession;
+import org.eclipse.emf.cdo.server.IStoreAccessor;
+import org.eclipse.emf.cdo.server.IStoreAccessor.DurableLocking2;
+import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext;
+import org.eclipse.emf.cdo.server.ITransaction;
+import org.eclipse.emf.cdo.server.IView;
+import org.eclipse.emf.cdo.server.StoreThreadLocal;
+import org.eclipse.emf.cdo.server.mem.IMEMStore;
+import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch;
+import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranchManager;
+import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranchManager.BranchLoader;
+import org.eclipse.emf.cdo.spi.common.commit.CDOChangeSetSegment;
+import org.eclipse.emf.cdo.spi.common.commit.InternalCDOCommitInfoManager;
+import org.eclipse.emf.cdo.spi.common.revision.DetachedCDORevision;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+import org.eclipse.emf.cdo.spi.common.revision.SyntheticCDORevision;
+import org.eclipse.emf.cdo.spi.server.InternalLockManager;
+import org.eclipse.emf.cdo.spi.server.LongIDStore;
+import org.eclipse.emf.cdo.spi.server.StoreAccessorPool;
+
+import org.eclipse.net4j.util.HexUtil;
+import org.eclipse.net4j.util.ObjectUtil;
+import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump;
+import org.eclipse.net4j.util.collection.Pair;
+import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
+import org.eclipse.net4j.util.io.IOUtil;
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.CharArrayReader;
+import java.io.CharArrayWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * @author Simon McDuff
+ */
+public class MEMStore extends LongIDStore implements IMEMStore, BranchLoader, DurableLocking2
+{
+ public static final String TYPE = "mem"; //$NON-NLS-1$
+
+ private long creationTime;
+
+ private Map<String, String> properties = new HashMap<String, String>();
+
+ private Map<Integer, BranchInfo> branchInfos = new HashMap<Integer, BranchInfo>();
+
+ private int lastBranchID;
+
+ private int lastLocalBranchID;
+
+ private Map<Object, List<InternalCDORevision>> revisions = new HashMap<Object, List<InternalCDORevision>>();
+
+ private List<CommitInfo> commitInfos = new ArrayList<CommitInfo>();
+
+ private Map<CDOID, EClass> objectTypes = new HashMap<CDOID, EClass>();
+
+ private Map<String, LockArea> lockAreas = new HashMap<String, LockArea>();
+
+ private Map<String, Object> lobs = new HashMap<String, Object>();
+
+ private int listLimit;
+
+ @ExcludeFromDump
+ private transient EStructuralFeature resourceNameFeature;
+
+ /**
+ * @param listLimit
+ * See {@link #setListLimit(int)}.
+ * @since 2.0
+ */
+ public MEMStore(int listLimit)
+ {
+ super(TYPE, set(ChangeFormat.REVISION, ChangeFormat.DELTA), set(RevisionTemporality.NONE,
+ RevisionTemporality.AUDITING), set(RevisionParallelism.NONE, RevisionParallelism.BRANCHING));
+ setRevisionTemporality(RevisionTemporality.AUDITING);
+ setRevisionParallelism(RevisionParallelism.BRANCHING);
+ this.listLimit = listLimit;
+ }
+
+ public MEMStore()
+ {
+ this(UNLIMITED);
+ }
+
+ @Override
+ public CDOID createObjectID(String val)
+ {
+ if (getRepository().getIDGenerationLocation() == IDGenerationLocation.CLIENT)
+ {
+ byte[] decoded = CDOIDUtil.decodeUUID(val);
+ return CDOIDUtil.createUUID(decoded);
+ }
+
+ return super.createObjectID(val);
+ }
+
+ @Override
+ public boolean isLocal(CDOID id)
+ {
+ if (getRepository().getIDGenerationLocation() == IDGenerationLocation.CLIENT)
+ {
+ return false;
+ }
+
+ return super.isLocal(id);
+ }
+
+ @Override
+ public void ensureLastObjectID(CDOID id)
+ {
+ if (getRepository().getIDGenerationLocation() == IDGenerationLocation.CLIENT)
+ {
+ return;
+ }
+
+ super.ensureLastObjectID(id);
+ }
+
+ public synchronized Map<String, String> getPersistentProperties(Set<String> names)
+ {
+ if (names == null || names.isEmpty())
+ {
+ return new HashMap<String, String>(properties);
+ }
+
+ Map<String, String> result = new HashMap<String, String>();
+ for (String name : names)
+ {
+ String value = properties.get(name);
+ if (value != null)
+ {
+ result.put(name, value);
+ }
+ }
+
+ return result;
+ }
+
+ public synchronized void setPersistentProperties(Map<String, String> properties)
+ {
+ this.properties.putAll(properties);
+ }
+
+ public synchronized void removePersistentProperties(Set<String> names)
+ {
+ for (String name : names)
+ {
+ properties.remove(name);
+ }
+ }
+
+ public synchronized Pair<Integer, Long> createBranch(int branchID, BranchInfo branchInfo)
+ {
+ if (branchID == NEW_BRANCH)
+ {
+ branchID = ++lastBranchID;
+ }
+ else if (branchID == NEW_LOCAL_BRANCH)
+ {
+ branchID = --lastLocalBranchID;
+ }
+
+ branchInfos.put(branchID, branchInfo);
+ return new Pair<Integer, Long>(branchID, branchInfo.getBaseTimeStamp());
+ }
+
+ public synchronized BranchInfo loadBranch(int branchID)
+ {
+ return branchInfos.get(branchID);
+ }
+
+ public synchronized SubBranchInfo[] loadSubBranches(int branchID)
+ {
+ List<SubBranchInfo> result = new ArrayList<SubBranchInfo>();
+ for (Entry<Integer, BranchInfo> entry : branchInfos.entrySet())
+ {
+ BranchInfo branchInfo = entry.getValue();
+ if (branchInfo.getBaseBranchID() == branchID)
+ {
+ int id = entry.getKey();
+ result.add(new SubBranchInfo(id, branchInfo.getName(), branchInfo.getBaseTimeStamp()));
+ }
+ }
+
+ return result.toArray(new SubBranchInfo[result.size()]);
+ }
+
+ public synchronized int loadBranches(int startID, int endID, CDOBranchHandler handler)
+ {
+ int count = 0;
+ InternalCDOBranchManager branchManager = getRepository().getBranchManager();
+ for (Entry<Integer, BranchInfo> entry : branchInfos.entrySet())
+ {
+ int id = entry.getKey();
+ if (startID <= id && (id <= endID || endID == 0))
+ {
+ BranchInfo branchInfo = entry.getValue();
+ InternalCDOBranch branch = branchManager.getBranch(id, branchInfo);
+ handler.handleBranch(branch);
+ ++count;
+ }
+ }
+
+ return count;
+ }
+
+ public synchronized void loadCommitInfos(CDOBranch branch, long startTime, long endTime, CDOCommitInfoHandler handler)
+ {
+ InternalCDOCommitInfoManager manager = getRepository().getCommitInfoManager();
+ for (int i = 0; i < commitInfos.size(); i++)
+ {
+ CommitInfo info = commitInfos.get(i);
+ if (startTime != CDOBranchPoint.UNSPECIFIED_DATE && info.getTimeStamp() < startTime)
+ {
+ continue;
+ }
+
+ if (endTime != CDOBranchPoint.UNSPECIFIED_DATE && info.getTimeStamp() > endTime)
+ {
+ continue;
+ }
+
+ if (branch != null && !ObjectUtil.equals(info.getBranch(), branch))
+ {
+ continue;
+ }
+
+ info.handle(manager, handler);
+ }
+ }
+
+ public synchronized Set<CDOID> readChangeSet(CDOChangeSetSegment[] segments)
+ {
+ Set<CDOID> ids = new HashSet<CDOID>();
+ for (CDOChangeSetSegment segment : segments)
+ {
+ for (List<InternalCDORevision> list : revisions.values())
+ {
+ readChangeSet(segment, list, ids);
+ }
+ }
+
+ return ids;
+ }
+
+ private void readChangeSet(CDOChangeSetSegment segment, List<InternalCDORevision> list, Set<CDOID> ids)
+ {
+ long startTime = segment.getTimeStamp();
+ long endTime = segment.getEndTime();
+ boolean listCheckDone = false;
+ for (InternalCDORevision revision : list)
+ {
+ CDOID id = revision.getID();
+ if (!listCheckDone)
+ {
+ if (ids.contains(id))
+ {
+ return;
+ }
+
+ if (!ObjectUtil.equals(revision.getBranch(), segment.getBranch()))
+ {
+ return;
+ }
+
+ listCheckDone = true;
+ }
+
+ if (CDOCommonUtil.isValidTimeStamp(revision.getTimeStamp(), startTime, endTime))
+ {
+ ids.add(id);
+ }
+ }
+ }
+
+ public synchronized void handleRevisions(EClass eClass, CDOBranch branch, long timeStamp, boolean exactTime,
+ CDORevisionHandler handler)
+ {
+ for (List<InternalCDORevision> list : revisions.values())
+ {
+ for (InternalCDORevision revision : list)
+ {
+ if (!handleRevision(revision, eClass, branch, timeStamp, exactTime, handler))
+ {
+ return;
+ }
+ }
+ }
+ }
+
+ private boolean handleRevision(InternalCDORevision revision, EClass eClass, CDOBranch branch, long timeStamp,
+ boolean exactTime, CDORevisionHandler handler)
+ {
+ if (eClass != null && revision.getEClass() != eClass)
+ {
+ return true;
+ }
+
+ if (branch != null && !ObjectUtil.equals(revision.getBranch(), branch))
+ {
+ return true;
+ }
+
+ if (timeStamp != CDOBranchPoint.INVALID_DATE)
+ {
+ if (exactTime)
+ {
+ if (timeStamp != CDOBranchPoint.UNSPECIFIED_DATE && revision.getTimeStamp() != timeStamp)
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (!revision.isValid(timeStamp))
+ {
+ return true;
+ }
+ }
+ }
+
+ return handler.handleRevision(revision);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public int getListLimit()
+ {
+ return listLimit;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public synchronized void setListLimit(int listLimit)
+ {
+ if (listLimit != UNLIMITED && this.listLimit != listLimit)
+ {
+ for (List<InternalCDORevision> list : revisions.values())
+ {
+ enforceListLimit(list);
+ }
+ }
+
+ this.listLimit = listLimit;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public synchronized List<InternalCDORevision> getCurrentRevisions()
+ {
+ ArrayList<InternalCDORevision> simpleRevisions = new ArrayList<InternalCDORevision>();
+ Iterator<List<InternalCDORevision>> itr = revisions.values().iterator();
+ while (itr.hasNext())
+ {
+ List<InternalCDORevision> list = itr.next();
+ InternalCDORevision revision = list.get(list.size() - 1);
+ simpleRevisions.add(revision);
+ }
+
+ return simpleRevisions;
+ }
+
+ public synchronized InternalCDORevision getRevisionByVersion(CDOID id, CDOBranchVersion branchVersion)
+ {
+ Object listKey = getListKey(id, branchVersion.getBranch());
+ List<InternalCDORevision> list = revisions.get(listKey);
+ if (list == null)
+ {
+ return null;
+ }
+
+ return getRevisionByVersion(list, branchVersion.getVersion());
+ }
+
+ /**
+ * @since 2.0
+ */
+ public synchronized InternalCDORevision getRevision(CDOID id, CDOBranchPoint branchPoint)
+ {
+ Object listKey = getListKey(id, branchPoint.getBranch());
+ if (branchPoint.getTimeStamp() == CDORevision.UNSPECIFIED_DATE)
+ {
+ List<InternalCDORevision> list = revisions.get(listKey);
+ if (list == null)
+ {
+ return null;
+ }
+
+ return list.get(list.size() - 1);
+ }
+
+ if (!getRepository().isSupportingAudits())
+ {
+ throw new UnsupportedOperationException("Auditing not supported");
+ }
+
+ List<InternalCDORevision> list = revisions.get(listKey);
+ if (list == null)
+ {
+ return null;
+ }
+
+ return getRevision(list, branchPoint);
+ }
+
+ public synchronized void addRevision(InternalCDORevision revision, boolean raw)
+ {
+ Object listKey = getListKey(revision.getID(), revision.getBranch());
+ List<InternalCDORevision> list = revisions.get(listKey);
+ if (list == null)
+ {
+ list = new ArrayList<InternalCDORevision>();
+ revisions.put(listKey, list);
+ }
+
+ addRevision(list, revision, raw);
+
+ if (raw)
+ {
+ ensureLastObjectID(revision.getID());
+ }
+ }
+
+ public synchronized void addCommitInfo(CDOBranch branch, long timeStamp, long previousTimeStamp, String userID,
+ String comment)
+ {
+ int index = commitInfos.size() - 1;
+ while (index >= 0)
+ {
+ CommitInfo info = commitInfos.get(index);
+ if (timeStamp > info.getTimeStamp())
+ {
+ break;
+ }
+
+ --index;
+ }
+
+ CommitInfo commitInfo = new CommitInfo(branch, timeStamp, previousTimeStamp, userID, comment);
+ commitInfos.add(index + 1, commitInfo);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public synchronized boolean rollbackRevision(InternalCDORevision revision)
+ {
+ CDOID id = revision.getID();
+ CDOBranch branch = revision.getBranch();
+ int version = revision.getVersion();
+
+ Object listKey = getListKey(id, branch);
+ List<InternalCDORevision> list = revisions.get(listKey);
+ if (list == null)
+ {
+ return false;
+ }
+
+ for (Iterator<InternalCDORevision> it = list.iterator(); it.hasNext();)
+ {
+ InternalCDORevision rev = it.next();
+ if (rev.getVersion() == version)
+ {
+ it.remove();
+ return true;
+ }
+ else if (rev.getVersion() == version - 1)
+ {
+ rev.setRevised(CDORevision.UNSPECIFIED_DATE);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @since 3.0
+ */
+ public synchronized DetachedCDORevision detachObject(CDOID id, CDOBranch branch, long timeStamp)
+ {
+ Object listKey = getListKey(id, branch);
+ List<InternalCDORevision> list = revisions.get(listKey);
+ if (list != null)
+ {
+ InternalCDORevision revision = getRevision(list, branch.getHead());
+ if (revision != null)
+ {
+ revision.setRevised(timeStamp - 1);
+ }
+ }
+
+ int version;
+ if (list == null)
+ {
+ list = new ArrayList<InternalCDORevision>();
+ revisions.put(listKey, list);
+ version = CDOBranchVersion.FIRST_VERSION;
+ }
+ else
+ {
+ version = getHighestVersion(list) + 1;
+ }
+
+ EClass eClass = getObjectType(id);
+ DetachedCDORevision detached = new DetachedCDORevision(eClass, id, branch, version, timeStamp);
+ addRevision(list, detached, false);
+ return detached;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public synchronized void queryResources(IStoreAccessor.QueryResourcesContext context)
+ {
+ CDOID folderID = context.getFolderID();
+ String name = context.getName();
+ boolean exactMatch = context.exactMatch();
+ for (Entry<Object, List<InternalCDORevision>> entry : revisions.entrySet())
+ {
+ CDOBranch branch = getBranch(entry.getKey());
+ if (!ObjectUtil.equals(branch, context.getBranch()))
+ {
+ continue;
+ }
+
+ List<InternalCDORevision> list = entry.getValue();
+ if (list.isEmpty())
+ {
+ continue;
+ }
+
+ InternalCDORevision revision = list.get(0);
+ if (revision instanceof SyntheticCDORevision)
+ {
+ continue;
+ }
+
+ if (!revision.isResourceNode())
+ {
+ continue;
+ }
+
+ revision = getRevision(list, context);
+ if (revision == null || revision instanceof DetachedCDORevision)
+ {
+ continue;
+ }
+
+ CDOID revisionFolder = (CDOID)revision.data().getContainerID();
+ if (!CDOIDUtil.equals(revisionFolder, folderID))
+ {
+ continue;
+ }
+
+ String revisionName = (String)revision.data().get(resourceNameFeature, 0);
+ boolean useEquals = exactMatch || revisionName == null || name == null;
+ boolean match = useEquals ? ObjectUtil.equals(revisionName, name) : revisionName.startsWith(name);
+
+ if (match)
+ {
+ if (!context.addResource(revision.getID()))
+ {
+ // No more results allowed
+ break;
+ }
+ }
+ }
+ }
+
+ public synchronized void queryXRefs(QueryXRefsContext context)
+ {
+ Set<CDOID> targetIDs = context.getTargetObjects().keySet();
+ Map<EClass, List<EReference>> sourceCandidates = context.getSourceCandidates();
+
+ for (Entry<Object, List<InternalCDORevision>> entry : revisions.entrySet())
+ {
+ CDOBranch branch = getBranch(entry.getKey());
+ if (!ObjectUtil.equals(branch, context.getBranch()))
+ {
+ continue;
+ }
+
+ List<InternalCDORevision> list = entry.getValue();
+ if (list.isEmpty())
+ {
+ continue;
+ }
+
+ InternalCDORevision revision = getRevision(list, context);
+ if (revision == null || revision instanceof SyntheticCDORevision)
+ {
+ continue;
+ }
+
+ EClass eClass = revision.getEClass();
+ CDOID sourceID = revision.getID();
+
+ List<EReference> eReferences = sourceCandidates.get(eClass);
+ if (eReferences != null)
+ {
+ for (EReference eReference : eReferences)
+ {
+ Object value = revision.getValue(eReference);
+ if (value != null)
+ {
+ if (eReference.isMany())
+ {
+ @SuppressWarnings("unchecked")
+ List<CDOID> ids = (List<CDOID>)value;
+ int index = 0;
+ for (CDOID id : ids)
+ {
+ if (!queryXRefs(context, targetIDs, id, sourceID, eReference, index++))
+ {
+ return;
+ }
+ }
+ }
+ else
+ {
+ CDOID id = (CDOID)value;
+ if (!queryXRefs(context, targetIDs, id, sourceID, eReference, 0))
+ {
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private boolean queryXRefs(QueryXRefsContext context, Set<CDOID> targetIDs, CDOID targetID, CDOID sourceID,
+ EReference sourceReference, int index)
+ {
+ for (CDOID id : targetIDs)
+ {
+ if (id.equals(targetID))
+ {
+ if (!context.addXRef(targetID, sourceID, sourceReference, index))
+ {
+ // No more results allowed
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public synchronized void rawExport(CDODataOutput out, int fromBranchID, int toBranchID, long fromCommitTime,
+ long toCommitTime)
+ {
+ // TODO: implement MEMStore.rawExport(out, fromBranchID, toBranchID, fromCommitTime, toCommitTime)
+ throw new UnsupportedOperationException();
+ }
+
+ public synchronized void rawImport(CDODataInput in, int fromBranchID, int toBranchID, long fromCommitTime,
+ long toCommitTime, OMMonitor monitor)
+ {
+ // TODO: implement MEMStore.rawImport(in, fromBranchID, toBranchID, fromCommitTime, toCommitTime, monitor)
+ throw new UnsupportedOperationException();
+ }
+
+ public synchronized void rawDelete(CDOID id, int version, CDOBranch branch)
+ {
+ Object listKey = getListKey(id, branch);
+ List<InternalCDORevision> list = revisions.get(listKey);
+ if (list != null)
+ {
+ for (Iterator<InternalCDORevision> it = list.iterator(); it.hasNext();)
+ {
+ InternalCDORevision rev = it.next();
+ if (rev.getVersion() == version)
+ {
+ it.remove();
+ break;
+ }
+ }
+ }
+ }
+
+ public synchronized LockArea createLockArea(String userID, CDOBranchPoint branchPoint, boolean readOnly,
+ Map<CDOID, LockGrade> locks)
+ {
+ return createLockArea(null, userID, branchPoint, readOnly, locks);
+ }
+
+ public synchronized LockArea createLockArea(String durableLockingID, String userID, CDOBranchPoint branchPoint,
+ boolean readOnly, Map<CDOID, LockGrade> locks)
+ {
+ if (durableLockingID != null)
+ {
+ // If the caller is specifying the ID, make sure there is no area with this ID yet
+ if (lockAreas.containsKey(durableLockingID))
+ {
+ throw new LockAreaAlreadyExistsException(durableLockingID);
+ }
+ }
+ else
+ {
+ do
+ {
+ durableLockingID = CDOLockUtil.createDurableLockingID();
+ } while (lockAreas.containsKey(durableLockingID));
+ }
+
+ LockArea area = CDOLockUtil.createLockArea(durableLockingID, userID, branchPoint, readOnly, locks);
+ lockAreas.put(durableLockingID, area);
+ return area;
+ }
+
+ public synchronized void updateLockArea(LockArea lockArea)
+ {
+ String durableLockingID = lockArea.getDurableLockingID();
+ lockAreas.put(durableLockingID, lockArea);
+ }
+
+ public synchronized LockArea getLockArea(String durableLockingID) throws LockAreaNotFoundException
+ {
+ LockArea area = lockAreas.get(durableLockingID);
+ if (area == null)
+ {
+ throw new LockAreaNotFoundException(durableLockingID);
+ }
+
+ return area;
+ }
+
+ public synchronized void getLockAreas(String userIDPrefix, Handler handler)
+ {
+ for (LockArea area : lockAreas.values())
+ {
+ String userID = area.getUserID();
+ if (userID == null || userID.startsWith(userIDPrefix))
+ {
+ if (!handler.handleLockArea(area))
+ {
+ return;
+ }
+ }
+ }
+ }
+
+ public synchronized void deleteLockArea(String durableLockingID)
+ {
+ lockAreas.remove(durableLockingID);
+ }
+
+ public synchronized void lock(String durableLockingID, LockType type, Collection<? extends Object> objectsToLock)
+ {
+ LockArea area = getLockArea(durableLockingID);
+ Map<CDOID, LockGrade> locks = area.getLocks();
+
+ InternalLockManager lockManager = getRepository().getLockManager();
+ for (Object objectToLock : objectsToLock)
+ {
+ CDOID id = lockManager.getLockKeyID(objectToLock);
+ LockGrade grade = locks.get(id);
+ if (grade != null)
+ {
+ grade = grade.getUpdated(type, true);
+ }
+ else
+ {
+ grade = LockGrade.get(type);
+ }
+
+ locks.put(id, grade);
+ }
+ }
+
+ public synchronized void unlock(String durableLockingID, LockType type, Collection<? extends Object> objectsToUnlock)
+ {
+ LockArea area = getLockArea(durableLockingID);
+ Map<CDOID, LockGrade> locks = area.getLocks();
+
+ InternalLockManager lockManager = getRepository().getLockManager();
+ for (Object objectToUnlock : objectsToUnlock)
+ {
+ CDOID id = lockManager.getLockKeyID(objectToUnlock);
+ LockGrade grade = locks.get(id);
+ if (grade != null)
+ {
+ grade = grade.getUpdated(type, false);
+ if (grade == LockGrade.NONE)
+ {
+ locks.remove(id);
+ }
+ }
+ }
+ }
+
+ public synchronized void unlock(String durableLockingID)
+ {
+ LockArea area = getLockArea(durableLockingID);
+ Map<CDOID, LockGrade> locks = area.getLocks();
+ locks.clear();
+ }
+
+ public synchronized void queryLobs(List<byte[]> ids)
+ {
+ for (Iterator<byte[]> it = ids.iterator(); it.hasNext();)
+ {
+ byte[] id = it.next();
+ String key = HexUtil.bytesToHex(id);
+ if (!lobs.containsKey(key))
+ {
+ it.remove();
+ }
+ }
+ }
+
+ public void handleLobs(long fromTime, long toTime, CDOLobHandler handler) throws IOException
+ {
+ for (Entry<String, Object> entry : lobs.entrySet())
+ {
+ byte[] id = HexUtil.hexToBytes(entry.getKey());
+ Object lob = entry.getValue();
+ if (lob instanceof byte[])
+ {
+ byte[] blob = (byte[])lob;
+ ByteArrayInputStream in = new ByteArrayInputStream(blob);
+ OutputStream out = handler.handleBlob(id, blob.length);
+ if (out != null)
+ {
+ try
+ {
+ IOUtil.copyBinary(in, out, blob.length);
+ }
+ finally
+ {
+ IOUtil.close(out);
+ }
+ }
+ }
+ else
+ {
+ char[] clob = (char[])lob;
+ CharArrayReader in = new CharArrayReader(clob);
+ Writer out = handler.handleClob(id, clob.length);
+ if (out != null)
+ {
+ try
+ {
+ IOUtil.copyCharacter(in, out, clob.length);
+ }
+ finally
+ {
+ IOUtil.close(out);
+ }
+ }
+ }
+ }
+ }
+
+ public synchronized void loadLob(byte[] id, OutputStream out) throws IOException
+ {
+ String key = HexUtil.bytesToHex(id);
+ Object lob = lobs.get(key);
+ if (lob == null)
+ {
+ throw new IOException("Lob not found: " + key);
+ }
+
+ if (lob instanceof byte[])
+ {
+ byte[] blob = (byte[])lob;
+ ByteArrayInputStream in = new ByteArrayInputStream(blob);
+ IOUtil.copyBinary(in, out, blob.length);
+ }
+ else
+ {
+ char[] clob = (char[])lob;
+ CharArrayReader in = new CharArrayReader(clob);
+ IOUtil.copyCharacter(in, new OutputStreamWriter(out), clob.length);
+ }
+ }
+
+ public synchronized void writeBlob(byte[] id, long size, InputStream inputStream) throws IOException
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ IOUtil.copyBinary(inputStream, out, size);
+ lobs.put(HexUtil.bytesToHex(id), out.toByteArray());
+ }
+
+ public synchronized void writeClob(byte[] id, long size, Reader reader) throws IOException
+ {
+ CharArrayWriter out = new CharArrayWriter();
+ IOUtil.copyCharacter(reader, out, size);
+ lobs.put(HexUtil.bytesToHex(id), out.toCharArray());
+ }
+
+ @Override
+ public MEMStoreAccessor createReader(ISession session)
+ {
+ return new MEMStoreAccessor(this, session);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public MEMStoreAccessor createWriter(ITransaction transaction)
+ {
+ return new MEMStoreAccessor(this, transaction);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public long getCreationTime()
+ {
+ return creationTime;
+ }
+
+ public void setCreationTime(long creationTime)
+ {
+ this.creationTime = creationTime;
+ }
+
+ public boolean isFirstStart()
+ {
+ return true;
+ }
+
+ public synchronized Map<CDOBranch, List<CDORevision>> getAllRevisions()
+ {
+ Map<CDOBranch, List<CDORevision>> result = new HashMap<CDOBranch, List<CDORevision>>();
+ InternalCDOBranchManager branchManager = getRepository().getBranchManager();
+ result.put(branchManager.getMainBranch(), new ArrayList<CDORevision>());
+
+ for (Integer branchID : branchInfos.keySet())
+ {
+ InternalCDOBranch branch = branchManager.getBranch(branchID);
+ result.put(branch, new ArrayList<CDORevision>());
+ }
+
+ for (List<InternalCDORevision> list : revisions.values())
+ {
+ for (InternalCDORevision revision : list)
+ {
+ CDOBranch branch = revision.getBranch();
+ List<CDORevision> resultList = result.get(branch);
+ resultList.add(revision);
+ }
+ }
+
+ return result;
+ }
+
+ public synchronized EClass getObjectType(CDOID id)
+ {
+ return objectTypes.get(id);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ protected void doActivate() throws Exception
+ {
+ super.doActivate();
+ creationTime = getRepository().getTimeStamp();
+
+ if (getRepository().getIDGenerationLocation() == IDGenerationLocation.CLIENT)
+ {
+ setObjectIDTypes(Collections.singleton(CDOID.ObjectType.UUID));
+ }
+ }
+
+ @Override
+ protected void doDeactivate() throws Exception
+ {
+ revisions.clear();
+ branchInfos.clear();
+ commitInfos.clear();
+ objectTypes.clear();
+ properties.clear();
+ resourceNameFeature = null;
+ lastBranchID = 0;
+ lastLocalBranchID = 0;
+ super.doDeactivate();
+ }
+
+ @Override
+ protected StoreAccessorPool getReaderPool(ISession session, boolean forReleasing)
+ {
+ // Pooling of store accessors not supported
+ return null;
+ }
+
+ @Override
+ protected StoreAccessorPool getWriterPool(IView view, boolean forReleasing)
+ {
+ // Pooling of store accessors not supported
+ return null;
+ }
+
+ private Object getListKey(CDOID id, CDOBranch branch)
+ {
+ if (getRevisionParallelism() == RevisionParallelism.NONE)
+ {
+ return id;
+ }
+
+ return new ListKey(id, branch);
+ }
+
+ private CDOBranch getBranch(Object key)
+ {
+ if (key instanceof ListKey)
+ {
+ return ((ListKey)key).getBranch();
+ }
+
+ return getRepository().getBranchManager().getMainBranch();
+ }
+
+ private int getHighestVersion(List<InternalCDORevision> list)
+ {
+ int version = CDOBranchVersion.UNSPECIFIED_VERSION;
+ for (InternalCDORevision revision : list)
+ {
+ if (revision.getVersion() > version)
+ {
+ version = revision.getVersion();
+ }
+ }
+
+ return version;
+ }
+
+ private InternalCDORevision getRevisionByVersion(List<InternalCDORevision> list, int version)
+ {
+ for (InternalCDORevision revision : list)
+ {
+ if (revision.getVersion() == version)
+ {
+ return revision;
+ }
+ }
+
+ return null;
+ }
+
+ private InternalCDORevision getRevision(List<InternalCDORevision> list, CDOBranchPoint branchPoint)
+ {
+ long timeStamp = branchPoint.getTimeStamp();
+ for (InternalCDORevision revision : list)
+ {
+ if (timeStamp == CDORevision.UNSPECIFIED_DATE)
+ {
+ if (!revision.isHistorical())
+ {
+ return revision;
+ }
+ }
+ else
+ {
+ if (revision.isValid(timeStamp))
+ {
+ return revision;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private void addRevision(List<InternalCDORevision> list, InternalCDORevision revision, boolean raw)
+ {
+ boolean resource = !(revision instanceof SyntheticCDORevision) && revision.isResource();
+ if (resource && resourceNameFeature == null)
+ {
+ resourceNameFeature = revision.getEClass().getEStructuralFeature(CDOModelConstants.RESOURCE_NODE_NAME_ATTRIBUTE);
+ }
+
+ if (!raw)
+ {
+ // Check version conflict
+ int version = revision.getVersion();
+ InternalCDORevision rev = getRevisionByVersion(list, version);
+ if (rev != null)
+ {
+ rev = getRevisionByVersion(list, version);
+ throw new IllegalStateException("Concurrent modification of " + rev.getEClass().getName() + "@" + rev.getID());
+ }
+
+ // Revise old revision
+ int oldVersion = version - 1;
+ if (oldVersion >= CDORevision.UNSPECIFIED_VERSION)
+ {
+ InternalCDORevision oldRevision = getRevisionByVersion(list, oldVersion);
+ if (oldRevision != null)
+ {
+ if (getRepository().isSupportingAudits())
+ {
+ oldRevision.setRevised(revision.getTimeStamp() - 1);
+ }
+ else
+ {
+ list.remove(oldRevision);
+ }
+ }
+ }
+
+ // Check duplicate resource
+ if (resource)
+ {
+ checkDuplicateResource(revision);
+ }
+ }
+
+ // Adjust the list
+ list.add(revision);
+ if (listLimit != UNLIMITED)
+ {
+ enforceListLimit(list);
+ }
+
+ CDOID id = revision.getID();
+ if (!objectTypes.containsKey(id))
+ {
+ objectTypes.put(id, revision.getEClass());
+ }
+ }
+
+ private void checkDuplicateResource(InternalCDORevision revision)
+ {
+ CDOID revisionFolder = (CDOID)revision.data().getContainerID();
+ String revisionName = (String)revision.data().get(resourceNameFeature, 0);
+
+ IStoreAccessor accessor = StoreThreadLocal.getAccessor();
+
+ CDOID resourceID = accessor.readResourceID(revisionFolder, revisionName, revision);
+ if (!CDOIDUtil.isNull(resourceID))
+ {
+ throw new IllegalStateException("Duplicate resource: name=" + revisionName + ", folderID=" + revisionFolder); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ private void enforceListLimit(List<InternalCDORevision> list)
+ {
+ while (list.size() > listLimit)
+ {
+ list.remove(0);
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private static final class ListKey
+ {
+ private CDOID id;
+
+ private CDOBranch branch;
+
+ public ListKey(CDOID id, CDOBranch branch)
+ {
+ this.id = id;
+ this.branch = branch;
+ }
+
+ public CDOID getID()
+ {
+ return id;
+ }
+
+ public CDOBranch getBranch()
+ {
+ return branch;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return id.hashCode() ^ branch.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (obj instanceof ListKey)
+ {
+ ListKey that = (ListKey)obj;
+ return ObjectUtil.equals(id, that.getID()) && ObjectUtil.equals(branch, that.getBranch());
+ }
+
+ return false;
+ }
+
+ @Override
+ public String toString()
+ {
+ return MessageFormat.format("{0}:{1}", id, branch.getID());
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private static final class CommitInfo
+ {
+ private CDOBranch branch;
+
+ private long timeStamp;
+
+ private long previousTimeStamp;
+
+ private String userID;
+
+ private String comment;
+
+ public CommitInfo(CDOBranch branch, long timeStamp, long previousTimeStamp, String userID, String comment)
+ {
+ this.branch = branch;
+ this.timeStamp = timeStamp;
+ this.previousTimeStamp = previousTimeStamp;
+ this.userID = userID;
+ this.comment = comment;
+ }
+
+ public CDOBranch getBranch()
+ {
+ return branch;
+ }
+
+ public long getTimeStamp()
+ {
+ return timeStamp;
+ }
+
+ public void handle(InternalCDOCommitInfoManager manager, CDOCommitInfoHandler handler)
+ {
+ CDOCommitInfo commitInfo = manager.createCommitInfo(branch, timeStamp, previousTimeStamp, userID, comment, null);
+ handler.handleCommitInfo(commitInfo);
+ }
+
+ @Override
+ public String toString()
+ {
+ return MessageFormat.format("CommitInfo[{0}, {1}, {2}, {3}, {4}]", branch, timeStamp, previousTimeStamp, userID,
+ comment);
+ }
+ }
+}

Back to the top