diff options
6 files changed, 124 insertions, 20 deletions
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties index 574981d385..bdf05e901a 100644 --- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties +++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties @@ -184,6 +184,7 @@ unmergedPaths=Unmerged paths: unsupportedOperation=Unsupported operation: {0} untrackedFiles=Untracked files: updating=Updating {0}..{1} +usage_Aggressive=This option will cause gc to more aggressively optimize the repository at the expense of taking much more time usage_Blame=Show what revision and author last modified each line usage_CommandLineClientForamazonsS3Service=Command line client for Amazon's S3 service usage_CommitAll=commit all modified and deleted files diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java index 58813bcb00..aa5c90590e 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Gc.java @@ -43,16 +43,19 @@ package org.eclipse.jgit.pgm; -import org.eclipse.jgit.internal.storage.file.FileRepository; -import org.eclipse.jgit.internal.storage.file.GC; +import org.eclipse.jgit.api.Git; import org.eclipse.jgit.lib.TextProgressMonitor; +import org.kohsuke.args4j.Option; @Command(common = true, usage = "usage_Gc") class Gc extends TextBuiltin { + @Option(name = "--aggressive", usage = "usage_Aggressive") + private boolean aggressive; + @Override protected void run() throws Exception { - GC gc = new GC((FileRepository) db); - gc.setProgressMonitor(new TextProgressMonitor()); - gc.gc(); + Git git = Git.wrap(db); + git.gc().setAggressive(aggressive) + .setProgressMonitor(new TextProgressMonitor()).call(); } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java index 0f27099c09..0742504d23 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java @@ -51,21 +51,32 @@ import java.util.Iterator; import org.eclipse.jgit.junit.TestRepository.BranchBuilder; import org.eclipse.jgit.revwalk.RevCommit; -import org.junit.Test; +import org.eclipse.jgit.storage.pack.PackConfig; +import org.junit.experimental.theories.DataPoints; +import org.junit.experimental.theories.Theories; +import org.junit.experimental.theories.Theory; +import org.junit.runner.RunWith; +@RunWith(Theories.class) public class GcBasicPackingTest extends GcTestCase { - @Test - public void repackEmptyRepo_noPackCreated() throws IOException { + @DataPoints + public static boolean[] aggressiveValues = { true, false }; + + @Theory + public void repackEmptyRepo_noPackCreated(boolean aggressive) + throws IOException { + configureGc(gc, aggressive); gc.repack(); assertEquals(0, repo.getObjectDatabase().getPacks().size()); } - @Test - public void testPackRepoWithNoRefs() throws Exception { + @Theory + public void testPackRepoWithNoRefs(boolean aggressive) throws Exception { tr.commit().add("A", "A").add("B", "B").create(); stats = gc.getStatistics(); assertEquals(4, stats.numberOfLooseObjects); assertEquals(0, stats.numberOfPackedObjects); + configureGc(gc, aggressive); gc.gc(); stats = gc.getStatistics(); assertEquals(4, stats.numberOfLooseObjects); @@ -73,8 +84,8 @@ public class GcBasicPackingTest extends GcTestCase { assertEquals(0, stats.numberOfPackFiles); } - @Test - public void testPack2Commits() throws Exception { + @Theory + public void testPack2Commits(boolean aggressive) throws Exception { BranchBuilder bb = tr.branch("refs/heads/master"); bb.commit().add("A", "A").add("B", "B").create(); bb.commit().add("A", "A2").add("B", "B2").create(); @@ -82,6 +93,7 @@ public class GcBasicPackingTest extends GcTestCase { stats = gc.getStatistics(); assertEquals(8, stats.numberOfLooseObjects); assertEquals(0, stats.numberOfPackedObjects); + configureGc(gc, aggressive); gc.gc(); stats = gc.getStatistics(); assertEquals(0, stats.numberOfLooseObjects); @@ -89,13 +101,15 @@ public class GcBasicPackingTest extends GcTestCase { assertEquals(1, stats.numberOfPackFiles); } - @Test - public void testPackAllObjectsInOnePack() throws Exception { + @Theory + public void testPackAllObjectsInOnePack(boolean aggressive) + throws Exception { tr.branch("refs/heads/master").commit().add("A", "A").add("B", "B") .create(); stats = gc.getStatistics(); assertEquals(4, stats.numberOfLooseObjects); assertEquals(0, stats.numberOfPackedObjects); + configureGc(gc, aggressive); gc.gc(); stats = gc.getStatistics(); assertEquals(0, stats.numberOfLooseObjects); @@ -110,8 +124,8 @@ public class GcBasicPackingTest extends GcTestCase { assertEquals(1, stats.numberOfPackFiles); } - @Test - public void testPackCommitsAndLooseOne() throws Exception { + @Theory + public void testPackCommitsAndLooseOne(boolean aggressive) throws Exception { BranchBuilder bb = tr.branch("refs/heads/master"); RevCommit first = bb.commit().add("A", "A").add("B", "B").create(); bb.commit().add("A", "A2").add("B", "B2").create(); @@ -120,6 +134,7 @@ public class GcBasicPackingTest extends GcTestCase { stats = gc.getStatistics(); assertEquals(8, stats.numberOfLooseObjects); assertEquals(0, stats.numberOfPackedObjects); + configureGc(gc, aggressive); gc.gc(); stats = gc.getStatistics(); assertEquals(0, stats.numberOfLooseObjects); @@ -127,8 +142,8 @@ public class GcBasicPackingTest extends GcTestCase { assertEquals(2, stats.numberOfPackFiles); } - @Test - public void testNotPackTwice() throws Exception { + @Theory + public void testNotPackTwice(boolean aggressive) throws Exception { BranchBuilder bb = tr.branch("refs/heads/master"); RevCommit first = bb.commit().message("M").add("M", "M").create(); bb.commit().message("B").add("B", "Q").create(); @@ -146,6 +161,7 @@ public class GcBasicPackingTest extends GcTestCase { gc.setExpireAgeMillis(0); fsTick(); + configureGc(gc, aggressive); gc.gc(); stats = gc.getStatistics(); assertEquals(0, stats.numberOfLooseObjects); @@ -159,4 +175,15 @@ public class GcBasicPackingTest extends GcTestCase { assertEquals(9, pIt.next().getObjectCount()); } } + + private void configureGc(GC myGc, boolean aggressive) { + PackConfig pconfig = new PackConfig(repo); + if (aggressive) { + pconfig.setDeltaSearchWindowSize(250); + pconfig.setMaxDeltaDepth(250); + pconfig.setReuseObjects(false); + } else + pconfig = new PackConfig(repo); + myGc.setPackConfig(pconfig); + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java index 77b84d3a36..2f7a3edbb1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java @@ -54,8 +54,11 @@ import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.storage.file.FileRepository; import org.eclipse.jgit.internal.storage.file.GC; import org.eclipse.jgit.internal.storage.file.GC.RepoStatistics; +import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.storage.pack.PackConfig; import org.eclipse.jgit.util.GitDateParser; /** @@ -63,17 +66,34 @@ import org.eclipse.jgit.util.GitDateParser; * supported options and arguments of this command and a {@link #call()} method * to finally execute the command. Each instance of this class should only be * used for one invocation of the command (means: one call to {@link #call()}) - * + * * @since 2.2 * @see <a href="http://www.kernel.org/pub/software/scm/git/docs/git-gc.html" * >Git documentation about gc</a> */ public class GarbageCollectCommand extends GitCommand<Properties> { + /** + * Default value of maximum delta chain depth during aggressive garbage + * collection: {@value} + * + * @since 3.6 + */ + public static final int DEFAULT_GC_AGGRESSIVE_DEPTH = 250; + + /** + * Default window size during packing during aggressive garbage collection: + * * {@value} + * + * @since 3.6 + */ + public static final int DEFAULT_GC_AGGRESSIVE_WINDOW = 250; private ProgressMonitor monitor; private Date expire; + private PackConfig pconfig; + /** * @param repo */ @@ -82,6 +102,7 @@ public class GarbageCollectCommand extends GitCommand<Properties> { if (!(repo instanceof FileRepository)) throw new UnsupportedOperationException(MessageFormat.format( JGitText.get().unsupportedGC, repo.getClass().toString())); + pconfig = new PackConfig(repo); } /** @@ -110,11 +131,41 @@ public class GarbageCollectCommand extends GitCommand<Properties> { return this; } + /** + * Whether to use aggressive mode or not. If set to true JGit behaves more + * similar to native git's "git gc --aggressive". If set to + * <code>true</code> compressed objects found in old packs are not reused + * but every object is compressed again. Configuration variables + * pack.window and pack.depth are set to 250 for this GC. + * + * @since 3.6 + * @param aggressive + * whether to turn on or off aggressive mode + * @return this instance + */ + public GarbageCollectCommand setAggressive(boolean aggressive) { + if (aggressive) { + StoredConfig repoConfig = repo.getConfig(); + pconfig.setDeltaSearchWindowSize(repoConfig.getInt( + ConfigConstants.CONFIG_GC_SECTION, + ConfigConstants.CONFIG_KEY_AGGRESSIVE_WINDOW, + DEFAULT_GC_AGGRESSIVE_WINDOW)); + pconfig.setMaxDeltaDepth(repoConfig.getInt( + ConfigConstants.CONFIG_GC_SECTION, + ConfigConstants.CONFIG_KEY_AGGRESSIVE_DEPTH, + DEFAULT_GC_AGGRESSIVE_DEPTH)); + pconfig.setReuseObjects(false); + } else + pconfig = new PackConfig(repo); + return this; + } + @Override public Properties call() throws GitAPIException { checkCallable(); GC gc = new GC((FileRepository) repo); + gc.setPackConfig(pconfig); gc.setProgressMonitor(monitor); if (this.expire != null) gc.setExpire(expire); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java index 3cc4e7b97b..48335e48c2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java @@ -93,6 +93,7 @@ import org.eclipse.jgit.lib.ReflogEntry; import org.eclipse.jgit.revwalk.ObjectWalk; import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.storage.pack.PackConfig; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.filter.TreeFilter; import org.eclipse.jgit.util.FileUtils; @@ -117,6 +118,8 @@ public class GC { private Date expire; + private PackConfig pconfig = null; + /** * the refs which existed during the last call to {@link #repack()}. This is * needed during {@link #prune(Set)} where we can optimize by looking at the @@ -686,7 +689,7 @@ public class GC { } }); - PackWriter pw = new PackWriter(repo); + PackWriter pw = new PackWriter((pconfig == null) ? new PackConfig(repo) : pconfig, repo.newObjectReader()); try { // prepare the PackWriter pw.setDeltaBaseAsOffset(true); @@ -948,6 +951,19 @@ public class GC { } /** + * Set the PackConfig used when (re-)writing packfiles. This allows to + * influence how packs are written and to implement something similar to + * "git gc --aggressive" + * + * @since 3.6 + * @param pconfig + * the {@link PackConfig} used when writing packs + */ + public void setPackConfig(PackConfig pconfig) { + this.pconfig = pconfig; + } + + /** * During gc() or prune() each unreferenced, loose object which has been * created or modified after or at <code>expire</code> will not be pruned. * Only older objects may be pruned. If set to null then every object is a diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java index 378d91c58c..b905c9593c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java @@ -226,6 +226,12 @@ public class ConfigConstants { /** The "pruneexpire" key */ public static final String CONFIG_KEY_PRUNEEXPIRE = "pruneexpire"; + /** The "aggressiveDepth" key */ + public static final String CONFIG_KEY_AGGRESSIVE_DEPTH = "aggressiveDepth"; + + /** The "aggressiveWindow" key */ + public static final String CONFIG_KEY_AGGRESSIVE_WINDOW = "aggressiveWindow"; + /** The "mergeoptions" key */ public static final String CONFIG_KEY_MERGEOPTIONS = "mergeoptions"; |