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 md...@apache.org on 2014/12/01 15:34:19 UTC

svn commit: r1642692 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/kernel/ main/java/org/apache/jackrabbit/oak/plugins/document/ main/java/org/apache/jackrabbit/oak/plugins/memory/ main/java/org/apache/jackrabbit/oak/plug...

Author: mduerig
Date: Mon Dec  1 14:34:19 2014
New Revision: 1642692

URL: http://svn.apache.org/r1642692
Log:
OAK-2291: Associate user defined values with checkpoint
Initial implementation

Added:
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/CheckpointTest.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeStore.java
    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/spi/state/NodeStore.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ProxyNodeStore.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/NodeStoreFixture.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java?rev=1642692&r1=1642691&r2=1642692&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java Mon Dec  1 14:34:19 2014
@@ -22,6 +22,8 @@ import static com.google.common.base.Pre
 import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Collections;
+import java.util.Map;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
@@ -211,12 +213,26 @@ public class KernelNodeStore implements 
         }
     }
 
+
+    @Nonnull
+    @Override
+    public String checkpoint(long lifetime, @Nonnull Map<String, String> properties) {
+        throw new UnsupportedOperationException("MicroKernel based NodeStore implementations do " +
+                "not support checkpoint metadata");
+    }
+
     @Override @Nonnull
     public String checkpoint(long lifetime) {
         checkArgument(lifetime > 0);
         return kernel.checkpoint(lifetime);
     }
 
+    @Nonnull
+    @Override
+    public Map<String, String> checkpointInfo(@Nonnull String checkpoint) {
+        return Collections.emptyMap();
+    }
+
     @Override @CheckForNull
     public NodeState retrieve(@Nonnull String checkpoint) {
         try {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java?rev=1642692&r1=1642691&r2=1642692&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java Mon Dec  1 14:34:19 2014
@@ -1364,10 +1364,22 @@ public final class DocumentNodeStore
 
     @Nonnull
     @Override
+    public String checkpoint(long lifetime, @Nonnull Map<String, String> properties) {
+        throw new UnsupportedOperationException();  // FIXME implement. See OAK-2291
+    }
+
+    @Nonnull
+    @Override
     public String checkpoint(long lifetime) {
         return checkpoints.create(lifetime).toString();
     }
 
+    @Nonnull
+    @Override
+    public Map<String, String> checkpointInfo(@Nonnull String checkpoint) {
+        throw new UnsupportedOperationException();  // FIXME implement. See OAK-2291
+    }
+
     @CheckForNull
     @Override
     public NodeState retrieve(@Nonnull String checkpoint) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeStore.java?rev=1642692&r1=1642691&r2=1642692&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeStore.java Mon Dec  1 14:34:19 2014
@@ -26,6 +26,7 @@ import static org.apache.jackrabbit.oak.
 import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Collections;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicReference;
@@ -34,6 +35,7 @@ import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import com.google.common.collect.Maps;
 import com.google.common.io.ByteStreams;
 
 import org.apache.jackrabbit.oak.api.Blob;
@@ -56,7 +58,7 @@ public class MemoryNodeStore implements 
 
     private final AtomicReference<NodeState> root;
 
-    private final Map<String, NodeState> checkpoints = newHashMap();
+    private final Map<String, Checkpoint> checkpoints = newHashMap();
 
     private final Map<Closeable, Observer> observers = newHashMap();
 
@@ -187,17 +189,40 @@ public class MemoryNodeStore implements 
         return null;
     }
 
-    @Override @Nonnull
-    public synchronized String checkpoint(long lifetime) {
+    @Nonnull
+    @Override
+    public String checkpoint(long lifetime, @Nonnull Map<String, String> properties) {
         checkArgument(lifetime > 0);
+        checkNotNull(properties);
         String checkpoint = "checkpoint" + checkpoints.size();
-        checkpoints.put(checkpoint, getRoot());
+        checkpoints.put(checkpoint, new Checkpoint(getRoot(), properties));
         return checkpoint;
     }
 
+    @Override @Nonnull
+    public synchronized String checkpoint(long lifetime) {
+        return checkpoint(lifetime, Collections.<String, String>emptyMap());
+    }
+
+    @Nonnull
+    @Override
+    public Map<String, String> checkpointInfo(@Nonnull String checkpoint) {
+        Checkpoint cp = checkpoints.get(checkNotNull(checkpoint));
+        if (cp == null) {
+            return Collections.emptyMap();
+        } else {
+            return cp.getProperties();
+        }
+    }
+
     @Override @CheckForNull
     public synchronized NodeState retrieve(@Nonnull String checkpoint) {
-        return checkpoints.get(checkNotNull(checkpoint));
+        Checkpoint cp = checkpoints.get(checkNotNull(checkpoint));
+        if (cp == null) {
+            return null;
+        } else {
+            return cp.getRoot();
+        }
     }
 
     @Override
@@ -281,4 +306,21 @@ public class MemoryNodeStore implements 
         }
     }
 
+    private static class Checkpoint {
+        private final NodeState root;
+        private final Map<String, String> properties;
+
+        private Checkpoint(NodeState root, Map<String, String> properties) {
+            this.root = root;
+            this.properties = Maps.newHashMap(properties);
+        }
+
+        public NodeState getRoot() {
+            return root;
+        }
+
+        public Map<String, String> getProperties() {
+            return properties;
+        }
+    }
 }

Modified: 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=1642692&r1=1642691&r2=1642692&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStore.java Mon Dec  1 14:34:19 2014
@@ -22,11 +22,15 @@ import static java.lang.System.currentTi
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.NANOSECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.apache.jackrabbit.oak.api.Type.STRING;
 import static org.apache.jackrabbit.oak.plugins.segment.Record.fastEquals;
 
 import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Random;
 import java.util.UUID;
 import java.util.concurrent.Semaphore;
@@ -35,6 +39,7 @@ import java.util.concurrent.atomic.Atomi
 import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 
+import com.google.common.collect.Maps;
 import org.apache.jackrabbit.oak.api.Blob;
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.PropertyState;
@@ -210,9 +215,11 @@ public class SegmentNodeStore implements
                 "without specifying BlobStore");
     }
 
-    @Override @Nonnull
-    public synchronized String checkpoint(long lifetime) {
+    @Nonnull
+    @Override
+    public String checkpoint(long lifetime, @Nonnull Map<String, String> properties) {
         checkArgument(lifetime > 0);
+        checkNotNull(properties);
         String name = UUID.randomUUID().toString();
         long now = System.currentTimeMillis();
 
@@ -239,6 +246,12 @@ public class SegmentNodeStore implements
                     NodeBuilder cp = checkpoints.child(name);
                     cp.setProperty("timestamp",  now + lifetime);
                     cp.setProperty("created", now);
+
+                    NodeBuilder props = cp.setChildNode("properties");
+                    for (Entry<String, String> p : properties.entrySet()) {
+                        props.setProperty(p.getKey(), p.getValue());
+                    }
+
                     cp.setChildNode(ROOT, state.getChildNode(ROOT));
 
                     SegmentNodeState newState = builder.getNodeState();
@@ -261,6 +274,28 @@ public class SegmentNodeStore implements
         return name;
     }
 
+    @Override @Nonnull
+    public synchronized String checkpoint(long lifetime) {
+        return checkpoint(lifetime, Collections.<String, String>emptyMap());
+    }
+
+    @Nonnull
+    @Override
+    public Map<String, String> checkpointInfo(@Nonnull String checkpoint) {
+        Map<String, String> properties = Maps.newHashMap();
+        checkNotNull(checkpoint);
+        NodeState cp = head.get()
+                .getChildNode("checkpoints")
+                .getChildNode(checkpoint)
+                .getChildNode("properties");
+
+        for (PropertyState prop : cp.getProperties()) {
+            properties.put(prop.getName(), prop.getValue(STRING));
+        }
+
+        return properties;
+    }
+
     @Override @CheckForNull
     public NodeState retrieve(@Nonnull String checkpoint) {
         checkNotNull(checkpoint);

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeStore.java?rev=1642692&r1=1642691&r2=1642692&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeStore.java Mon Dec  1 14:34:19 2014
@@ -18,6 +18,7 @@ package org.apache.jackrabbit.oak.spi.st
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Map;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
@@ -116,6 +117,27 @@ public interface NodeStore {
      * remains valid for at least as long as requested and allows that state
      * of the repository to be retrieved using the returned opaque string
      * reference.
+     * <p>
+     * The {@code properties} passed to this methods are associated with the
+     * checkpoint and can be retrieved through the {@link #checkpointInfo(String)}
+     * method. Its semantics is entirely application specific.
+     *
+     * @param lifetime time (in milliseconds, &gt; 0) that the checkpoint
+     *                 should remain available
+     * @param properties properties to associate with the checkpoint
+     * @return string reference of this checkpoint
+     */
+    @Nonnull
+    String checkpoint(long lifetime, @Nonnull Map<String, String> properties);
+
+    /**
+     * Creates a new checkpoint of the latest root of the tree. The checkpoint
+     * remains valid for at least as long as requested and allows that state
+     * of the repository to be retrieved using the returned opaque string
+     * reference.
+     * <p>
+     * This method is a shortcut for {@link #checkpoint(long, Map)} passing
+     * an empty map for its 2nd argument.
      *
      * @param lifetime time (in milliseconds, &gt; 0) that the checkpoint
      *                 should remain available
@@ -125,6 +147,17 @@ public interface NodeStore {
     String checkpoint(long lifetime);
 
     /**
+     * Retrieve the properties associated with a checkpoint.
+     *
+     * @param checkpoint string reference of a checkpoint
+     * @return the properties associated with the checkpoint referenced by
+     *         {@code checkpoint} or an empty map when there is no such
+     *         checkpoint.
+     */
+    @Nonnull
+    Map<String, String> checkpointInfo(@Nonnull String checkpoint);
+
+    /**
      * Retrieves the root node from a previously created repository checkpoint.
      *
      * @param checkpoint string reference of a checkpoint

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ProxyNodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ProxyNodeStore.java?rev=1642692&r1=1642691&r2=1642692&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ProxyNodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ProxyNodeStore.java Mon Dec  1 14:34:19 2014
@@ -18,6 +18,7 @@ package org.apache.jackrabbit.oak.spi.st
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Map;
 
 import javax.annotation.Nonnull;
 
@@ -62,11 +63,23 @@ public abstract class ProxyNodeStore imp
         return getNodeStore().getBlob(reference);
     }
 
+    @Nonnull
+    @Override
+    public String checkpoint(long lifetime, @Nonnull Map<String, String> properties) {
+        return getNodeStore().checkpoint(lifetime, properties);
+    }
+
     @Override
     public String checkpoint(long lifetime) {
         return getNodeStore().checkpoint(lifetime);
     }
 
+    @Nonnull
+    @Override
+    public Map<String, String> checkpointInfo(@Nonnull String checkpoint) {
+        return getNodeStore().checkpointInfo(checkpoint);
+    }
+
     @Override
     public NodeState retrieve(String checkpoint) {
         return getNodeStore().retrieve(checkpoint);

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/NodeStoreFixture.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/NodeStoreFixture.java?rev=1642692&r1=1642691&r2=1642692&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/NodeStoreFixture.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/NodeStoreFixture.java Mon Dec  1 14:34:19 2014
@@ -24,6 +24,7 @@ import java.io.IOException;
 import org.apache.jackrabbit.oak.kernel.KernelNodeStore;
 import org.apache.jackrabbit.oak.plugins.document.DocumentMK;
 import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
 import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStore;
 import org.apache.jackrabbit.oak.plugins.segment.memory.MemoryStore;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
@@ -91,6 +92,16 @@ public abstract class NodeStoreFixture {
         }
     };
 
+    public static final NodeStoreFixture MEMORY_NS = new NodeStoreFixture() {
+        @Override
+        public NodeStore createNodeStore() {
+            return new MemoryNodeStore();
+        }
+
+        @Override
+        public void dispose(NodeStore nodeStore) { }
+    };
+
     public abstract NodeStore createNodeStore();
 
     public abstract void dispose(NodeStore nodeStore);

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/CheckpointTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/CheckpointTest.java?rev=1642692&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/CheckpointTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/CheckpointTest.java Mon Dec  1 14:34:19 2014
@@ -0,0 +1,116 @@
+/*
+ * 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.kernel;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+import static org.junit.runners.Parameterized.Parameters;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.jackrabbit.oak.NodeStoreFixture;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(value = Parameterized.class)
+public class CheckpointTest {
+
+    @Parameters
+    public static Collection<Object[]> fixtures() {
+        Object[][] fixtures = new Object[][] {
+                {NodeStoreFixture.MONGO_MK},
+                {NodeStoreFixture.MONGO_NS},
+                {NodeStoreFixture.SEGMENT_MK},
+                {NodeStoreFixture.MEMORY_NS},
+        };
+        return Arrays.asList(fixtures);
+    }
+
+    private final NodeStoreFixture fixture;
+
+    private NodeStore store;
+
+    private NodeState root;
+
+    public CheckpointTest(NodeStoreFixture fixture) {
+        this.fixture = fixture;
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        store = fixture.createNodeStore();
+        NodeBuilder builder = store.getRoot().builder();
+        NodeBuilder test = builder.child("test");
+        test.setProperty("a", 1);
+        test.setProperty("b", 2);
+        test.setProperty("c", 3);
+        test.child("x");
+        test.child("y");
+        test.child("z");
+        root = store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        fixture.dispose(store);
+    }
+
+    @Test
+    public void checkpoint() throws CommitFailedException {
+        String cp = store.checkpoint(Long.MAX_VALUE);
+
+        NodeBuilder builder = store.getRoot().builder();
+        builder.setChildNode("new");
+        store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+        assertFalse(root.equals(store.getRoot()));
+        assertEquals(root, store.retrieve(cp));
+
+        assertTrue(store.release(cp));
+        if (fixture != NodeStoreFixture.MONGO_MK && fixture != NodeStoreFixture.MONGO_NS) {
+            assertNull(store.retrieve(cp));
+        }
+    }
+
+    @Test
+    public void checkpointInfo() throws CommitFailedException {
+        // FIXME implement. See OAK-2291
+        assumeTrue(fixture != NodeStoreFixture.MONGO_MK && fixture != NodeStoreFixture.MONGO_NS);
+        ImmutableMap<String, String> props = ImmutableMap.of(
+                "one", "1", "two", "2", "three", "2");
+        String cp = store.checkpoint(Long.MAX_VALUE, props);
+        assertEquals(props, store.checkpointInfo(cp));
+    }
+
+}