Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java (revision 1762289) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java (working copy) @@ -72,6 +72,7 @@ import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import com.google.common.cache.Cache; +import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.util.concurrent.UncheckedExecutionException; @@ -1657,6 +1658,24 @@ } } + @Nonnull + @Override + public Iterable checkpoints() { + final long now = clock.getTime(); + return Iterables.transform(Iterables.filter(checkpoints.getCheckpoints().entrySet(), + new Predicate>() { + @Override + public boolean apply(Map.Entry cp) { + return cp.getValue().getExpiryTime() > now; + } + }), new Function, String>() { + @Override + public String apply(Map.Entry cp) { + return cp.getKey().toString(); + } + }); + } + @CheckForNull @Override public NodeState retrieve(@Nonnull String checkpoint) { Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeStore.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeStore.java (revision 1762289) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeStore.java (working copy) @@ -36,7 +36,9 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import com.google.common.io.ByteStreams; import org.apache.jackrabbit.oak.api.Blob; @@ -221,6 +223,12 @@ } } + @Nonnull + @Override + public synchronized Iterable checkpoints() { + return Lists.newArrayList(checkpoints.keySet()); + } + @Override @CheckForNull public synchronized NodeState retrieve(@Nonnull String checkpoint) { Checkpoint cp = checkpoints.get(checkNotNull(checkpoint)); @@ -238,8 +246,8 @@ } /** test purpose only! */ - public synchronized Set listCheckpoints() { - return checkpoints.keySet(); + public Set listCheckpoints() { + return Sets.newHashSet(checkpoints()); } //------------------------------------------------------------< private >--- Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeStore.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeStore.java (revision 1762289) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeStore.java (working copy) @@ -158,6 +158,14 @@ Map checkpointInfo(@Nonnull String checkpoint); /** + * Returns all currently valid checkpoints. + * + * @return valid checkpoints. + */ + @Nonnull + Iterable checkpoints(); + + /** * Retrieves the root node from a previously created repository checkpoint. * * @param checkpoint string reference of a checkpoint Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ProxyNodeStore.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ProxyNodeStore.java (revision 1762289) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ProxyNodeStore.java (working copy) @@ -80,7 +80,13 @@ return getNodeStore().checkpointInfo(checkpoint); } + @Nonnull @Override + public Iterable checkpoints() { + return getNodeStore().checkpoints(); + } + + @Override public NodeState retrieve(String checkpoint) { return getNodeStore().retrieve(checkpoint); } Index: oak-it/src/test/java/org/apache/jackrabbit/oak/spi/state/NodeStoreTest.java =================================================================== --- oak-it/src/test/java/org/apache/jackrabbit/oak/spi/state/NodeStoreTest.java (revision 1762289) +++ oak-it/src/test/java/org/apache/jackrabbit/oak/spi/state/NodeStoreTest.java (working copy) @@ -32,6 +32,8 @@ import java.util.Arrays; import java.util.Calendar; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; @@ -39,6 +41,10 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; +import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + import org.apache.jackrabbit.oak.NodeStoreFixtures; import org.apache.jackrabbit.oak.OakBaseTest; import org.apache.jackrabbit.oak.api.CommitFailedException; @@ -547,6 +553,33 @@ assertTrue(root.hasChildNode("bar")); } + @Test + public void checkpoints() throws Exception { + assumeTrue(fixture != NodeStoreFixtures.SEGMENT_TAR); + int numCps = 3; + Map info = Maps.newHashMap(); + Set cps = Sets.newHashSet(); + for (int i = 0; i < numCps; i++) { + info.put("key", "" + i); + cps.add(store.checkpoint(TimeUnit.HOURS.toMillis(1), info)); + } + assertEquals(numCps, cps.size()); + assertEquals(cps, Sets.newHashSet(store.checkpoints())); + Set keys = Sets.newHashSet(); + for (String cp : cps) { + info = store.checkpointInfo(cp); + assertTrue(info.containsKey("key")); + keys.add(info.get("key")); + } + assertEquals(Sets.newHashSet("0", "1", "2"), keys); + while (!cps.isEmpty()) { + String cp = cps.iterator().next(); + cps.remove(cp); + store.release(cp); + assertEquals(cps.size(), Iterables.size(store.checkpoints())); + } + } + private void compareAgainstBaseState(int childNodeCount) throws CommitFailedException { NodeState before = store.getRoot(); NodeBuilder builder = before.builder(); Index: oak-segment/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStore.java =================================================================== --- oak-segment/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStore.java (revision 1762289) +++ oak-segment/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStore.java (working copy) @@ -462,6 +462,12 @@ return properties; } + @Nonnull + @Override + public Iterable checkpoints() { + return getCheckpoints().getChildNodeNames(); + } + @Override @CheckForNull public NodeState retrieve(@Nonnull String checkpoint) { checkNotNull(checkpoint); Index: oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/TarNodeStore.java =================================================================== --- oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/TarNodeStore.java (revision 1762289) +++ oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/TarNodeStore.java (working copy) @@ -100,7 +100,13 @@ return ns.checkpointInfo(checkpoint); } + @Nonnull @Override + public Iterable checkpoints() { + return ns.checkpoints(); + } + + @Override public NodeState retrieve(@Nonnull String checkpoint) { return ns.retrieve(checkpoint); }