blob: 82c2c4705db945d12918ab7aaadc81f48e1fbc33 [file] [log] [blame]
/*
* Copyright (c) 2010-2012, 2015 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:
* Victor Roldan Betancort - initial API and implementation
*/
package org.eclipse.emf.cdo.server.internal.db4o;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDUtil;
import org.eclipse.emf.cdo.server.ISession;
import org.eclipse.emf.cdo.server.IStore;
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.db4o.IDB4OIdentifiableObject;
import org.eclipse.emf.cdo.server.db4o.IDB4OStore;
import org.eclipse.emf.cdo.spi.server.LongIDStore;
import org.eclipse.emf.cdo.spi.server.StoreAccessorPool;
import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump;
import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
import com.db4o.Db4o;
import com.db4o.ObjectContainer;
import com.db4o.ObjectServer;
import com.db4o.ObjectSet;
import com.db4o.config.Configuration;
import com.db4o.constraints.UniqueFieldValueConstraint;
import com.db4o.query.Query;
import com.db4o.reflect.jdk.JdkReflector;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author Victor Roldan Betancort
*/
public class DB4OStore extends LongIDStore implements IDB4OStore
{
private static final String ID_ATTRIBUTE = "id";
private transient String storeLocation;
private transient int port;
private transient ObjectServer server;
private transient Configuration serverConfiguration;
private ServerInfo serverInfo;
private DB4ODurableLockingManager durableLockingManager = new DB4ODurableLockingManager();
@ExcludeFromDump
private transient final StoreAccessorPool readerPool = new StoreAccessorPool(this, null);
@ExcludeFromDump
private transient final StoreAccessorPool writerPool = new StoreAccessorPool(this, null);
public DB4OStore(String storeLocation, int port)
{
super(IDB4OStore.TYPE, set(ChangeFormat.REVISION), set(RevisionTemporality.NONE, RevisionTemporality.AUDITING),
set(RevisionParallelism.NONE, RevisionParallelism.BRANCHING));
// setRevisionTemporality(RevisionTemporality.AUDITING);
// setRevisionParallelism(RevisionParallelism.BRANCHING);
this.storeLocation = storeLocation;
this.port = port;
}
public DB4OStore(String storeLocation, int port, Configuration serverConfiguration)
{
this(storeLocation, port);
this.serverConfiguration = serverConfiguration;
}
public String getStoreLocation()
{
return storeLocation;
}
public int getPort()
{
return port;
}
public long getCreationTime()
{
return getServerInfo().getCreationTime();
}
public void setCreationTime(long creationTime)
{
getServerInfo().setCreationTime(creationTime);
}
public boolean isFirstStart()
{
return getServerInfo().isFirstTime();
}
public DB4ODurableLockingManager getDurableLockingManager()
{
return durableLockingManager;
}
public Map<String, String> getPersistentProperties(Set<String> names)
{
if (names == null || names.isEmpty())
{
return new HashMap<String, String>(getServerInfo().getProperties());
}
Map<String, String> result = new HashMap<String, String>();
for (String key : names)
{
String value = getServerInfo().getProperties().get(key);
if (value != null)
{
result.put(key, value);
}
}
return result;
}
public void setPersistentProperties(Map<String, String> properties)
{
ServerInfo serverInfo = getServerInfo();
serverInfo.getProperties().putAll(properties);
commitServerInfo(null);
}
public void removePersistentProperties(Set<String> names)
{
ServerInfo serverInfo = getServerInfo();
Map<String, String> properties = serverInfo.getProperties();
for (String key : names)
{
properties.remove(key);
}
commitServerInfo(null);
}
// @Override
// public CDOID getNextCDOID(LongIDStoreAccessor accessor, CDORevision revision)
// {
// ObjectContainer objectContainer = ((DB4OStoreAccessor)accessor).getObjectContainer();
// ExtObjectContainer ext = objectContainer.ext();
// ext.store(revision);
//
// long id = ext.getID(revision);
// return CDOIDUtil.createLong(id);
// }
public ObjectContainer openClient()
{
return server.openClient();
}
@Override
protected void doActivate() throws Exception
{
super.doActivate();
initObjectServer();
initServerInfo();
setLastCommitTime(getServerInfo().getLastCommitTime());
setLastObjectID(fetchLastObjectID());
LifecycleUtil.activate(durableLockingManager);
}
private long fetchLastObjectID()
{
ObjectContainer container = openClient();
try
{
Query query = container.query();
query.constrain(DB4ORevision.class);
query.descend("id").orderDescending();
ObjectSet<?> results = query.execute();
int size = results.size();
if (size > 0)
{
DB4ORevision rev = (DB4ORevision)results.next();
return rev.getID();
}
return 0;
}
finally
{
closeClient(container);
}
}
@SuppressWarnings("deprecation")
protected void initObjectServer()
{
Configuration configuration = serverConfiguration;
if (configuration == null)
{
configuration = createServerConfiguration();
}
{
File file = new File(getStoreLocation());
if (!file.exists())
{
try
{
file.createNewFile();
}
catch (IOException ex)
{
throw new RuntimeException(ex);
}
}
}
server = Db4o.openServer(configuration, getStoreLocation(), getPort());
}
protected void tearDownObjectServer()
{
server.close();
server = null;
}
private ServerInfo getServerInfo()
{
if (serverInfo == null)
{
initServerInfo();
}
return serverInfo;
}
private void initServerInfo()
{
ObjectContainer container = openClient();
try
{
serverInfo = getServerInfoFromDatabase(container);
if (serverInfo == null)
{
serverInfo = new ServerInfo();
serverInfo.setFirstTime(true);
serverInfo.setCreationTime(System.currentTimeMillis());
commitServerInfo(container);
}
else
{
if (serverInfo.isFirstTime())
{
serverInfo.setFirstTime(false);
commitServerInfo(container);
}
}
}
finally
{
closeClient(container);
}
}
private ServerInfo getServerInfoFromDatabase(ObjectContainer container)
{
ObjectSet<ServerInfo> infos = container.query(ServerInfo.class);
if (infos.size() > 1)
{
throw new IllegalStateException("ServeInfo is stored in container more than once");
}
if (infos.size() == 1)
{
return infos.get(0);
}
return null;
}
protected void closeClient(ObjectContainer container)
{
container.close();
}
private void commitServerInfo(ObjectContainer container)
{
ObjectContainer usedContainer = container != null ? container : openClient();
try
{
ServerInfo storedInfo = getServerInfoFromDatabase(usedContainer);
if (storedInfo != null && storedInfo != serverInfo)
{
storedInfo.setCreationTime(serverInfo.getCreationTime());
storedInfo.setFirstTime(serverInfo.isFirstTime());
storedInfo.setLastCommitTime(serverInfo.getLastCommitTime());
storedInfo.setProperties(serverInfo.getProperties());
serverInfo = storedInfo;
}
usedContainer.store(serverInfo);
usedContainer.commit();
}
finally
{
if (usedContainer != container)
{
closeClient(usedContainer);
}
}
}
@Override
protected void doDeactivate() throws Exception
{
ObjectContainer container = openClient();
try
{
getServerInfo().setLastCommitTime(getLastCommitTime());
commitServerInfo(container);
}
finally
{
closeClient(container);
}
LifecycleUtil.deactivate(durableLockingManager);
tearDownObjectServer();
super.doDeactivate();
}
protected Configuration createServerConfiguration()
{
@SuppressWarnings("deprecation")
Configuration config = Db4o.newConfiguration();
config.reflectWith(new JdkReflector(getClass().getClassLoader()));
config.objectClass(DB4ORevision.class).objectField("id").indexed(true);
config.add(new UniqueFieldValueConstraint(DB4ORevision.class, "id"));
config.objectClass(DB4OPackageUnit.class).objectField("id").indexed(true);
config.add(new UniqueFieldValueConstraint(DB4OPackageUnit.class, "id"));
config.objectClass(DB4OIdentifiableObject.class).objectField("id").indexed(true);
config.add(new UniqueFieldValueConstraint(DB4OIdentifiableObject.class, "id"));
config.objectClass(DB4OCommitInfo.class).objectField("timeStamp").indexed(true);
config.objectClass(DB4OLockArea.class).objectField("id").indexed(true);
config.add(new UniqueFieldValueConstraint(DB4OLockArea.class, "id"));
config.objectClass(DB4OLockArea.class).cascadeOnUpdate(true);
config.objectClass(DB4OLockArea.class).cascadeOnDelete(true);
return config;
}
@Override
protected IStoreAccessor createReader(ISession session)
{
return new DB4OStoreAccessor(this, session);
}
@Override
protected IStoreAccessor createWriter(ITransaction transaction)
{
return new DB4OStoreAccessor(this, transaction);
}
@Override
protected StoreAccessorPool getReaderPool(ISession session, boolean forReleasing)
{
return readerPool;
}
@Override
protected StoreAccessorPool getWriterPool(IView view, boolean forReleasing)
{
return writerPool;
}
public static DB4ORevision getRevision(ObjectContainer container, CDOID id)
{
Query query = container.query();
query.constrain(DB4ORevision.class);
query.descend(ID_ATTRIBUTE).constrain(CDOIDUtil.getLong(id));
ObjectSet<?> revisions = query.execute();
if (revisions.isEmpty())
{
return null;
}
return (DB4ORevision)revisions.get(0);
}
public static <T> List<T> getElementsOfType(ObjectContainer container, Class<T> clazz)
{
ObjectSet<T> elements = container.query(clazz);
return elements;
}
public static IDB4OIdentifiableObject getIdentifiableObject(ObjectContainer container, String id)
{
Query query = container.query();
query.constrain(IDB4OIdentifiableObject.class);
query.descend(ID_ATTRIBUTE).constrain(id);
ObjectSet<?> revisions = query.execute();
if (revisions.isEmpty())
{
return null;
}
return (IDB4OIdentifiableObject)revisions.get(0);
}
public static void removeRevision(ObjectContainer container, CDOID id)
{
DB4ORevision revision = getRevision(container, id);
if (revision != null)
{
container.delete(revision);
}
}
/**
* Carries {@link IStore}-related information.
*
* @author Victor Roldan Betancort
*/
private static final class ServerInfo
{
private boolean isFirstTime;
private long creationTime;
private long lastCommitTime;
private Map<String, String> properties = new HashMap<String, String>();
public boolean isFirstTime()
{
return isFirstTime;
}
public void setFirstTime(boolean isFirstTime)
{
this.isFirstTime = isFirstTime;
}
public void setCreationTime(long creationTime)
{
this.creationTime = creationTime;
}
public long getCreationTime()
{
return creationTime;
}
public void setProperties(Map<String, String> properties)
{
this.properties = properties;
}
public Map<String, String> getProperties()
{
return properties;
}
public long getLastCommitTime()
{
return lastCommitTime;
}
public void setLastCommitTime(long lastCommitTime)
{
this.lastCommitTime = lastCommitTime;
}
}
}