blob: 407f50c409ad22d4d75b708cf3c67650e3cb3058 [file] [log] [blame]
/**
* 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:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.emf.cdo.spi.server;
import org.eclipse.emf.cdo.common.CDOCommonView;
import org.eclipse.emf.cdo.common.branch.CDOBranch;
import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOID.ObjectType;
import org.eclipse.emf.cdo.common.id.CDOIDUtil;
import org.eclipse.emf.cdo.common.revision.CDORevisionFactory;
import org.eclipse.emf.cdo.internal.server.Repository;
import org.eclipse.emf.cdo.server.IRepository;
import org.eclipse.emf.cdo.server.ISession;
import org.eclipse.emf.cdo.server.ISessionManager;
import org.eclipse.emf.cdo.server.IStoreAccessor;
import org.eclipse.emf.cdo.server.ITransaction;
import org.eclipse.emf.cdo.server.IView;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump;
import org.eclipse.net4j.util.StringUtil;
import org.eclipse.net4j.util.container.IContainerDelta.Kind;
import org.eclipse.net4j.util.lifecycle.Lifecycle;
import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
import org.eclipse.net4j.util.om.monitor.ProgressDistributor;
import org.eclipse.emf.ecore.EClass;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* @author Eike Stepper
* @since 2.0
*/
public abstract class Store extends Lifecycle implements InternalStore
{
/**
* @since 3.0
* @deprecated Use CDOBranchPoint.UNSPECIFIED_DATE
*/
@Deprecated
public static final long UNSPECIFIED_DATE = CDOBranchPoint.UNSPECIFIED_DATE;
private String type;
private Set<ObjectType> objectIDTypes;
private Set<ChangeFormat> supportedChangeFormats;
private Set<RevisionTemporality> supportedRevisionTemporalities;
private Set<RevisionParallelism> supportedRevisionParallelisms;
private RevisionTemporality revisionTemporality = RevisionTemporality.NONE;
private RevisionParallelism revisionParallelism = RevisionParallelism.NONE;
private InternalRepository repository;
private boolean dropAllDataOnActivate;
/**
* Is protected against concurrent thread access through {@link Repository#createBranchLock}.
*/
@ExcludeFromDump
private transient int lastBranchID;
/**
* Is protected against concurrent thread access through {@link Repository#createBranchLock}.
*/
@ExcludeFromDump
private transient int lastLocalBranchID;
@ExcludeFromDump
private transient long lastCommitTime;
@ExcludeFromDump
private transient Object lastCommitTimeLock = new Object();
@ExcludeFromDump
private transient long lastNonLocalCommitTime;
@ExcludeFromDump
private transient Object lastNonLocalCommitTimeLock = new Object();
/**
* @since 3.0
*/
@ExcludeFromDump
private transient ProgressDistributor indicatingCommitDistributor = new ProgressDistributor.Geometric()
{
@Override
public String toString()
{
String result = "indicatingCommitDistributor"; //$NON-NLS-1$
if (repository != null)
{
result += ": " + repository.getName(); //$NON-NLS-1$
}
return result;
}
};
/**
* @since 3.0
*/
public Store(String type, Set<CDOID.ObjectType> objectIDTypes, Set<ChangeFormat> supportedChangeFormats,
Set<RevisionTemporality> supportedRevisionTemporalities, Set<RevisionParallelism> supportedRevisionParallelisms)
{
checkArg(!StringUtil.isEmpty(type), "Empty type"); //$NON-NLS-1$
this.type = type;
this.objectIDTypes = objectIDTypes;
checkArg(supportedChangeFormats != null && !supportedChangeFormats.isEmpty(), "Empty supportedChangeFormats"); //$NON-NLS-1$
this.supportedChangeFormats = supportedChangeFormats;
checkArg(supportedRevisionTemporalities != null && !supportedRevisionTemporalities.isEmpty(),
"Empty supportedRevisionTemporalities"); //$NON-NLS-1$
this.supportedRevisionTemporalities = supportedRevisionTemporalities;
checkArg(supportedRevisionParallelisms != null && !supportedRevisionParallelisms.isEmpty(),
"Empty supportedRevisionParallelisms"); //$NON-NLS-1$
this.supportedRevisionParallelisms = supportedRevisionParallelisms;
}
public final String getType()
{
return type;
}
/**
* @since 3.0
*/
public Set<CDOID.ObjectType> getObjectIDTypes()
{
return objectIDTypes;
}
/**
* @since 4.0
*/
protected void setObjectIDTypes(Set<ObjectType> objectIDTypes)
{
this.objectIDTypes = objectIDTypes;
}
public Set<ChangeFormat> getSupportedChangeFormats()
{
return supportedChangeFormats;
}
public Set<RevisionTemporality> getSupportedRevisionTemporalities()
{
return supportedRevisionTemporalities;
}
public final Set<RevisionParallelism> getSupportedRevisionParallelisms()
{
return supportedRevisionParallelisms;
}
public RevisionTemporality getRevisionTemporality()
{
return revisionTemporality;
}
public void setRevisionTemporality(RevisionTemporality revisionTemporality)
{
checkInactive();
checkState(supportedRevisionTemporalities.contains(revisionTemporality), "Revision temporality not supported: " //$NON-NLS-1$
+ revisionTemporality);
this.revisionTemporality = revisionTemporality;
}
public RevisionParallelism getRevisionParallelism()
{
return revisionParallelism;
}
public void setRevisionParallelism(RevisionParallelism revisionParallelism)
{
checkInactive();
checkState(supportedRevisionParallelisms.contains(revisionParallelism), "Revision parallelism not supported: " //$NON-NLS-1$
+ revisionParallelism);
this.revisionParallelism = revisionParallelism;
}
/**
* @since 3.0
*/
public InternalRepository getRepository()
{
return repository;
}
public void setRepository(IRepository repository)
{
this.repository = (InternalRepository)repository;
}
/**
* @since 4.0
*/
public boolean isDropAllDataOnActivate()
{
return dropAllDataOnActivate;
}
/**
* @since 4.0
*/
public void setDropAllDataOnActivate(boolean dropAllDataOnActivate)
{
this.dropAllDataOnActivate = dropAllDataOnActivate;
}
/**
* @since 3.0
*/
public int getLastBranchID()
{
return lastBranchID;
}
/**
* @since 3.0
*/
public void setLastBranchID(int lastBranchID)
{
this.lastBranchID = lastBranchID;
}
/**
* @since 3.0
*/
public int getNextBranchID()
{
return ++lastBranchID;
}
/**
* @since 3.0
*/
public int getLastLocalBranchID()
{
return lastLocalBranchID;
}
/**
* @since 3.0
*/
public void setLastLocalBranchID(int lastLocalBranchID)
{
this.lastLocalBranchID = lastLocalBranchID;
}
/**
* @since 3.0
*/
public int getNextLocalBranchID()
{
return --lastLocalBranchID;
}
/**
* @since 3.0
*/
public long getLastCommitTime()
{
synchronized (lastCommitTimeLock)
{
return lastCommitTime;
}
}
/**
* @since 3.0
*/
public void setLastCommitTime(long lastCommitTime)
{
synchronized (lastCommitTimeLock)
{
if (this.lastCommitTime < lastCommitTime)
{
this.lastCommitTime = lastCommitTime;
}
}
}
/**
* @since 3.0
*/
public long getLastNonLocalCommitTime()
{
synchronized (lastNonLocalCommitTimeLock)
{
return lastNonLocalCommitTime;
}
}
/**
* @since 3.0
*/
public void setLastNonLocalCommitTime(long lastNonLocalCommitTime)
{
synchronized (lastNonLocalCommitTimeLock)
{
if (this.lastNonLocalCommitTime < lastNonLocalCommitTime)
{
this.lastNonLocalCommitTime = lastNonLocalCommitTime;
}
}
}
public IStoreAccessor getReader(ISession session)
{
IStoreAccessor reader = null;
StoreAccessorPool pool = getReaderPool(session, false);
if (pool != null)
{
reader = pool.removeStoreAccessor(session);
}
if (reader == null && session != null)
{
CDOCommonView[] views = session.getViews();
for (CDOCommonView view : views)
{
pool = getWriterPool((IView)view, false);
if (pool != null)
{
reader = pool.removeStoreAccessor(view);
if (reader != null)
{
break;
}
}
}
}
if (reader == null)
{
reader = createReader(session);
LifecycleUtil.activate(reader);
}
return reader;
}
public IStoreAccessor getWriter(ITransaction transaction)
{
IStoreAccessor writer = null;
StoreAccessorPool pool = getWriterPool(transaction, false);
if (pool != null)
{
writer = pool.removeStoreAccessor(transaction);
}
if (writer == null)
{
writer = createWriter(transaction);
LifecycleUtil.activate(writer);
}
return writer;
}
public ProgressDistributor getIndicatingCommitDistributor()
{
return indicatingCommitDistributor;
}
/**
* @since 3.0
*/
public InternalCDORevision createRevision(EClass eClass, CDOID id)
{
CDORevisionFactory factory = repository.getRevisionManager().getFactory();
InternalCDORevision revision = (InternalCDORevision)factory.createRevision(eClass);
revision.setID(id);
return revision;
}
/**
* @since 4.0
*/
protected void releaseAccessor(StoreAccessorBase accessor)
{
StoreAccessorPool pool = null;
if (accessor.isReader())
{
pool = getReaderPool(accessor.getSession(), true);
}
else
{
pool = getWriterPool(accessor.getTransaction(), true);
}
if (pool != null)
{
pool.addStoreAccessor(accessor);
}
else
{
accessor.deactivate();
}
}
/**
* Returns a {@link StoreAccessorPool pool} that may contain {@link IStoreAccessor} instances that are compatible with
* the given session. The implementor may return <code>null</code> to indicate that no pooling occurs. It's also left
* to the implementors choice how to determine the appropriate pool instance to be used for the given session, for
* example it could always return the same pool instance, regardless of the given session.
* <p>
* If the implementor of this method decides to create pools that are only compatible with certain sessions or views,
* then it is his responsibility to listen to {@link Kind#REMOVED REMOVED} events sent by either the
* {@link ISessionManager} (indicating that a session is closed) or any of its sessions (indicating that a view is
* closed). <b>Note:</b> Closing a session <em>implies</em> that all contained views are closed sliently without
* firing respective events!
*
* @param session
* The context which the pool must be compatible with. Must not be <code>null</code>.
* @param forReleasing
* Enables lazy pool creation. The implementor is not supposed to create a new pool if <code>false</code> is
* passed. If <code>true</code> is passed it's up to the implementor whether to create a new pool or not.
*/
protected abstract StoreAccessorPool getReaderPool(ISession session, boolean forReleasing);
/**
* Returns a {@link StoreAccessorPool pool} that may contain {@link IStoreAccessor} instances that are compatible with
* the given session. The implementor may return <code>null</code> to indicate that no pooling occurs. It's also left
* to the implementors choice how to determine the appropriate pool instance to be used for the given session, for
* example it could always return the same pool instance, regardless of the given session.
* <p>
* If the implementor of this method decides to create pools that are only compatible with certain sessions or views,
* then it is his responsibility to listen to {@link Kind#REMOVED REMOVED} events sent by either the
* {@link ISessionManager} (indicating that a session is closed) or any of its sessions (indicating that a view is
* closed). <b>Note:</b> Closing a session <em>implies</em> that all contained views are closed sliently without
* firing respective events!
*
* @param view
* The context which the pool must be compatible with. Must not be <code>null</code>.
* @param forReleasing
* Enables lazy pool creation. The implementor is not supposed to create a new pool if <code>false</code> is
* passed. If <code>true</code> is passed it's up to the implementor whether to create a new pool or not.
*/
protected abstract StoreAccessorPool getWriterPool(IView view, boolean forReleasing);
/**
* Creates and returns a <b>new</b> {@link IStoreAccessor} instance. The caller of this method is responsible for
* {@link Lifecycle#activate() activating} the new instance.
*/
protected abstract IStoreAccessor createReader(ISession session);
/**
* Creates and returns a <b>new</b> {@link IStoreAccessor} instance. The caller of this method is responsible for
* {@link Lifecycle#activate() activating} the new instance.
*/
protected abstract IStoreAccessor createWriter(ITransaction transaction);
protected static <T> Set<T> set(T... elements)
{
return Collections.unmodifiableSet(new HashSet<T>(Arrays.asList(elements)));
}
/**
* @since 4.0
*/
public static String idToString(CDOID id)
{
StringBuilder builder = new StringBuilder();
CDOIDUtil.write(builder, id);
return builder.toString();
}
/**
* @since 4.0
*/
public static CDOID stringToID(String string)
{
return CDOIDUtil.read(string);
}
/**
* @since 3.0
*/
public static IStoreAccessor.QueryResourcesContext.ExactMatch createExactMatchContext(final CDOID folderID,
final String name, final CDOBranchPoint branchPoint)
{
return new IStoreAccessor.QueryResourcesContext.ExactMatch()
{
private CDOID resourceID;
public CDOID getResourceID()
{
return resourceID;
}
public CDOBranch getBranch()
{
return branchPoint.getBranch();
}
public long getTimeStamp()
{
return branchPoint.getTimeStamp();
}
public CDOID getFolderID()
{
return folderID;
}
public String getName()
{
return name;
}
public boolean exactMatch()
{
return true;
}
public int getMaxResults()
{
return 1;
}
public boolean addResource(CDOID resourceID)
{
this.resourceID = resourceID;
return false;
}
};
}
}