blob: 9a7ffe794aa5c2cb0beff37b604b06bb369349d3 [file] [log] [blame]
/**
* Copyright (c) 2004 - 2010 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
* Stefan Winkler - https://bugs.eclipse.org/bugs/show_bug.cgi?id=259402
* Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444
* Stefan Winkler - 249610: [DB] Support external references (Implementation)
* Victor Roldan - 289237: [DB] [maintenance] Support external references
* Caspar De Groot - https://bugs.eclipse.org/333260
*/
package org.eclipse.emf.cdo.server.internal.db;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.server.ISession;
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.server.StoreThreadLocal;
import org.eclipse.emf.cdo.server.db.IMetaDataManager;
import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
import org.eclipse.emf.cdo.server.internal.db.messages.Messages;
import org.eclipse.emf.cdo.spi.server.LongIDStore;
import org.eclipse.emf.cdo.spi.server.StoreAccessorPool;
import org.eclipse.net4j.db.DBException;
import org.eclipse.net4j.db.DBUtil;
import org.eclipse.net4j.db.IDBAdapter;
import org.eclipse.net4j.db.IDBConnectionProvider;
import org.eclipse.net4j.db.ddl.IDBSchema;
import org.eclipse.net4j.db.ddl.IDBTable;
import org.eclipse.net4j.spi.db.DBSchema;
import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump;
import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
import org.eclipse.net4j.util.om.monitor.ProgressDistributor;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
* @author Eike Stepper
*/
public class DBStore extends LongIDStore implements InternalIDBStore
{
public static final String TYPE = "db"; //$NON-NLS-1$
private long creationTime;
private boolean firstTime;
private IMappingStrategy mappingStrategy;
private IDBSchema dbSchema;
private IDBAdapter dbAdapter;
private IDBConnectionProvider dbConnectionProvider;
private IMetaDataManager metaDataManager;
private IExternalReferenceManager.Internal externalReferenceManager;
private CDOID rootResourceID;
@ExcludeFromDump
private transient ProgressDistributor accessorWriteDistributor = new ProgressDistributor.Geometric()
{
@Override
public String toString()
{
String result = "accessorWriteDistributor"; //$NON-NLS-1$
if (getRepository() != null)
{
result += ": " + getRepository().getName(); //$NON-NLS-1$
}
return result;
}
};
@ExcludeFromDump
private transient StoreAccessorPool readerPool = new StoreAccessorPool(this, null);
@ExcludeFromDump
private transient StoreAccessorPool writerPool = new StoreAccessorPool(this, null);
public DBStore()
{
super(TYPE, set(ChangeFormat.REVISION, ChangeFormat.DELTA), //
set(RevisionTemporality.AUDITING, RevisionTemporality.NONE), //
set(RevisionParallelism.NONE));
}
public IMappingStrategy getMappingStrategy()
{
return mappingStrategy;
}
public void setMappingStrategy(IMappingStrategy mappingStrategy)
{
this.mappingStrategy = mappingStrategy;
mappingStrategy.setStore(this);
setRevisionTemporality(mappingStrategy.hasAuditSupport() ? RevisionTemporality.AUDITING : RevisionTemporality.NONE);
}
public IDBAdapter getDBAdapter()
{
return dbAdapter;
}
public void setDBAdapter(IDBAdapter dbAdapter)
{
this.dbAdapter = dbAdapter;
}
public IDBConnectionProvider getDBConnectionProvider()
{
return dbConnectionProvider;
}
public void setDbConnectionProvider(IDBConnectionProvider dbConnectionProvider)
{
this.dbConnectionProvider = dbConnectionProvider;
}
public void setDataSource(DataSource dataSource)
{
dbConnectionProvider = DBUtil.createConnectionProvider(dataSource);
}
public IMetaDataManager getMetaDataManager()
{
return metaDataManager;
}
public IExternalReferenceManager getExternalReferenceManager()
{
return externalReferenceManager;
}
@Override
public Set<ChangeFormat> getSupportedChangeFormats()
{
if (mappingStrategy.hasDeltaSupport())
{
return set(ChangeFormat.DELTA);
}
return set(ChangeFormat.REVISION);
}
public ProgressDistributor getAccessorWriteDistributor()
{
return accessorWriteDistributor;
}
public IDBSchema getDBSchema()
{
return dbSchema;
}
@Override
public DBStoreAccessor getReader(ISession session)
{
return (DBStoreAccessor)super.getReader(session);
}
@Override
public DBStoreAccessor getWriter(ITransaction transaction)
{
return (DBStoreAccessor)super.getWriter(transaction);
}
@Override
protected StoreAccessorPool getReaderPool(ISession session, boolean forReleasing)
{
return readerPool;
}
@Override
protected StoreAccessorPool getWriterPool(IView view, boolean forReleasing)
{
return writerPool;
}
@Override
protected DBStoreAccessor createReader(ISession session) throws DBException
{
return new DBStoreAccessor(this, session);
}
@Override
protected DBStoreAccessor createWriter(ITransaction transaction) throws DBException
{
return new DBStoreAccessor(this, transaction);
}
protected Connection getConnection()
{
Connection connection = dbConnectionProvider.getConnection();
try
{
connection.setAutoCommit(false);
}
catch (SQLException ex)
{
throw new DBException(ex);
}
if (connection == null)
{
throw new DBException("No connection from connection provider: " + dbConnectionProvider); //$NON-NLS-1$
}
return connection;
}
public long getCreationTime()
{
return creationTime;
}
public boolean isFirstTime()
{
return firstTime;
}
@Override
protected void doBeforeActivate() throws Exception
{
super.doBeforeActivate();
checkNull(mappingStrategy, Messages.getString("DBStore.2")); //$NON-NLS-1$
checkNull(dbAdapter, Messages.getString("DBStore.1")); //$NON-NLS-1$
checkNull(dbConnectionProvider, Messages.getString("DBStore.0")); //$NON-NLS-1$
checkState(getRevisionTemporality() == RevisionTemporality.AUDITING == mappingStrategy.hasAuditSupport(),
Messages.getString("DBStore.7")); //$NON-NLS-1$
}
@Override
protected void doActivate() throws Exception
{
super.doActivate();
dbSchema = createSchema();
metaDataManager = new MetaDataManager(this);
LifecycleUtil.activate(metaDataManager);
Connection connection = getConnection();
LifecycleUtil.activate(mappingStrategy);
try
{
Set<IDBTable> createdTables = CDODBSchema.INSTANCE.create(dbAdapter, connection);
if (createdTables.contains(CDODBSchema.REPOSITORY))
{
firstStart(connection);
}
else
{
reStart(connection);
}
connection.commit();
externalReferenceManager = createExternalReferenceManager();
externalReferenceManager.setStore(this);
LifecycleUtil.activate(externalReferenceManager);
}
finally
{
DBUtil.close(connection);
}
}
protected void firstStart(Connection connection)
{
creationTime = getStartupTime();
firstTime = true;
DBUtil.insertRow(connection, dbAdapter, CDODBSchema.REPOSITORY, creationTime, 1, creationTime, 0, CRASHED, CRASHED);
OM.LOG.info(MessageFormat.format(Messages.getString("DBStore.8"), creationTime)); //$NON-NLS-1$
}
protected void reStart(Connection connection)
{
creationTime = DBUtil.selectMaximumLong(connection, CDODBSchema.REPOSITORY_CREATED);
long lastMetaId = DBUtil.selectMaximumLong(connection, CDODBSchema.REPOSITORY_NEXT_METAID);
long lastObjectID = DBUtil.selectMaximumLong(connection, CDODBSchema.REPOSITORY_NEXT_CDOID);
if (lastObjectID == CRASHED || getLastMetaID() == CRASHED)
{
OM.LOG.info(Messages.getString("DBStore.9")); //$NON-NLS-1$
lastObjectID = mappingStrategy.repairAfterCrash(dbAdapter, connection);
lastMetaId = DBUtil.selectMaximumLong(connection, CDODBSchema.PACKAGE_INFOS_META_UB);
OM.LOG.info(MessageFormat.format(Messages.getString("DBStore.10"), lastObjectID, lastMetaId)); //$NON-NLS-1$
}
setLastMetaID(lastMetaId);
setLastObjectID(lastObjectID);
StringBuilder builder = new StringBuilder();
builder.append("UPDATE "); //$NON-NLS-1$
builder.append(CDODBSchema.REPOSITORY);
builder.append(" SET "); //$NON-NLS-1$
builder.append(CDODBSchema.REPOSITORY_STARTS);
builder.append("="); //$NON-NLS-1$
builder.append(CDODBSchema.REPOSITORY_STARTS);
builder.append("+1, "); //$NON-NLS-1$
builder.append(CDODBSchema.REPOSITORY_STARTED);
builder.append("="); //$NON-NLS-1$
builder.append(getStartupTime());
builder.append(", "); //$NON-NLS-1$
builder.append(CDODBSchema.REPOSITORY_STOPPED);
builder.append("=0, "); //$NON-NLS-1$
builder.append(CDODBSchema.REPOSITORY_NEXT_CDOID);
builder.append("="); //$NON-NLS-1$
builder.append(CRASHED);
builder.append(", "); //$NON-NLS-1$
builder.append(CDODBSchema.REPOSITORY_NEXT_METAID);
builder.append("="); //$NON-NLS-1$
builder.append(CRASHED);
String sql = builder.toString();
int count = DBUtil.update(connection, sql);
if (count == 0)
{
throw new DBException("No row updated in table " + CDODBSchema.REPOSITORY); //$NON-NLS-1$
}
}
@Override
protected void doDeactivate() throws Exception
{
Connection connection = null;
LifecycleUtil.deactivate(metaDataManager);
metaDataManager = null;
LifecycleUtil.deactivate(externalReferenceManager);
externalReferenceManager = null;
try
{
connection = getConnection();
LifecycleUtil.deactivate(mappingStrategy);
StringBuilder builder = new StringBuilder();
builder.append("UPDATE "); //$NON-NLS-1$
builder.append(CDODBSchema.REPOSITORY);
builder.append(" SET "); //$NON-NLS-1$
builder.append(CDODBSchema.REPOSITORY_STOPPED);
builder.append("="); //$NON-NLS-1$
builder.append(getShutdownTime());
builder.append(", "); //$NON-NLS-1$
builder.append(CDODBSchema.REPOSITORY_NEXT_CDOID);
builder.append("="); //$NON-NLS-1$
builder.append(getLastObjectID());
builder.append(", "); //$NON-NLS-1$
builder.append(CDODBSchema.REPOSITORY_NEXT_METAID);
builder.append("="); //$NON-NLS-1$
builder.append(getLastMetaID());
String sql = builder.toString();
int count = DBUtil.update(connection, sql);
if (count == 0)
{
throw new DBException("No row updated in table " + CDODBSchema.REPOSITORY); //$NON-NLS-1$
}
connection.commit();
}
finally
{
DBUtil.close(connection);
}
readerPool.dispose();
writerPool.dispose();
super.doDeactivate();
}
protected IExternalReferenceManager.Internal createExternalReferenceManager()
{
return new ExternalReferenceManager();
}
protected IDBSchema createSchema()
{
String name = getRepository().getName();
return new DBSchema(name);
}
protected long getStartupTime()
{
return System.currentTimeMillis();
}
protected long getShutdownTime()
{
return System.currentTimeMillis();
}
@Override
public CDOID getRootResourceID()
{
if (rootResourceID != null)
{
return rootResourceID;
}
IStoreAccessor accessor = StoreThreadLocal.getAccessor();
final List<CDOID> resourceIDs = new LinkedList<CDOID>();
accessor.queryResources(new IStoreAccessor.QueryResourcesContext()
{
public long getTimeStamp()
{
return CDORevision.UNSPECIFIED_DATE;
}
public CDOID getFolderID()
{
return null;
}
public String getName()
{
return null;
}
public boolean exactMatch()
{
return true;
}
public int getMaxResults()
{
return 2;
}
public boolean addResource(CDOID resourceID)
{
return resourceIDs.add(resourceID);
}
});
if (resourceIDs.size() != 1)
{
throw new RuntimeException("Could not deduce rootResourceID");
}
rootResourceID = resourceIDs.get(0);
return rootResourceID;
}
}