diff options
author | Caspar De Groot | 2011-06-08 10:54:59 +0000 |
---|---|---|
committer | Caspar De Groot | 2011-06-08 10:54:59 +0000 |
commit | 4d83e5b62819ef74f598653ca158969830d87af1 (patch) | |
tree | f7f8f0f45779818d738de4de219ef81d21602f2c | |
parent | c5d3ceacb3ab876418518d7b1bc81368c177975f (diff) | |
download | cdo-4d83e5b62819ef74f598653ca158969830d87af1.tar.gz cdo-4d83e5b62819ef74f598653ca158969830d87af1.tar.xz cdo-4d83e5b62819ef74f598653ca158969830d87af1.zip |
[347285] Durable locking support for db4o
https://bugs.eclipse.org/bugs/show_bug.cgi?id=347285
15 files changed, 684 insertions, 23 deletions
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/IDurableLockingManager.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/IDurableLockingManager.java index 741f86ad8b..52f803bbc2 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/IDurableLockingManager.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/lock/IDurableLockingManager.java @@ -99,7 +99,7 @@ public interface IDurableLockingManager {
NONE(0), READ(1), WRITE(2), READ_WRITE(READ.getValue() | WRITE.getValue());
- private int value;
+ private final int value;
private LockGrade(int value)
{
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDOListImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDOListImpl.java index 56fe0ae7d1..a5b4926881 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDOListImpl.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDOListImpl.java @@ -40,7 +40,7 @@ public class CDOListImpl extends MoveableArrayList<Object> implements InternalCD private static final long serialVersionUID = 1L; - private boolean frozen; + private transient boolean frozen; public CDOListImpl(int initialCapacity, int size) { diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDORevisionImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDORevisionImpl.java index 433d4c50b4..38a0fecc17 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDORevisionImpl.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDORevisionImpl.java @@ -34,7 +34,7 @@ public class CDORevisionImpl extends BaseCDORevision { private Object[] values; - private boolean frozen; + private transient boolean frozen; public CDORevisionImpl(EClass eClass) { @@ -93,7 +93,7 @@ public class CDORevisionImpl extends BaseCDORevision public void freeze() { frozen = true; - + EStructuralFeature[] features = CDOModelUtil.getAllPersistentFeatures(getEClass()); for (int i = 0; i < features.length; i++) { diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DurableLockingManager.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DurableLockingManager.java index 07d2e35d54..594ff9964c 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DurableLockingManager.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DurableLockingManager.java @@ -16,13 +16,13 @@ import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea; import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea.Handler;
import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockAreaNotFoundException;
import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockGrade;
-import org.eclipse.emf.cdo.internal.server.LockManager;
import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
import org.eclipse.emf.cdo.server.db.IIDHandler;
import org.eclipse.emf.cdo.server.db.IPreparedStatementCache;
import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability;
import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranchManager;
import org.eclipse.emf.cdo.spi.server.DurableLockArea;
+import org.eclipse.emf.cdo.spi.server.InternalLockManager;
import org.eclipse.net4j.db.DBException;
import org.eclipse.net4j.db.DBType;
@@ -596,9 +596,10 @@ public class DurableLockingManager extends Lifecycle stmtUpdate = statementCache.getPreparedStatement(sqlUpdateLock, ReuseProbability.MEDIUM);
stmtUpdate.setString(2, durableLockingID);
+ InternalLockManager lockManager = accessor.getStore().getRepository().getLockManager();
for (Object key : keys)
{
- CDOID id = LockManager.getIDToLock(key);
+ CDOID id = lockManager.getLockKeyID(key);
idHandler.setCDOID(stmtSelect, 2, id);
resultSet = stmtSelect.executeQuery();
diff --git a/plugins/org.eclipse.emf.cdo.server.db4o/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.server.db4o/META-INF/MANIFEST.MF index 96e17d1dd4..f77863eb66 100644 --- a/plugins/org.eclipse.emf.cdo.server.db4o/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.emf.cdo.server.db4o/META-INF/MANIFEST.MF @@ -11,6 +11,7 @@ Export-Package: org.eclipse.emf.cdo.server.db4o;version="1.0.0", org.eclipse.emf.cdo.server.internal.db4o.bundle;version="1.0.0";x-internal:=true Import-Package: com.db4o;version="[7.4.0,8.0.0)", com.db4o.config;version="[7.4.0,8.0.0)", + com.db4o.constraints;version="[7.4.0,8.0.0)", com.db4o.ext;version="[7.4.0,8.0.0)", com.db4o.query;version="[7.4.0,8.0.0)", com.db4o.reflect;version="[7.4.0,8.0.0)", diff --git a/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4ODurableLockingManager.java b/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4ODurableLockingManager.java new file mode 100644 index 0000000000..2efdf7e275 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4ODurableLockingManager.java @@ -0,0 +1,199 @@ +/** + * 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: + * Caspar De Groot - initial API and implementation + */ +package org.eclipse.emf.cdo.server.internal.db4o; + +import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea.Handler; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockAreaNotFoundException; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockGrade; +import org.eclipse.emf.cdo.spi.server.DurableLockArea; +import org.eclipse.emf.cdo.spi.server.InternalLockManager; + +import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; +import org.eclipse.net4j.util.lifecycle.Lifecycle; + +import com.db4o.ObjectContainer; +import com.db4o.ObjectSet; +import com.db4o.query.Query; + +import java.util.Collection; +import java.util.Map; + +/** + * @author Caspar De Groot + */ +public class DB4ODurableLockingManager extends Lifecycle +{ + public DB4ODurableLockingManager() + { + } + + public LockArea createLockArea(DB4OStoreAccessor accessor, String userID, CDOBranchPoint branchPoint, + boolean readOnly, Map<CDOID, LockGrade> locks) + { + String durableLockingID = getNextDurableLockingID(accessor); + LockArea lockArea = new DurableLockArea(durableLockingID, userID, branchPoint, readOnly, locks); + storeLockArea(accessor, lockArea); + return lockArea; + } + + private void storeLockArea(DB4OStoreAccessor accessor, LockArea area) + { + ObjectContainer objectContainer = accessor.getObjectContainer(); + DB4OLockArea primitiveLockArea = DB4OLockArea.getPrimitiveLockArea(area); + objectContainer.store(primitiveLockArea); + objectContainer.commit(); + } + + public LockArea getLockArea(DB4OStoreAccessor accessor, String durableLockingID) throws LockAreaNotFoundException + { + DB4OLockArea primitive = getPrimitiveLockArea(accessor, durableLockingID); + return DB4OLockArea.getLockArea(accessor.getStore(), primitive); + } + + private DB4OLockArea getPrimitiveLockArea(DB4OStoreAccessor accessor, String durableLockingID) + throws LockAreaNotFoundException + { + ObjectContainer container = accessor.getObjectContainer(); + Query query = container.query(); + query.constrain(DB4OLockArea.class); + query.descend("id").constrain(durableLockingID); + + ObjectSet<?> lockAreas = query.execute(); + if (lockAreas.isEmpty()) + { + throw new LockAreaNotFoundException(durableLockingID); + } + + if (lockAreas.size() > 1) + { + throw new AssertionError("Lockarea stored more than once in object database"); + } + + return (DB4OLockArea)lockAreas.get(0); + } + + public void getLockAreas(DB4OStoreAccessor accessor, String userIDPrefix, Handler handler) + { + ObjectContainer container = accessor.getObjectContainer(); + Query query = container.query(); + query.constrain(DB4OLockArea.class); + + if (userIDPrefix.length() > 0) + { + query.descend("userID").constrain(userIDPrefix).startsWith(true); + } + + ObjectSet<?> primitives = query.execute(); + for (Object primitive : primitives) + { + LockArea area = DB4OLockArea.getLockArea(accessor.getStore(), (DB4OLockArea)primitive); + if (!handler.handleLockArea(area)) + { + break; + } + } + } + + public void deleteLockArea(DB4OStoreAccessor accessor, String durableLockingID) + { + DB4OLockArea primitive = getPrimitiveLockArea(accessor, durableLockingID); + ObjectContainer container = accessor.getObjectContainer(); + container.delete(primitive); + container.commit(); + } + + public void lock(DB4OStoreAccessor accessor, String durableLockingID, LockType type, + Collection<? extends Object> objectsToLock) + { + // TODO (CD) Refactor? Next chunk of code copied verbatim from MEMStore.lock + LockArea area = getLockArea(accessor, durableLockingID); + Map<CDOID, LockGrade> locks = area.getLocks(); + + InternalLockManager lockManager = accessor.getStore().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); + } + + storeLockArea(accessor, area); + } + + public void unlock(DB4OStoreAccessor accessor, String durableLockingID, LockType type, + Collection<? extends Object> objectsToUnlock) + { + // TODO (CD) Refactor? Next chunk of code copied verbatim from MEMStore.lock + LockArea area = getLockArea(accessor, durableLockingID); + Map<CDOID, LockGrade> locks = area.getLocks(); + + InternalLockManager lockManager = accessor.getStore().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); + } + else + { + locks.put(id, grade); + } + } + } + + storeLockArea(accessor, area); + } + + public void unlock(DB4OStoreAccessor accessor, String durableLockingID) + { + LockArea area = getLockArea(accessor, durableLockingID); + Map<CDOID, LockGrade> locks = area.getLocks(); + locks.clear(); + + storeLockArea(accessor, area); + } + + // TODO: Refactor -- this was copied verbatim from DurableLockingManager + private String getNextDurableLockingID(DB4OStoreAccessor accessor) + { + for (;;) + { + String durableLockingID = DurableLockArea.createDurableLockingID(); + + try + { + getLockArea(accessor, durableLockingID); // Check uniqueness + // Not unique; try once more... + } + catch (LockAreaNotFoundException ex) + { + return durableLockingID; + } + } + } +} diff --git a/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4OLockArea.java b/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4OLockArea.java new file mode 100644 index 0000000000..35d248e751 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4OLockArea.java @@ -0,0 +1,119 @@ +/** + * 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: + * Caspar De Groot - initial API and implementation + */ +package org.eclipse.emf.cdo.server.internal.db4o; + +import org.eclipse.emf.cdo.common.branch.CDOBranch; +import org.eclipse.emf.cdo.common.branch.CDOBranchManager; +import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockGrade; +import org.eclipse.emf.cdo.server.db4o.IDB4OStore; +import org.eclipse.emf.cdo.spi.server.DurableLockArea; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * @author Caspar De Groot + */ +public class DB4OLockArea +{ + private static Map<LockArea, DB4OLockArea> map = new HashMap<LockArea, DB4OLockArea>(); + + private String id; + + private String userID; + + private long timestamp; + + private int branchID; + + private boolean readOnly; + + private List<DB4OLockEntry> lockEntries = new LinkedList<DB4OLockEntry>(); + + public static DB4OLockArea getPrimitiveLockArea(LockArea lockArea) + { + DB4OLockArea primitive = map.get(lockArea); + if (primitive == null) + { + primitive = new DB4OLockArea(); + } + + primitive.id = lockArea.getDurableLockingID(); + primitive.userID = lockArea.getUserID(); + primitive.timestamp = lockArea.getTimeStamp(); + primitive.branchID = lockArea.getBranch().getID(); + primitive.readOnly = lockArea.isReadOnly(); + + List<DB4OLockEntry> newList = DB4OLockEntry.getPrimitiveLockEntries(primitive, lockArea.getLocks()); + primitive.lockEntries = newList; + + return primitive; + } + + public static LockArea getLockArea(IDB4OStore store, DB4OLockArea primitive) + { + // Reconstruct the branchpoint + // + CDOBranchManager branchManager = store.getRepository().getBranchManager(); + CDOBranch branch = branchManager.getBranch(primitive.branchID); + CDOBranchPoint branchpoint = branch.getPoint(primitive.timestamp); + + // Reconstruct the lockMap + // + Map<CDOID, LockGrade> lockMap = new HashMap<CDOID, LockGrade>(); + for (DB4OLockEntry entry : primitive.getLockEntries()) + { + CDOID cdoid = CDOIDUtil.createLong(entry.getCdoID()); + LockGrade lockGrade = LockGrade.get(entry.getLockGrade()); + lockMap.put(cdoid, lockGrade); + } + + LockArea lockArea = new DurableLockArea(primitive.id, primitive.userID, branchpoint, primitive.readOnly, lockMap); + map.put(lockArea, primitive); + return lockArea; + } + + public void setId(String id) + { + this.id = id; + } + + public String getId() + { + return id; + } + + public String getUserID() + { + return userID; + } + + public long getTimestamp() + { + return timestamp; + } + + public int getBranchID() + { + return branchID; + } + + public List<DB4OLockEntry> getLockEntries() + { + return lockEntries; + } +} diff --git a/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4OLockEntry.java b/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4OLockEntry.java new file mode 100644 index 0000000000..267c5c2d1e --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4OLockEntry.java @@ -0,0 +1,93 @@ +/** + * 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: + * Caspar De Groot - 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.common.lock.IDurableLockingManager.LockGrade; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * @author Caspar De Groot + */ +public class DB4OLockEntry +{ + private long cdoID; + + private int lockGrade; + + public DB4OLockEntry(long longCdoID, int intLockGrade) + { + cdoID = longCdoID; + lockGrade = intLockGrade; + } + + public static List<DB4OLockEntry> getPrimitiveLockEntries(DB4OLockArea primitive, Map<CDOID, LockGrade> locks) + { + List<DB4OLockEntry> newList = new LinkedList<DB4OLockEntry>(); + + for (Entry<CDOID, LockGrade> entry : locks.entrySet()) + { + CDOID cdoid = entry.getKey(); + long longCdoID = CDOIDUtil.getLong(cdoid); + + LockGrade lockGrade = entry.getValue(); + int intLockGrade = lockGrade.getValue(); + + DB4OLockEntry lockEntry = getEntry(primitive.getLockEntries(), longCdoID); + if (lockEntry == null) + { + lockEntry = new DB4OLockEntry(longCdoID, intLockGrade); + } + else + { + lockEntry.setLockGrade(intLockGrade); + } + + newList.add(lockEntry); + } + + return newList; + } + + private void setLockGrade(int lockGrade) + { + this.lockGrade = lockGrade; + } + + // TODO (CD) Avoid linear search + private static DB4OLockEntry getEntry(List<DB4OLockEntry> entries, long targetID) + { + for (DB4OLockEntry entry : entries) + { + if (entry.cdoID == targetID) + { + return entry; + } + } + + return null; + } + + public long getCdoID() + { + return cdoID; + } + + public int getLockGrade() + { + return lockGrade; + } +} diff --git a/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4ORevision.java b/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4ORevision.java index a4ae8d3856..d8090ba8fc 100644 --- a/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4ORevision.java +++ b/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4ORevision.java @@ -19,6 +19,7 @@ import org.eclipse.emf.cdo.common.model.CDOClassInfo; import org.eclipse.emf.cdo.common.revision.CDOList; import org.eclipse.emf.cdo.common.revision.CDOListFactory; import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.CDORevisionData; import org.eclipse.emf.cdo.common.revision.CDORevisionFactory; import org.eclipse.emf.cdo.common.revision.CDORevisionUtil; import org.eclipse.emf.cdo.server.IRepository; @@ -272,6 +273,12 @@ public class DB4ORevision } else { + // Prevent the explicit null-ref "NIL" from being serialized! + if (obj == CDORevisionData.NIL) + { + obj = new ExplicitNull(); + } + values.add(i, obj); } } @@ -322,6 +329,12 @@ public class DB4ORevision value = DB4OFeatureMapEntry.getCDOFeatureMapEntryList(eClass, value); } + // Convert 'null' into the explicit null-ref "NIL" if appropriate + if (value instanceof ExplicitNull) + { + value = CDORevisionData.NIL; + } + revision.setValue(feature, value); } @@ -440,4 +453,11 @@ public class DB4ORevision return list; } } + + /** + * @author Caspar De Groot + */ + private static final class ExplicitNull + { + } } diff --git a/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4OStore.java b/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4OStore.java index 901ee7a0ed..518a1fcbe3 100644 --- a/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4OStore.java +++ b/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4OStore.java @@ -23,12 +23,14 @@ 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; @@ -56,6 +58,8 @@ public class DB4OStore extends LongIDStore implements IDB4OStore private ServerInfo serverInfo; + private DB4ODurableLockingManager durableLockingManager = new DB4ODurableLockingManager(); + @ExcludeFromDump private transient final StoreAccessorPool readerPool = new StoreAccessorPool(this, null); @@ -105,6 +109,11 @@ public class DB4OStore extends LongIDStore implements IDB4OStore return getServerInfo().isFirstTime(); } + public DB4ODurableLockingManager getDurableLockingManager() + { + return durableLockingManager; + } + public Map<String, String> getPersistentProperties(Set<String> names) { if (names == null || names.isEmpty()) @@ -167,6 +176,32 @@ public class DB4OStore extends LongIDStore implements IDB4OStore 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); + } } protected void initObjectServer() @@ -216,13 +251,9 @@ public class DB4OStore extends LongIDStore implements IDB4OStore try { - ObjectSet<ServerInfo> infos = container.query(ServerInfo.class); - if (infos.size() > 1) - { - throw new IllegalStateException("ServeInfo is stored in container more than once"); - } + serverInfo = getServerInfoFromDatabase(container); - if (infos.isEmpty()) + if (serverInfo == null) { serverInfo = new ServerInfo(); serverInfo.setFirstTime(true); @@ -231,7 +262,6 @@ public class DB4OStore extends LongIDStore implements IDB4OStore } else { - serverInfo = infos.get(0); if (serverInfo.isFirstTime()) { serverInfo.setFirstTime(false); @@ -245,6 +275,22 @@ public class DB4OStore extends LongIDStore implements IDB4OStore } } + 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(); @@ -256,6 +302,16 @@ public class DB4OStore extends LongIDStore implements IDB4OStore 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(); } @@ -271,8 +327,8 @@ public class DB4OStore extends LongIDStore implements IDB4OStore @Override protected void doDeactivate() throws Exception { - tearDownObjectServer(); ObjectContainer container = openClient(); + try { getServerInfo().setLastCommitTime(getLastCommitTime()); @@ -282,6 +338,10 @@ public class DB4OStore extends LongIDStore implements IDB4OStore { closeClient(container); } + + LifecycleUtil.deactivate(durableLockingManager); + tearDownObjectServer(); + super.doDeactivate(); } @@ -289,10 +349,23 @@ public class DB4OStore extends LongIDStore implements IDB4OStore { 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; } @@ -400,7 +473,6 @@ public class DB4OStore extends LongIDStore implements IDB4OStore return creationTime; } - @SuppressWarnings("unused") public void setProperties(Map<String, String> properties) { this.properties = properties; diff --git a/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4OStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4OStoreAccessor.java index b65e4dbc9a..5040ca8111 100644 --- a/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4OStoreAccessor.java +++ b/plugins/org.eclipse.emf.cdo.server.db4o/src/org/eclipse/emf/cdo/server/internal/db4o/DB4OStoreAccessor.java @@ -18,6 +18,7 @@ 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.IDurableLockingManager.LockArea.Handler; import org.eclipse.emf.cdo.common.model.EMFUtil; import org.eclipse.emf.cdo.common.protocol.CDODataInput; import org.eclipse.emf.cdo.common.protocol.CDODataOutput; @@ -29,7 +30,8 @@ import org.eclipse.emf.cdo.common.util.CDOQueryInfo; import org.eclipse.emf.cdo.eresource.EresourcePackage; import org.eclipse.emf.cdo.server.IQueryHandler; import org.eclipse.emf.cdo.server.ISession; -import org.eclipse.emf.cdo.server.IStoreAccessor; +import org.eclipse.emf.cdo.server.IStoreAccessor.DurableLocking; +import org.eclipse.emf.cdo.server.IStoreAccessor.Raw; import org.eclipse.emf.cdo.server.IStoreChunkReader; import org.eclipse.emf.cdo.server.ITransaction; import org.eclipse.emf.cdo.server.db4o.IDB4OIdentifiableObject; @@ -47,6 +49,7 @@ import org.eclipse.net4j.util.HexUtil; import org.eclipse.net4j.util.ObjectUtil; import org.eclipse.net4j.util.StringUtil; 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.Monitor; import org.eclipse.net4j.util.om.monitor.OMMonitor; @@ -85,7 +88,7 @@ import java.util.Set; /** * @author Victor Roldan Betancort */ -public class DB4OStoreAccessor extends LongIDStoreAccessor implements IStoreAccessor.Raw +public class DB4OStoreAccessor extends LongIDStoreAccessor implements Raw, DurableLocking { private ObjectContainer objectContainer; @@ -827,4 +830,47 @@ public class DB4OStoreAccessor extends LongIDStoreAccessor implements IStoreAcce { doCommit(monitor); } + + public LockArea createLockArea(String userID, CDOBranchPoint branchPoint, boolean readOnly, + Map<CDOID, LockGrade> locks) + { + DB4ODurableLockingManager manager = getStore().getDurableLockingManager(); + return manager.createLockArea(this, userID, branchPoint, readOnly, locks); + } + + public LockArea getLockArea(String durableLockingID) throws LockAreaNotFoundException + { + DB4ODurableLockingManager manager = getStore().getDurableLockingManager(); + return manager.getLockArea(this, durableLockingID); + } + + public void getLockAreas(String userIDPrefix, Handler handler) + { + DB4ODurableLockingManager manager = getStore().getDurableLockingManager(); + manager.getLockAreas(this, userIDPrefix, handler); + } + + public void deleteLockArea(String durableLockingID) + { + DB4ODurableLockingManager manager = getStore().getDurableLockingManager(); + manager.deleteLockArea(this, durableLockingID); + } + + public void lock(String durableLockingID, LockType type, Collection<? extends Object> objectsToLock) + { + DB4ODurableLockingManager manager = getStore().getDurableLockingManager(); + manager.lock(this, durableLockingID, type, objectsToLock); + } + + public void unlock(String durableLockingID, LockType type, Collection<? extends Object> objectsToUnlock) + { + DB4ODurableLockingManager manager = getStore().getDurableLockingManager(); + manager.unlock(this, durableLockingID, type, objectsToUnlock); + } + + public void unlock(String durableLockingID) + { + DB4ODurableLockingManager manager = getStore().getDurableLockingManager(); + manager.unlock(this, durableLockingID); + } } diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/LockManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/LockManager.java index 74318dd46e..ad6c3a7ba1 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/LockManager.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/LockManager.java @@ -129,7 +129,7 @@ public class LockManager extends RWLockManager<Object, IView> implements Interna { public boolean handleLockEntry(LockEntry<Object, IView> lockEntry) { - CDOID id = getIDToLock(lockEntry.getObject()); + CDOID id = getLockKeyID(lockEntry.getObject()); LockGrade grade = LockGrade.NONE; if (lockEntry.isReadLock(view)) { @@ -364,7 +364,7 @@ public class LockManager extends RWLockManager<Object, IView> implements Interna } } - public static CDOID getIDToLock(Object key) + public CDOID getLockKeyID(Object key) { if (key instanceof CDOID) { diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java index df70bf7573..6afe13c758 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java @@ -29,7 +29,6 @@ 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.internal.server.LockManager; import org.eclipse.emf.cdo.server.ISession; import org.eclipse.emf.cdo.server.IStoreAccessor; import org.eclipse.emf.cdo.server.IStoreAccessor.DurableLocking; @@ -47,6 +46,7 @@ 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.DurableLockArea; +import org.eclipse.emf.cdo.spi.server.InternalLockManager; import org.eclipse.emf.cdo.spi.server.LongIDStore; import org.eclipse.emf.cdo.spi.server.StoreAccessorPool; @@ -757,9 +757,10 @@ public class MEMStore extends LongIDStore implements IMEMStore, BranchLoader, Du LockArea area = getLockArea(durableLockingID); Map<CDOID, LockGrade> locks = area.getLocks(); + InternalLockManager lockManager = getRepository().getLockManager(); for (Object objectToLock : objectsToLock) { - CDOID id = LockManager.getIDToLock(objectToLock); + CDOID id = lockManager.getLockKeyID(objectToLock); LockGrade grade = locks.get(id); if (grade != null) { @@ -779,9 +780,10 @@ public class MEMStore extends LongIDStore implements IMEMStore, BranchLoader, Du LockArea area = getLockArea(durableLockingID); Map<CDOID, LockGrade> locks = area.getLocks(); + InternalLockManager lockManager = getRepository().getLockManager(); for (Object objectToUnlock : objectsToUnlock) { - CDOID id = LockManager.getIDToLock(objectToUnlock); + CDOID id = lockManager.getLockKeyID(objectToUnlock); LockGrade grade = locks.get(id); if (grade != null) { diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockManager.java index a7a7c5cde3..e7bd2e6226 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockManager.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalLockManager.java @@ -50,6 +50,11 @@ public interface InternalLockManager extends IRWLockManager<Object, IView>, IDur /** * @since 4.0 */ + public CDOID getLockKeyID(Object key); + + /** + * @since 4.0 + */ public Map<CDOID, LockGrade> getLocks(IView view); /** diff --git a/plugins/org.eclipse.emf.cdo.tests.db4o/src/org/eclipse/emf/cdo/tests/db4o/AllTestsDB4O.java b/plugins/org.eclipse.emf.cdo.tests.db4o/src/org/eclipse/emf/cdo/tests/db4o/AllTestsDB4O.java index 87eb709960..16e0a77a7c 100644 --- a/plugins/org.eclipse.emf.cdo.tests.db4o/src/org/eclipse/emf/cdo/tests/db4o/AllTestsDB4O.java +++ b/plugins/org.eclipse.emf.cdo.tests.db4o/src/org/eclipse/emf/cdo/tests/db4o/AllTestsDB4O.java @@ -12,13 +12,24 @@ package org.eclipse.emf.cdo.tests.db4o; import org.eclipse.emf.cdo.server.IRepository; import org.eclipse.emf.cdo.server.IStore; +import org.eclipse.emf.cdo.server.internal.db4o.DB4OStore; import org.eclipse.emf.cdo.tests.AllConfigs; +import org.eclipse.emf.cdo.tests.BranchingSameSessionTest; +import org.eclipse.emf.cdo.tests.BranchingTest; +import org.eclipse.emf.cdo.tests.BranchingWithCacheClearTest; import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_261218_Test; +import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_324585_Test; import org.eclipse.emf.cdo.tests.config.impl.ConfigTest; import org.eclipse.emf.cdo.tests.config.impl.RepositoryConfig; +import org.eclipse.net4j.util.io.TMPUtil; + +import java.io.File; +import java.io.IOException; +import java.net.ServerSocket; import java.util.List; import java.util.Map; +import java.util.Random; import junit.framework.Test; import junit.framework.TestSuite; @@ -41,6 +52,12 @@ public class AllTestsDB4O extends AllConfigs // Added here testcases to skip // takes too much testClasses.remove(Bugzilla_261218_Test.class); + testClasses.remove(Bugzilla_324585_Test.class); + + // db4o doesn't support branching + testClasses.remove(BranchingTest.class); + testClasses.remove(BranchingSameSessionTest.class); + testClasses.remove(BranchingWithCacheClearTest.class); } @Override @@ -54,10 +71,14 @@ public class AllTestsDB4O extends AllConfigs */ public static class DB4ORepositoryConfig extends RepositoryConfig { + private static final Random RANDOM = new Random(System.currentTimeMillis()); + public static final DB4ORepositoryConfig INSTANCE = new DB4ORepositoryConfig("DB4O"); private static final long serialVersionUID = 1L; + private transient boolean optimizing = true; + public DB4ORepositoryConfig(String name) { super(name); @@ -74,8 +95,90 @@ public class AllTestsDB4O extends AllConfigs @Override protected IStore createStore(String repoName) { - MEMDB4OStore.clearContainer(); + File tempFolder = TMPUtil.getTempFolder(); + File file = new File(tempFolder, "cdodb_" + repoName + ".db4o"); + if (file.exists() && !isRestarting()) + { + file.delete(); + } + + int port = 0; + boolean ok = false; + do + { + ServerSocket sock = null; + try + { + port = 1024 + RANDOM.nextInt(65536 - 1024); + sock = new ServerSocket(port); + ok = true; + } + catch (IOException e) + { + } + finally + { + try + { + if (sock != null) + { + sock.close(); + } + } + catch (IOException e) + { + } + } + } while (!ok); + + IStore store = new DB4OStore(file.getPath(), port); + return store; + } + + @Override + protected boolean isOptimizing() + { + // Do NOT replace this with a hardcoded value! + return optimizing; + } + } + + public static class MemDB4ORepositoryConfig extends RepositoryConfig + { + public static final MemDB4ORepositoryConfig INSTANCE = new MemDB4ORepositoryConfig("DB4O"); + + private static final long serialVersionUID = 1L; + + private transient boolean optimizing = false; + + public MemDB4ORepositoryConfig(String name) + { + super(name); + } + + @Override + protected void initRepositoryProperties(Map<String, String> props) + { + super.initRepositoryProperties(props); + props.put(IRepository.Props.SUPPORTING_AUDITS, "false"); + props.put(IRepository.Props.SUPPORTING_BRANCHES, "false"); + } + + @Override + protected IStore createStore(String repoName) + { + if (!isRestarting()) + { + MEMDB4OStore.clearContainer(); + } return new MEMDB4OStore(); } + + @Override + protected boolean isOptimizing() + { + // Do NOT replace this with a hardcoded value! + return optimizing; + } } } |