Pass PackConfig down to PackWriter when packing
When we are creating a pack the higher level application should be able
to override the PackConfig used, allowing it to control the number of
threads used or how much memory is allocated per writer.
Change-Id: I47795987bb0d161d3642082acc2f617d7cb28d8c
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties
index e879d6b..2fff6d4 100644
--- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties
+++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties
@@ -14,6 +14,7 @@
branchIsNotAnAncestorOfYourCurrentHEAD=The branch '{0}' is not an ancestor of your current HEAD.\nIf you are sure you want to delete it, run 'jgit branch -D {0}'.
branchNotFound=branch '{0}' not found.
cacheTreePathInfo="{0}": {1} entries, {2} children
+configFileNotFound=configuration file {0} not found
cannotBeRenamed={0} cannot be renamed
cannotChekoutNoHeadsAdvertisedByRemote=cannot checkout; no HEAD advertised by remote
cannotCreateCommand=Cannot create command {0}
@@ -61,6 +62,7 @@
metaVar_command=command
metaVar_commitOrTag=COMMIT|TAG
metaVar_commitish=commit-ish
+metaVar_configFile=FILE
metaVar_connProp=conn.prop
metaVar_directory=DIRECTORY
metaVar_file=FILE
@@ -138,6 +140,7 @@
usage_beMoreVerbose=be more verbose
usage_beVerbose=be verbose
usage_cloneRepositoryIntoNewDir=Clone a repository into a new directory
+usage_configFile=configuration file
usage_configureTheServiceInDaemonServicename=configure the service in daemon.servicename
usage_deleteBranchEvenIfNotMerged=delete branch (even if not merged)
usage_deleteFullyMergedBranch=delete fully merged branch
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java
index bae895c..14dcb1f 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java
@@ -67,6 +67,7 @@ public static CLIText get() {
/***/ public String branchIsNotAnAncestorOfYourCurrentHEAD;
/***/ public String branchNotFound;
/***/ public String cacheTreePathInfo;
+ /***/ public String configFileNotFound;
/***/ public String cannotBeRenamed;
/***/ public String cannotChekoutNoHeadsAdvertisedByRemote;
/***/ public String cannotCreateCommand;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Daemon.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Daemon.java
index f015a9e..3cca87a 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Daemon.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Daemon.java
@@ -48,13 +48,22 @@
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Executors;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.storage.file.WindowCache;
+import org.eclipse.jgit.storage.file.WindowCacheConfig;
+import org.eclipse.jgit.storage.pack.PackConfig;
+import org.eclipse.jgit.transport.DaemonService;
+import org.eclipse.jgit.util.FS;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
-import org.eclipse.jgit.transport.DaemonService;
@Command(common = true, usage = "usage_exportRepositoriesOverGit")
class Daemon extends TextBuiltin {
+ @Option(name = "--config-file", metaVar = "metaVar_configFile", usage = "usage_configFile")
+ File configFile;
+
@Option(name = "--port", metaVar = "metaVar_port", usage = "usage_portNumberToListenOn")
int port = org.eclipse.jgit.transport.Daemon.DEFAULT_PORT;
@@ -89,12 +98,38 @@ protected boolean requiresRepository() {
@Override
protected void run() throws Exception {
+ PackConfig packConfig = new PackConfig();
+
+ if (configFile != null) {
+ if (!configFile.exists()) {
+ throw die(MessageFormat.format(
+ CLIText.get().configFileNotFound, //
+ configFile.getAbsolutePath()));
+ }
+
+ FileBasedConfig cfg = new FileBasedConfig(configFile, FS.DETECTED);
+ cfg.load();
+
+ WindowCacheConfig wcc = new WindowCacheConfig();
+ wcc.fromConfig(cfg);
+ WindowCache.reconfigure(wcc);
+
+ packConfig.fromConfig(cfg);
+ }
+
+ int threads = packConfig.getThreads();
+ if (threads <= 0)
+ threads = Runtime.getRuntime().availableProcessors();
+ if (1 < threads)
+ packConfig.setExecutor(Executors.newFixedThreadPool(threads));
+
final org.eclipse.jgit.transport.Daemon d;
d = new org.eclipse.jgit.transport.Daemon(
host != null ? new InetSocketAddress(host, port)
: new InetSocketAddress(port));
d.setExportAll(exportAll);
+ d.setPackConfig(packConfig);
if (0 <= timeout)
d.setTimeout(timeout);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
index 297105d..0838f29 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
@@ -231,7 +231,8 @@ private void writePack(final Map<String, RemoteRefUpdate> refUpdates,
List<ObjectId> newObjects = new ArrayList<ObjectId>(refUpdates.size());
final long start;
- final PackWriter writer = new PackWriter(local);
+ final PackWriter writer = new PackWriter(transport.getPackConfig(),
+ local.newObjectReader());
try {
for (final Ref r : getRefs())
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
index 79fa58c..b513412 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
@@ -61,6 +61,7 @@
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.storage.pack.PackConfig;
import org.eclipse.jgit.storage.pack.PackWriter;
/**
@@ -81,12 +82,14 @@
* overall bundle size.
*/
public class BundleWriter {
- private final PackWriter packWriter;
+ private final Repository db;
private final Map<String, ObjectId> include;
private final Set<RevCommit> assume;
+ private PackConfig packConfig;
+
/**
* Create a writer for a bundle.
*
@@ -94,12 +97,23 @@ public class BundleWriter {
* repository where objects are stored.
*/
public BundleWriter(final Repository repo) {
- packWriter = new PackWriter(repo);
+ db = repo;
include = new TreeMap<String, ObjectId>();
assume = new HashSet<RevCommit>();
}
/**
+ * Set the configuration used by the pack generator.
+ *
+ * @param pc
+ * configuration controlling packing parameters. If null the
+ * source repository's settings will be used.
+ */
+ public void setPackConfig(PackConfig pc) {
+ this.packConfig = pc;
+ }
+
+ /**
* Include an object (and everything reachable from it) in the bundle.
*
* @param name
@@ -166,6 +180,10 @@ public void assume(final RevCommit c) {
*/
public void writeBundle(ProgressMonitor monitor, OutputStream os)
throws IOException {
+ PackConfig pc = packConfig;
+ if (pc == null)
+ pc = new PackConfig(db);
+ PackWriter packWriter = new PackWriter(pc, db.newObjectReader());
try {
final HashSet<ObjectId> inc = new HashSet<ObjectId>();
final HashSet<ObjectId> exc = new HashSet<ObjectId>();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Daemon.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Daemon.java
index aa2e252..0bc5fb3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Daemon.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Daemon.java
@@ -63,6 +63,7 @@
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryCache;
import org.eclipse.jgit.lib.RepositoryCache.FileKey;
+import org.eclipse.jgit.storage.pack.PackConfig;
import org.eclipse.jgit.util.FS;
/** Basic daemon for the anonymous <code>git://</code> transport protocol. */
@@ -90,6 +91,8 @@ public class Daemon {
private int timeout;
+ private PackConfig packConfig;
+
/** Configure a daemon to listen on any available network port. */
public Daemon() {
this(null);
@@ -120,6 +123,7 @@ protected void execute(final DaemonClient dc,
final UploadPack rp = new UploadPack(db);
final InputStream in = dc.getInputStream();
rp.setTimeout(Daemon.this.getTimeout());
+ rp.setPackConfig(Daemon.this.packConfig);
rp.upload(in, dc.getOutputStream(), null);
}
}, new DaemonService("receive-pack", "receivepack") {
@@ -243,6 +247,17 @@ public void setTimeout(final int seconds) {
}
/**
+ * Set the configuration used by the pack generator.
+ *
+ * @param pc
+ * configuration controlling packing parameters. If null the
+ * source repository's settings will be used.
+ */
+ public void setPackConfig(PackConfig pc) {
+ this.packConfig = pc;
+ }
+
+ /**
* Start this daemon on a background thread.
*
* @throws IOException
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
index a8e47af..500cf0c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
@@ -66,6 +66,7 @@
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.TransferConfig;
+import org.eclipse.jgit.storage.pack.PackConfig;
import org.eclipse.jgit.util.FS;
/**
@@ -554,6 +555,9 @@ private static String findTrackingRefName(final String remoteName,
/** Timeout in seconds to wait before aborting an IO read or write. */
private int timeout;
+ /** Pack configuration used by this transport to make pack file. */
+ private PackConfig packConfig;
+
/**
* Create a new transport instance.
*
@@ -792,6 +796,32 @@ public void setTimeout(final int seconds) {
}
/**
+ * Get the configuration used by the pack generator to make packs.
+ *
+ * If {@link #setPackConfig(PackConfig)} was previously given null a new
+ * PackConfig is created on demand by this method using the source
+ * repository's settings.
+ *
+ * @return the pack configuration. Never null.
+ */
+ public PackConfig getPackConfig() {
+ if (packConfig == null)
+ packConfig = new PackConfig(local);
+ return packConfig;
+ }
+
+ /**
+ * Set the configuration used by the pack generator.
+ *
+ * @param pc
+ * configuration controlling packing parameters. If null the
+ * source repository's settings will be used.
+ */
+ public void setPackConfig(PackConfig pc) {
+ packConfig = pc;
+ }
+
+ /**
* Fetch objects and refs from the remote repository to the local one.
* <p>
* This is a utility function providing standard fetch behavior. Local
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
index e733859..16d56df 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -69,6 +69,7 @@
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.storage.pack.PackConfig;
import org.eclipse.jgit.storage.pack.PackWriter;
import org.eclipse.jgit.transport.BasePackFetchConnection.MultiAck;
import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
@@ -102,6 +103,9 @@ public class UploadPack {
/** Revision traversal support over {@link #db}. */
private final RevWalk walk;
+ /** Configuration to pass into the PackWriter. */
+ private PackConfig packConfig;
+
/** Timeout in seconds to wait for client interaction. */
private int timeout;
@@ -259,6 +263,17 @@ public void setRefFilter(final RefFilter refFilter) {
}
/**
+ * Set the configuration used by the pack generator.
+ *
+ * @param pc
+ * configuration controlling packing parameters. If null the
+ * source repository's settings will be used.
+ */
+ public void setPackConfig(PackConfig pc) {
+ this.packConfig = pc;
+ }
+
+ /**
* Execute the upload task on the socket.
*
* @param input
@@ -566,7 +581,10 @@ private void sendPack() throws IOException {
SideBandOutputStream.CH_PROGRESS, bufsz, rawOut));
}
- final PackWriter pw = new PackWriter(db, walk.getObjectReader());
+ PackConfig cfg = packConfig;
+ if (cfg == null)
+ cfg = new PackConfig(db);
+ final PackWriter pw = new PackWriter(cfg, walk.getObjectReader());
try {
pw.setDeltaBaseAsOffset(options.contains(OPTION_OFS_DELTA));
pw.setThin(options.contains(OPTION_THIN_PACK));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java
index bbc918f..9ce0ec1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java
@@ -103,6 +103,9 @@ class WalkPushConnection extends BaseConnection implements PushConnection {
/** Database connection to the remote repository. */
private final WalkRemoteObjectDatabase dest;
+ /** The configured transport we were constructed by. */
+ private final Transport transport;
+
/**
* Packs already known to reside in the remote repository.
* <p>
@@ -123,9 +126,9 @@ class WalkPushConnection extends BaseConnection implements PushConnection {
WalkPushConnection(final WalkTransport walkTransport,
final WalkRemoteObjectDatabase w) {
- Transport t = (Transport)walkTransport;
- local = t.local;
- uri = t.getURI();
+ transport = (Transport) walkTransport;
+ local = transport.local;
+ uri = transport.getURI();
dest = w;
}
@@ -209,7 +212,8 @@ private void sendpack(final List<RemoteRefUpdate> updates,
String pathPack = null;
String pathIdx = null;
- final PackWriter pw = new PackWriter(local);
+ final PackWriter writer = new PackWriter(transport.getPackConfig(),
+ local.newObjectReader());
try {
final List<ObjectId> need = new ArrayList<ObjectId>();
final List<ObjectId> have = new ArrayList<ObjectId>();
@@ -220,20 +224,20 @@ private void sendpack(final List<RemoteRefUpdate> updates,
if (r.getPeeledObjectId() != null)
have.add(r.getPeeledObjectId());
}
- pw.preparePack(monitor, need, have);
+ writer.preparePack(monitor, need, have);
// We don't have to continue further if the pack will
// be an empty pack, as the remote has all objects it
// needs to complete this change.
//
- if (pw.getObjectsNumber() == 0)
+ if (writer.getObjectsNumber() == 0)
return;
packNames = new LinkedHashMap<String, String>();
for (final String n : dest.getPackNames())
packNames.put(n, n);
- final String base = "pack-" + pw.computeName().name();
+ final String base = "pack-" + writer.computeName().name();
final String packName = base + ".pack";
pathPack = "pack/" + packName;
pathIdx = "pack/" + base + ".idx";
@@ -254,7 +258,7 @@ private void sendpack(final List<RemoteRefUpdate> updates,
OutputStream os = dest.writeFile(pathPack, monitor, wt + "..pack");
try {
os = new BufferedOutputStream(os);
- pw.writePack(monitor, monitor, os);
+ writer.writePack(monitor, monitor, os);
} finally {
os.close();
}
@@ -262,7 +266,7 @@ private void sendpack(final List<RemoteRefUpdate> updates,
os = dest.writeFile(pathIdx, monitor, wt + "..idx");
try {
os = new BufferedOutputStream(os);
- pw.writeIndex(os);
+ writer.writeIndex(os);
} finally {
os.close();
}
@@ -282,7 +286,7 @@ private void sendpack(final List<RemoteRefUpdate> updates,
throw new TransportException(uri, JGitText.get().cannotStoreObjects, err);
} finally {
- pw.release();
+ writer.release();
}
}