diff --git oak-doc/src/site/markdown/nodestore/segment/overview.md oak-doc/src/site/markdown/nodestore/segment/overview.md
index 3048bfa248..234d693476 100644
--- oak-doc/src/site/markdown/nodestore/segment/overview.md
+++ oak-doc/src/site/markdown/nodestore/segment/overview.md
@@ -676,14 +676,18 @@ Besides the local storage in TAR files (previously known as TarMK), support for
### Segment-Copy
```
-java -jar oak-run.jar segment-copy SOURCE DESTINATION
+java -jar oak-run.jar segment-copy SOURCE DESTINATION [--last ]
```
The `segment-copy` command allows the "translation" of the Segment Store at `SOURCE` from one persistence type (e.g. local TarMK Segment Store) to a different persistence type (e.g. remote Azure Segment Store), saving the resulted Segment Store at `DESTINATION`.
Unlike a sidegrade peformed with `oak-upgrade` (see [Repository Migration](#../../migration.md)) which includes only the current head state, this translation includes __all previous revisions persisted in the Segment Store__, therefore retaining the entire history.
+If `--last` option is present, the tool will start with the most recent revision and will copy at most journal revisions.
`SOURCE` must be a valid path/uri to an existing Segment Store.
`DESTINATION` must be a valid path/uri for the resulting Segment Store.
+
+The optional `--last [Integer]` argument can be used to control the maximum number of revisions to be copied from the journal (default is 1).
+
Both are specified as `PATH | cloud-prefix:URI`.
Please refer to the [Remote Segment Stores](#remote-segment-stores) section for details on how to correctly specify connection URIs.
diff --git oak-run/src/main/java/org/apache/jackrabbit/oak/run/SegmentCopyCommand.java oak-run/src/main/java/org/apache/jackrabbit/oak/run/SegmentCopyCommand.java
index 09d9ee1ba7..4517a5bbfb 100644
--- oak-run/src/main/java/org/apache/jackrabbit/oak/run/SegmentCopyCommand.java
+++ oak-run/src/main/java/org/apache/jackrabbit/oak/run/SegmentCopyCommand.java
@@ -17,6 +17,7 @@
package org.apache.jackrabbit.oak.run;
+import joptsimple.OptionSpec;
import org.apache.jackrabbit.oak.run.commons.Command;
import org.apache.jackrabbit.oak.segment.azure.tool.SegmentCopy;
@@ -31,6 +32,11 @@ class SegmentCopyCommand implements Command {
@Override
public void execute(String... args) throws Exception {
OptionParser parser = new OptionParser();
+
+ OptionSpec last = parser.accepts("last", "define the number of revisions to be copied (default: 1)")
+ .withOptionalArg()
+ .ofType(Integer.class);
+
OptionSet options = parser.parse(args);
PrintWriter out = new PrintWriter(System.out, true);
@@ -43,14 +49,19 @@ class SegmentCopyCommand implements Command {
String source = options.nonOptionArguments().get(0).toString();
String destination = options.nonOptionArguments().get(1).toString();
- int statusCode = SegmentCopy.builder()
+
+
+ SegmentCopy.Builder builder = SegmentCopy.builder()
.withSource(source)
.withDestination(destination)
.withOutWriter(out)
- .withErrWriter(err)
- .build()
- .run();
- System.exit(statusCode);
+ .withErrWriter(err);
+
+ if (options.has(last)) {
+ builder.withRevisionsCount(last.value(options) != null ? last.value(options) : 1);
+ }
+
+ System.exit(builder.build().run());
}
private void printUsage(OptionParser parser, PrintWriter err, String... messages) throws IOException {
diff --git oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/tool/SegmentCopy.java oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/tool/SegmentCopy.java
index a1cceac70a..1edc264a70 100644
--- oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/tool/SegmentCopy.java
+++ oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/tool/SegmentCopy.java
@@ -63,6 +63,8 @@ public class SegmentCopy {
private PrintWriter errWriter;
+ private Integer revisionsCount;
+
private Builder() {
// Prevent external instantiation.
}
@@ -140,6 +142,18 @@ public class SegmentCopy {
return this;
}
+ /**
+ * The last {@code revisionsCount} revisions to be copied.
+ * This parameter is not required and defaults to {@code 1}.
+ *
+ * @param revisionsCount number of revisions to copied.
+ * @return this builder.
+ */
+ public Builder withRevisionsCount(Integer revisionsCount) {
+ this.revisionsCount = revisionsCount;
+ return this;
+ }
+
/**
* Create an executable version of the {@link Check} command.
*
@@ -150,6 +164,9 @@ public class SegmentCopy {
checkNotNull(source);
checkNotNull(destination);
}
+ if (revisionsCount == null) {
+ revisionsCount = Integer.MAX_VALUE;
+ }
return new SegmentCopy(this);
}
}
@@ -162,6 +179,8 @@ public class SegmentCopy {
private final PrintWriter errWriter;
+ private final Integer revisionCount;
+
private SegmentNodeStorePersistence srcPersistence;
private SegmentNodeStorePersistence destPersistence;
@@ -172,6 +191,7 @@ public class SegmentCopy {
this.destination = builder.destination;
this.srcPersistence = builder.srcPersistence;
this.destPersistence = builder.destPersistence;
+ this.revisionCount = builder.revisionsCount;
this.outWriter = builder.outWriter;
this.errWriter = builder.errWriter;
}
@@ -195,12 +215,15 @@ public class SegmentCopy {
printMessage(outWriter, "Source: {0}", srcDescription);
printMessage(outWriter, "Destination: {0}", destDescription);
- SegmentStoreMigrator migrator = new SegmentStoreMigrator.Builder()
+ SegmentStoreMigrator.Builder migrator = new SegmentStoreMigrator.Builder()
.withSourcePersistence(srcPersistence, srcDescription)
- .withTargetPersistence(destPersistence, destDescription)
- .build();
+ .withTargetPersistence(destPersistence, destDescription);
+
+ if (revisionCount != null) {
+ migrator.withRevisionCount(revisionCount);
+ }
- migrator.migrate();
+ migrator.build().migrate();
} catch (Exception e) {
watch.stop();
printMessage(errWriter, "A problem occured while copying archives from {0} to {1} ", source, destination);
diff --git oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/tool/SegmentStoreMigrator.java oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/tool/SegmentStoreMigrator.java
index 35bd4be13e..efd40a6a25 100644
--- oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/tool/SegmentStoreMigrator.java
+++ oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/tool/SegmentStoreMigrator.java
@@ -72,7 +72,7 @@ public class SegmentStoreMigrator implements Closeable {
private final boolean appendMode;
- private final boolean onlyLastJournalEntry;
+ private final Integer revisionCount;
private ExecutorService executor = Executors.newFixedThreadPool(READ_THREADS + 1);
@@ -82,7 +82,7 @@ public class SegmentStoreMigrator implements Closeable {
this.sourceName = builder.sourceName;
this.targetName = builder.targetName;
this.appendMode = builder.appendMode;
- this.onlyLastJournalEntry = builder.onlyLastJournalEntry;
+ this.revisionCount = builder.revisionCount;
}
public void migrate() throws IOException, ExecutionException, InterruptedException {
@@ -106,7 +106,7 @@ public class SegmentStoreMigrator implements Closeable {
if (line.length() > 0 && !line.trim().equals("")) {
journal.add(line);
}
- if (!journal.isEmpty() && onlyLastJournalEntry) {
+ if (journal.size() == revisionCount) {
break;
}
}
@@ -291,7 +291,7 @@ public class SegmentStoreMigrator implements Closeable {
private boolean appendMode;
- private boolean onlyLastJournalEntry;
+ private Integer revisionCount;
public Builder withSource(File dir) {
this.source = new TarPersistence(dir);
@@ -334,12 +334,15 @@ public class SegmentStoreMigrator implements Closeable {
return this;
}
- public Builder withOnlyLastJournalEntry() {
- this.onlyLastJournalEntry = true;
+ public Builder withRevisionCount(Integer revisionCount) {
+ this.revisionCount = revisionCount;
return this;
}
public SegmentStoreMigrator build() {
+ if (revisionCount == null) {
+ revisionCount = Integer.MAX_VALUE;
+ }
return new SegmentStoreMigrator(this);
}
}