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 ju...@apache.org on 2013/02/11 09:57:02 UTC
svn commit: r1444682 - in
/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment:
SegmentNodeStore.java SegmentNodeStoreBranch.java
Author: jukka
Date: Mon Feb 11 08:57:02 2013
New Revision: 1444682
URL: http://svn.apache.org/r1444682
Log:
OAK-593: Segment-based MK
Simple segment-based NodeStore implementation
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStore.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreBranch.java
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStore.java?rev=1444682&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStore.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStore.java Mon Feb 11 08:57:02 2013
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.segment;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.api.Blob;
+import org.apache.jackrabbit.oak.spi.commit.CommitHook;
+import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.jackrabbit.oak.spi.state.NodeStoreBranch;
+
+public class SegmentNodeStore implements NodeStore {
+
+ private final SegmentStore store;
+
+ private final SegmentReader reader;
+
+ private CommitHook hook = new EmptyHook();
+
+ public SegmentNodeStore(SegmentStore store) {
+ this.store = store;
+ this.reader = new SegmentReader(store);
+ }
+
+ @Override @Nonnull
+ public NodeState getRoot() {
+ return new SegmentNodeState(reader, store.getJournalHead());
+ }
+
+ @Override @Nonnull
+ public NodeStoreBranch branch() {
+ return new SegmentNodeStoreBranch(store, reader, hook);
+ }
+
+ @Override
+ public Blob createBlob(InputStream stream) throws IOException {
+ SegmentWriter writer = new SegmentWriter(store);
+ RecordId recordId = writer.writeStream(stream);
+ writer.flush();
+ return new SegmentBlob(reader, recordId);
+ }
+
+ public void setHook(CommitHook hook) {
+ this.hook = hook;
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreBranch.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreBranch.java?rev=1444682&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreBranch.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreBranch.java Mon Feb 11 08:57:02 2013
@@ -0,0 +1,269 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.segment;
+
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeBuilder;
+import org.apache.jackrabbit.oak.spi.commit.CommitHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
+import org.apache.jackrabbit.oak.spi.state.NodeStoreBranch;
+
+class SegmentNodeStoreBranch implements NodeStoreBranch {
+
+ private final SegmentStore store;
+
+ private final SegmentReader reader;
+
+ private final SegmentWriter writer;
+
+ private final CommitHook hook;
+
+ private RecordId baseId;
+
+ private RecordId rootId;
+
+ SegmentNodeStoreBranch(
+ SegmentStore store, SegmentReader reader, CommitHook hook) {
+ this.store = store;
+ this.reader = reader;
+ this.writer = new SegmentWriter(store);
+ this.hook = hook;
+ this.baseId = store.getJournalHead();
+ this.rootId = baseId;
+ }
+
+ @Override @Nonnull
+ public NodeState getBase() {
+ return new SegmentNodeState(reader, baseId);
+ }
+
+ @Override @Nonnull
+ public synchronized NodeState getRoot() {
+ return new SegmentNodeState(reader, rootId);
+ }
+
+ @Override
+ public synchronized void setRoot(NodeState newRoot) {
+ this.rootId = writer.writeNode(newRoot);
+ writer.flush();
+ }
+
+ // FIXME: Proper rebase needed
+ private class RebaseDiff implements NodeStateDiff {
+
+ private final NodeBuilder builder;
+
+ RebaseDiff(NodeBuilder builder) {
+ this.builder = builder;
+ }
+
+ @Override
+ public void propertyAdded(PropertyState after) {
+ PropertyState other = builder.getProperty(after.getName());
+ if (other == null) {
+ builder.setProperty(after);
+ } else if (!other.equals(after)) {
+ conflictMarker("addExistingProperty").setProperty(after);
+ }
+ }
+
+ @Override
+ public void propertyChanged(PropertyState before, PropertyState after) {
+ PropertyState other = builder.getProperty(before.getName());
+ if (other == null) {
+ conflictMarker("changeDeletedProperty").setProperty(after);
+ } else if (other.equals(before)) {
+ builder.setProperty(after);
+ } else if (!other.equals(after)) {
+ conflictMarker("changeChangedProperty").setProperty(after);
+ }
+ }
+
+ @Override
+ public void propertyDeleted(PropertyState before) {
+ PropertyState other = builder.getProperty(before.getName());
+ if (other == null) {
+ conflictMarker("deleteDeletedProperty").setProperty(before);
+ } else if (other.equals(before)) {
+ builder.removeProperty(before.getName());
+ } else {
+ conflictMarker("deleteChangedProperty").setProperty(before);
+ }
+ }
+
+ @Override
+ public void childNodeAdded(String name, NodeState after) {
+ if (builder.hasChildNode(name)) {
+ conflictMarker("addExistingNode").setNode(name, after);
+ } else {
+ builder.setNode(name, after);
+ }
+ }
+
+ @Override
+ public void childNodeChanged(
+ String name, NodeState before, NodeState after) {
+ if (builder.hasChildNode(name)) {
+ after.compareAgainstBaseState(
+ before, new RebaseDiff(builder.child(name)));
+ } else {
+ conflictMarker("changeDeletedNode").setNode(name, after);
+ }
+ }
+
+ @Override
+ public void childNodeDeleted(String name, NodeState before) {
+ if (!builder.hasChildNode(name)) {
+ conflictMarker("deleteDeletedNode").setNode(name, before);
+ } else if (before.equals(builder.child(name).getNodeState())) {
+ builder.removeNode(name);
+ } else {
+ conflictMarker("deleteChangedNode").setNode(name, before);
+ }
+ }
+
+ private NodeBuilder conflictMarker(String name) {
+ return builder.child(":conflict").child(name);
+ }
+
+ }
+
+ @Override
+ public synchronized void rebase() {
+ RecordId newBaseId = store.getJournalHead();
+ NodeBuilder builder =
+ new MemoryNodeBuilder(new SegmentNodeState(reader, newBaseId));
+ getRoot().compareAgainstBaseState(getBase(), new RebaseDiff(builder));
+ this.baseId = newBaseId;
+ this.rootId = writer.writeNode(builder.getNodeState());
+ writer.flush();
+ }
+
+ @Override @Nonnull
+ public synchronized NodeState merge() throws CommitFailedException {
+ RecordId originalBaseId = baseId;
+ RecordId originalRootId = rootId;
+ for (int i = 0; i < 10; i++) {
+ if (i > 0) {
+ baseId = originalBaseId;
+ rootId = originalRootId;
+ rebase();
+ }
+ RecordId headId =
+ writer.writeNode(hook.processCommit(getBase(), getRoot()));
+ writer.flush();
+ if (store.setJournalHead(rootId, baseId)) {
+ baseId = headId;
+ rootId = headId;
+ return getRoot();
+ }
+ }
+ throw new CommitFailedException();
+ }
+
+ @Override
+ public boolean move(String source, String target) {
+ if (PathUtils.isAncestor(source, target)) {
+ return false;
+ } else if (source.equals(target)) {
+ return true;
+ }
+
+ NodeBuilder builder = getRoot().builder();
+
+ NodeBuilder targetBuilder = builder;
+ String targetParent = PathUtils.getParentPath(target);
+ for (String name : PathUtils.elements(targetParent)) {
+ if (targetBuilder.hasChildNode(name)) {
+ targetBuilder = targetBuilder.child(name);
+ } else {
+ return false;
+ }
+ }
+ String targetName = PathUtils.getName(target);
+ if (targetBuilder.hasChildNode(targetName)) {
+ return false;
+ }
+
+ NodeBuilder sourceBuilder = builder;
+ String sourceParent = PathUtils.getParentPath(source);
+ for (String name : PathUtils.elements(sourceParent)) {
+ if (sourceBuilder.hasChildNode(name)) {
+ sourceBuilder = sourceBuilder.child(name);
+ } else {
+ return false;
+ }
+ }
+ String sourceName = PathUtils.getName(source);
+ if (!sourceBuilder.hasChildNode(sourceName)) {
+ return false;
+ }
+
+ NodeState sourceState = sourceBuilder.child(sourceName).getNodeState();
+ targetBuilder.setNode(targetName, sourceState);
+ sourceBuilder.removeNode(sourceName);
+
+ setRoot(builder.getNodeState());
+ return true;
+ }
+
+ @Override
+ public boolean copy(String source, String target) {
+ NodeBuilder builder = getRoot().builder();
+
+ NodeBuilder targetBuilder = builder;
+ String targetParent = PathUtils.getParentPath(target);
+ for (String name : PathUtils.elements(targetParent)) {
+ if (targetBuilder.hasChildNode(name)) {
+ targetBuilder = targetBuilder.child(name);
+ } else {
+ return false;
+ }
+ }
+ String targetName = PathUtils.getName(target);
+ if (targetBuilder.hasChildNode(targetName)) {
+ return false;
+ }
+
+ NodeBuilder sourceBuilder = builder;
+ String sourceParent = PathUtils.getParentPath(source);
+ for (String name : PathUtils.elements(sourceParent)) {
+ if (sourceBuilder.hasChildNode(name)) {
+ sourceBuilder = sourceBuilder.child(name);
+ } else {
+ return false;
+ }
+ }
+ String sourceName = PathUtils.getName(source);
+ if (!sourceBuilder.hasChildNode(sourceName)) {
+ return false;
+ }
+
+ NodeState sourceState = sourceBuilder.child(sourceName).getNodeState();
+ targetBuilder.setNode(targetName, sourceState);
+
+ setRoot(builder.getNodeState());
+ return true;
+ }
+
+}