Index: oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Checkpoints.java =================================================================== --- oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Checkpoints.java (revision 1886124) +++ oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Checkpoints.java (working copy) @@ -79,11 +79,9 @@ createIfNotExist(); } - public Revision create(long lifetimeInMillis, Map info) { - // create a unique dummy commit we can use as checkpoint revision - Revision r = nodeStore.commitQueue.createRevision(); + public Revision create(Revision revision, long lifetimeInMillis, Map info) { final RevisionVector[] rv = new RevisionVector[1]; - nodeStore.commitQueue.done(r, new CommitQueue.Callback() { + nodeStore.commitQueue.done(revision, new CommitQueue.Callback() { @Override public void headOfQueue(@NotNull Revision revision) { rv[0] = nodeStore.getHeadRevision(); @@ -95,11 +93,17 @@ long endTime = BigInteger.valueOf(nodeStore.getClock().getTime()) .add(BigInteger.valueOf(lifetimeInMillis)) .min(BigInteger.valueOf(Long.MAX_VALUE)).longValue(); - op.setMapEntry(PROP_CHECKPOINT, r, new Info(endTime, rv[0], info).toString()); + op.setMapEntry(PROP_CHECKPOINT, revision, new Info(endTime, rv[0], info).toString()); store.createOrUpdate(Collection.SETTINGS, op); - return r; + return revision; } + public Revision create(long lifetimeInMillis, Map info) { + // create a unique dummy commit we can use as checkpoint revision + Revision r = nodeStore.commitQueue.createRevision(); + return create(r, lifetimeInMillis, info); + } + public void release(String checkpoint) { UpdateOp op = new UpdateOp(ID, false); op.removeMapEntry(PROP_CHECKPOINT, Revision.fromString(checkpoint)); Index: oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentCheckpointMBean.java =================================================================== --- oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentCheckpointMBean.java (revision 1886124) +++ oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentCheckpointMBean.java (working copy) @@ -76,6 +76,18 @@ return cp; } + public String createCheckpointForRevision(String revision, long lifetime, boolean force) { + Revision rev = Revision.fromString(revision); + if (force || rev.getTimestamp() < getOldestCheckpointCreationTimestamp()) { + String cp = store.checkpoint(rev, lifetime); + log.info("Created checkpoint [{}] with lifetime {} for Revision {}", cp, lifetime, revision); + return cp; + } else { + throw new IllegalArgumentException(String.format("Cannot create a checkpoint for this revision. " + + "Revision timestamp is %l, and oldest checkpoint timestamp is %l", rev.getTimestamp(), getOldestCheckpointCreationTimestamp())); + } + } + @Override public boolean releaseCheckpoint(String checkpoint) { log.info("Released checkpoint [{}]", checkpoint); Index: oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java =================================================================== --- oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java (revision 1886124) +++ oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java (working copy) @@ -2031,6 +2031,13 @@ } @NotNull + public String checkpoint(Revision revision, long lifetime) { + checkOpen(); + Map empty = Collections.emptyMap(); + return checkpoints.create(revision, lifetime, empty).toString(); + } + + @NotNull @Override public Map checkpointInfo(@NotNull String checkpoint) { checkOpen(); Index: oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java =================================================================== --- oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java (revision 1886124) +++ oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java (working copy) @@ -4055,6 +4055,14 @@ } @Test + public void createCheckpointForRevisionAfterDispose() { + DocumentNodeStore store = new DocumentMK.Builder().getNodeStore(); + Revision r = store.newRevision(); + store.dispose(); + Assert.assertThrows(IllegalStateException.class, () -> store.checkpoint(r, 60000)); + } + + @Test public void retrieveCheckpointInfoAfterDispose() { DocumentNodeStore store = new DocumentMK.Builder().getNodeStore(); String ref = store.checkpoint(60000);