You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by th...@apache.org on 2013/03/20 15:29:04 UTC
svn commit: r1458853 - in /jackrabbit/oak/trunk/oak-mongomk/src:
main/java/org/apache/jackrabbit/mongomk/prototype/
test/java/org/apache/jackrabbit/mongomk/prototype/
Author: thomasm
Date: Wed Mar 20 14:29:03 2013
New Revision: 1458853
URL: http://svn.apache.org/r1458853
Log:
OAK-619 Lock-free MongoMK implementation (fix node identifiers)
Modified:
jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/Commit.java
jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/MemoryDocumentStore.java
jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/MongoMK.java
jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/Node.java
jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/UpdateOp.java
jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/prototype/SimpleTest.java
Modified: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/Commit.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/Commit.java?rev=1458853&r1=1458852&r2=1458853&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/Commit.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/Commit.java Wed Mar 20 14:29:03 2013
@@ -59,8 +59,6 @@ public class Commit {
private HashSet<String> addedNodes = new HashSet<String>();
private HashSet<String> removedNodes = new HashSet<String>();
- private HashMap<String, Long> writeCounts = new HashMap<String, Long>();
-
Commit(MongoMK mk, Revision revision) {
this.revision = revision;
this.mk = mk;
@@ -92,8 +90,7 @@ public class Commit {
UpdateOp op = getUpdateOperationForNode(path);
String key = Utils.escapePropertyName(propertyName);
op.addMapEntry(key + "." + revision.toString(), value);
- long increment = mk.getWriteCountIncrement(path);
- op.increment(UpdateOp.WRITE_COUNT, 1 + increment);
+ op.setMapEntry(UpdateOp.LAST_REV + "." + revision.getClusterId(), revision.toString());
}
void addNode(Node n) {
@@ -169,7 +166,7 @@ public class Commit {
for (UpdateOp op : newNodes) {
op.unset(UpdateOp.ID);
op.addMapEntry(UpdateOp.DELETED + "." + revision.toString(), "false");
- op.increment(UpdateOp.WRITE_COUNT, 1);
+ op.setMapEntry(UpdateOp.LAST_REV + "." + revision.getClusterId(), revision.toString());
createOrUpdateNode(store, op);
}
}
@@ -182,8 +179,7 @@ public class Commit {
// finally write commit, unless it was already written
// with added nodes.
if (changedNodes.size() != 0 || !root.isNew) {
- long increment = mk.getWriteCountIncrement(commitRoot);
- root.increment(UpdateOp.WRITE_COUNT, 1 + increment);
+ root.setMapEntry(UpdateOp.LAST_REV + "." + revision.getClusterId(), revision.toString());
root.addMapEntry(UpdateOp.REVISIONS + "." + revision.toString(), "true");
createOrUpdateNode(store, root);
operations.put(commitRoot, root);
@@ -217,12 +213,7 @@ public class Commit {
}
}
// TODO detect conflicts here
- Long count = (Long) map.get(UpdateOp.WRITE_COUNT);
- if (count == null) {
- count = 0L;
- }
- String path = op.getPath();
- writeCounts.put(path, count);
+ op.setMapEntry(UpdateOp.LAST_REV + "." + revision.getClusterId(), revision.toString());
}
private UpdateOp[] splitDocument(Map<String, Object> map) {
@@ -243,9 +234,9 @@ public class Commit {
// ok
} else if (key.equals(UpdateOp.PREVIOUS)) {
// ok
- } else if (key.equals(UpdateOp.WRITE_COUNT)) {
- // only maintain the write count on the main document
- main.set(UpdateOp.WRITE_COUNT, e.getValue());
+ } else if (key.equals(UpdateOp.LAST_REV)) {
+ // only maintain the lastRev in the main document
+ main.setMapEntry(UpdateOp.LAST_REV + "." + revision.getClusterId(), revision.toString());
} else {
// UpdateOp.DELETED,
// UpdateOp.REVISIONS,
@@ -310,23 +301,8 @@ public class Commit {
boolean isNew = op != null && op.isNew;
boolean isWritten = op != null;
boolean isDelete = op != null && op.isDelete;
- long writeCountInc = mk.getWriteCountIncrement(path);
- Long writeCount = writeCounts.get(path);
- if (writeCount == null) {
- if (isNew) {
- writeCount = 0L;
- writeCountInc = 0;
- } else {
- writeCountInc++;
- String id = Utils.getIdFromPath(path);
- Map<String, Object> map = mk.getDocumentStore().find(Collection.NODES, id);
- Long oldWriteCount = (Long) map.get(UpdateOp.WRITE_COUNT);
- writeCount = oldWriteCount == null ? 0 : oldWriteCount;
- }
- }
mk.applyChanges(revision, path,
isNew, isDelete, isWritten,
- writeCount, writeCountInc,
added, removed);
}
}
@@ -369,8 +345,7 @@ public class Commit {
UpdateOp op = getUpdateOperationForNode(path);
op.setDelete(true);
op.addMapEntry(UpdateOp.DELETED + "." + revision.toString(), "true");
- long increment = mk.getWriteCountIncrement(path);
- op.increment(UpdateOp.WRITE_COUNT, 1 + increment);
+ op.setMapEntry(UpdateOp.LAST_REV + "." + revision.getClusterId(), revision.toString());
}
}
Modified: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/MemoryDocumentStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/MemoryDocumentStore.java?rev=1458853&r1=1458852&r2=1458853&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/MemoryDocumentStore.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/MemoryDocumentStore.java Wed Mar 20 14:29:03 2013
@@ -168,9 +168,16 @@ public class MemoryDocumentStore impleme
break;
}
case SET_MAP_ENTRY: {
- Map<String, Object> m = Utils.newMap();
- target.put(k, m);
+ Object old = target.get(kv[0]);
+ @SuppressWarnings("unchecked")
+ Map<String, Object> m = (Map<String, Object>) old;
+ if (m == null) {
+ m = Utils.newMap();
+ target.put(kv[0], m);
+ }
+ m.put(kv[1], op.value);
break;
+
}
}
}
Modified: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/MongoMK.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/MongoMK.java?rev=1458853&r1=1458852&r2=1458853&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/MongoMK.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/MongoMK.java Wed Mar 20 14:29:03 2013
@@ -121,9 +121,11 @@ public class MongoMK implements MicroKer
private final Cache<String, Node.Children> nodeChildrenCache;
/**
- * The unsaved write count increments.
+ * The unsaved last revisions.
+ * Key: path, value: revision.
*/
- private final Map<String, Long> writeCountIncrements = new HashMap<String, Long>();
+ private final Map<String, Revision> unsavedLastRevisions =
+ new HashMap<String, Revision>();
/**
* The last known head revision. This is the last-known revision.
@@ -131,6 +133,8 @@ public class MongoMK implements MicroKer
private Revision headRevision;
private Thread backgroundThread;
+
+ private int simpleRevisionCounter;
/**
* Maps branch commit revision to revision it is based on
@@ -179,11 +183,16 @@ public class MongoMK implements MicroKer
.build();
backgroundThread = new Thread(
- new BackgroundOperation(this, isDisposed),
- "MongoMK background thread");
+ new BackgroundOperation(this, isDisposed),
+ "MongoMK background thread");
backgroundThread.setDaemon(true);
backgroundThread.start();
- headRevision = Revision.newRevision(clusterId);
+
+ init();
+ }
+
+ void init() {
+ headRevision = newRevision();
Node n = readNode("/", headRevision);
if (n == null) {
// root node is missing: repository is not initialized
@@ -194,7 +203,15 @@ public class MongoMK implements MicroKer
}
}
+ void useSimpleRevisions() {
+ this.simpleRevisionCounter = 1;
+ init();
+ }
+
Revision newRevision() {
+ if (simpleRevisionCounter > 0) {
+ return new Revision(simpleRevisionCounter++, 0, clusterId);
+ }
return Revision.newRevision(clusterId);
}
@@ -359,11 +376,30 @@ public class MongoMK implements MicroKer
return null;
}
Node n = new Node(path, rev);
- Long w = writeCountIncrements.get(path);
- long writeCount = w == null ? 0 : w;
+ Revision lastRevision = null;
+ Revision revision = unsavedLastRevisions.get(path);
+ if (revision != null) {
+ if (isRevisionNewer(revision, rev)) {
+ // at most the read revision
+ revision = rev;
+ }
+ lastRevision = revision;
+ }
for (String key : map.keySet()) {
- if (key.equals(UpdateOp.WRITE_COUNT)) {
- writeCount += (Long) map.get(key);
+ if (key.equals(UpdateOp.LAST_REV)) {
+ Object v = map.get(key);
+ @SuppressWarnings("unchecked")
+ Map<String, String> valueMap = (Map<String, String>) v;
+ for (String r : valueMap.keySet()) {
+ revision = Revision.fromString(valueMap.get(r));
+ if (isRevisionNewer(revision, rev)) {
+ // at most the read revision
+ revision = rev;
+ }
+ if (lastRevision == null || isRevisionNewer(revision, lastRevision)) {
+ lastRevision = revision;
+ }
+ }
}
if (!Utils.isPropertyName(key)) {
continue;
@@ -377,7 +413,7 @@ public class MongoMK implements MicroKer
n.setProperty(propertyName, value);
}
}
- n.setWriteCount(writeCount);
+ n.setLastRevision(lastRevision);
return n;
}
@@ -565,7 +601,7 @@ public class MongoMK implements MicroKer
String message) throws MicroKernelException {
revisionId = revisionId == null ? headRevision.toString() : revisionId;
JsopReader t = new JsopTokenizer(json);
- Revision rev = Revision.newRevision(clusterId);
+ Revision rev = newRevision();
Commit commit = new Commit(this, rev);
while (true) {
int r = t.read();
@@ -880,19 +916,13 @@ public class MongoMK implements MicroKer
public void applyChanges(Revision rev, String path,
boolean isNew, boolean isDelete, boolean isWritten,
- long oldWriteCount, long writeCountInc,
ArrayList<String> added, ArrayList<String> removed) {
if (!isWritten) {
- if (writeCountInc == 0) {
- writeCountIncrements.remove(path);
- } else {
- writeCountIncrements.put(path, writeCountInc);
- }
+ unsavedLastRevisions.put(path, rev);
} else {
- writeCountIncrements.remove(path);
+ unsavedLastRevisions.remove(path);
}
- long newWriteCount = oldWriteCount + writeCountInc;
- Children c = nodeChildrenCache.getIfPresent(path + "@" + (newWriteCount - 1));
+ Children c = nodeChildrenCache.getIfPresent(path + "@" + rev);
if (isNew || (!isDelete && c != null)) {
String key = path + "@" + rev;
Children c2 = new Children(path, rev);
@@ -906,10 +936,5 @@ public class MongoMK implements MicroKer
nodeChildrenCache.put(key, c2);
}
}
-
- public long getWriteCountIncrement(String path) {
- Long x = writeCountIncrements.get(path);
- return x == null ? 0 : x;
- }
-
+
}
Modified: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/Node.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/Node.java?rev=1458853&r1=1458852&r2=1458853&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/Node.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/Node.java Wed Mar 20 14:29:03 2013
@@ -30,7 +30,7 @@ public class Node {
final String path;
final Revision rev;
final Map<String, String> properties = Utils.newMap();
- private long writeCount;
+ Revision lastRevision;
Node(String path, Revision rev) {
this.path = path;
@@ -61,7 +61,6 @@ public class Node {
StringBuilder buff = new StringBuilder();
buff.append("path: ").append(path).append('\n');
buff.append("rev: ").append(rev).append('\n');
- buff.append("writeCount: ").append(writeCount).append('\n');
buff.append(properties);
buff.append('\n');
return buff.toString();
@@ -75,6 +74,7 @@ public class Node {
UpdateOp op = new UpdateOp(path, id, isNew);
op.set(UpdateOp.ID, id);
op.addMapEntry(UpdateOp.DELETED + "." + rev.toString(), "false");
+ op.setMapEntry(UpdateOp.LAST_REV + "." + rev.getClusterId(), rev.toString());
for (String p : properties.keySet()) {
String key = Utils.escapePropertyName(p);
op.addMapEntry(key + "." + rev.toString(), properties.get(p));
@@ -83,7 +83,7 @@ public class Node {
}
public String getId() {
- return path + "@" + writeCount;
+ return path + "@" + lastRevision;
}
public void append(JsopWriter json, boolean includeId) {
@@ -94,27 +94,9 @@ public class Node {
json.key(p).encodedValue(properties.get(p));
}
}
-
- public void setWriteCount(long writeCount) {
- this.writeCount = writeCount;
- }
- public long getWriteCount() {
- return writeCount;
- }
-
- public int hashCode() {
- return (int) writeCount ^ properties.size() ^ rev.hashCode();
- }
-
- public boolean equals(Object obj) {
- if (obj == this) {
- return true;
- } else if (!(obj instanceof Node)) {
- return false;
- }
- Node other = (Node) obj;
- return writeCount == other.writeCount;
+ public void setLastRevision(Revision lastRevision) {
+ this.lastRevision = lastRevision;
}
/**
Modified: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/UpdateOp.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/UpdateOp.java?rev=1458853&r1=1458852&r2=1458853&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/UpdateOp.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/prototype/UpdateOp.java Wed Mar 20 14:29:03 2013
@@ -31,13 +31,13 @@ public class UpdateOp {
static final String ID = "_id";
/**
- * The number of write operations to this node.
+ * The last revision. Key: machine id, value: revision.
*/
- static final String WRITE_COUNT = "_writeCount";
+ static final String LAST_REV = "_lastRev";
/**
- * The list of recent revisions against this node, where this node is the
- * root of the commit.
+ * The list of recent revisions for this node, where this node is the
+ * root of the commit. Key: revision, value: true.
*/
static final String REVISIONS = "_revisions";
@@ -56,9 +56,13 @@ public class UpdateOp {
static final String PREVIOUS = "_prev";
/**
- * Whether this node is
+ * Whether this node is deleted. Key: revision, value: true/false.
*/
static final String DELETED = "_deleted";
+
+ /**
+ * The modified time (5 second resolution).
+ */
static final String MODIFIED = "_modified";
final String path;
Modified: jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/prototype/SimpleTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/prototype/SimpleTest.java?rev=1458853&r1=1458852&r2=1458853&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/prototype/SimpleTest.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/prototype/SimpleTest.java Wed Mar 20 14:29:03 2013
@@ -94,6 +94,41 @@ public class SimpleTest {
}
@Test
+ public void nodeIdentifier() {
+ MongoMK mk = createMK();
+ mk.useSimpleRevisions();
+
+ String rev0 = mk.getHeadRevision();
+ String rev1 = mk.commit("/", "+\"test\":{}", null, null);
+ String rev2 = mk.commit("/test", "+\"a\":{}", null, null);
+ String rev3 = mk.commit("/test", "+\"b\":{}", null, null);
+ String rev4 = mk.commit("/test", "^\"a/x\":1", null, null);
+
+ String r0 = mk.getNodes("/", rev0, 0, 0, Integer.MAX_VALUE, ":id");
+ assertEquals("{\":id\":\"/@r0000001000-0\",\":childNodeCount\":0}", r0);
+ String r1 = mk.getNodes("/", rev1, 0, 0, Integer.MAX_VALUE, ":id");
+ assertEquals("{\":id\":\"/@r0000002000-0\",\"test\":{},\":childNodeCount\":1}", r1);
+ String r2 = mk.getNodes("/", rev2, 0, 0, Integer.MAX_VALUE, ":id");
+ assertEquals("{\":id\":\"/@r0000003000-0\",\"test\":{},\":childNodeCount\":1}", r2);
+ String r3;
+ r3 = mk.getNodes("/", rev3, 0, 0, Integer.MAX_VALUE, ":id");
+ assertEquals("{\":id\":\"/@r0000004000-0\",\"test\":{},\":childNodeCount\":1}", r3);
+ r3 = mk.getNodes("/test", rev3, 0, 0, Integer.MAX_VALUE, ":id");
+ assertEquals("{\":id\":\"/test@r0000004000-0\",\"a\":{},\"b\":{},\":childNodeCount\":2}", r3);
+ String r4;
+ r4 = mk.getNodes("/", rev4, 0, 0, Integer.MAX_VALUE, ":id");
+ assertEquals("{\":id\":\"/@r0000005000-0\",\"test\":{},\":childNodeCount\":1}", r4);
+ r4 = mk.getNodes("/test", rev4, 0, 0, Integer.MAX_VALUE, ":id");
+ assertEquals("{\":id\":\"/test@r0000005000-0\",\"a\":{},\"b\":{},\":childNodeCount\":2}", r4);
+ r4 = mk.getNodes("/test/a", rev4, 0, 0, Integer.MAX_VALUE, ":id");
+ assertEquals("{\":id\":\"/test/a@r0000005000-0\",\"x\":1,\":childNodeCount\":0}", r4);
+ r4 = mk.getNodes("/test/b", rev4, 0, 0, Integer.MAX_VALUE, ":id");
+ assertEquals("{\":id\":\"/test/b@r0000004000-0\",\":childNodeCount\":0}", r4);
+
+ mk.dispose();
+ }
+
+ @Test
@Ignore
public void diff() {
MongoMK mk = createMK();
@@ -289,7 +324,7 @@ public class SimpleTest {
}
@Test
- public void testAddAndMove() {
+ public void addAndMove() {
MongoMK mk = createMK();
String head = mk.getHeadRevision();