|
|
@ -45,8 +45,12 @@ package org.eclipse.jgit.internal.storage.file; |
|
|
|
|
|
|
|
|
|
|
|
import static java.lang.Integer.valueOf; |
|
|
|
import static java.lang.Integer.valueOf; |
|
|
|
import static org.junit.Assert.assertEquals; |
|
|
|
import static org.junit.Assert.assertEquals; |
|
|
|
|
|
|
|
import static org.junit.Assert.assertNotEquals; |
|
|
|
|
|
|
|
import static org.junit.Assert.assertNotNull; |
|
|
|
|
|
|
|
|
|
|
|
import java.io.IOException; |
|
|
|
import java.io.IOException; |
|
|
|
|
|
|
|
import java.util.Collection; |
|
|
|
|
|
|
|
import java.util.Collections; |
|
|
|
import java.util.concurrent.BrokenBarrierException; |
|
|
|
import java.util.concurrent.BrokenBarrierException; |
|
|
|
import java.util.concurrent.Callable; |
|
|
|
import java.util.concurrent.Callable; |
|
|
|
import java.util.concurrent.CyclicBarrier; |
|
|
|
import java.util.concurrent.CyclicBarrier; |
|
|
@ -56,8 +60,14 @@ import java.util.concurrent.Future; |
|
|
|
import java.util.concurrent.TimeUnit; |
|
|
|
import java.util.concurrent.TimeUnit; |
|
|
|
|
|
|
|
|
|
|
|
import org.eclipse.jgit.internal.JGitText; |
|
|
|
import org.eclipse.jgit.internal.JGitText; |
|
|
|
|
|
|
|
import org.eclipse.jgit.internal.storage.pack.PackWriter; |
|
|
|
|
|
|
|
import org.eclipse.jgit.junit.TestRepository; |
|
|
|
import org.eclipse.jgit.lib.EmptyProgressMonitor; |
|
|
|
import org.eclipse.jgit.lib.EmptyProgressMonitor; |
|
|
|
|
|
|
|
import org.eclipse.jgit.lib.NullProgressMonitor; |
|
|
|
|
|
|
|
import org.eclipse.jgit.lib.ObjectId; |
|
|
|
|
|
|
|
import org.eclipse.jgit.lib.Sets; |
|
|
|
import org.eclipse.jgit.revwalk.RevBlob; |
|
|
|
import org.eclipse.jgit.revwalk.RevBlob; |
|
|
|
|
|
|
|
import org.eclipse.jgit.revwalk.RevCommit; |
|
|
|
import org.junit.Test; |
|
|
|
import org.junit.Test; |
|
|
|
|
|
|
|
|
|
|
|
public class GcConcurrentTest extends GcTestCase { |
|
|
|
public class GcConcurrentTest extends GcTestCase { |
|
|
@ -118,4 +128,97 @@ public class GcConcurrentTest extends GcTestCase { |
|
|
|
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); |
|
|
|
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
public void repackAndGetStats() throws Exception { |
|
|
|
|
|
|
|
TestRepository<FileRepository>.BranchBuilder test = tr.branch("test"); |
|
|
|
|
|
|
|
test.commit().add("a", "a").create(); |
|
|
|
|
|
|
|
GC gc1 = new GC(tr.getRepository()); |
|
|
|
|
|
|
|
gc1.setPackExpireAgeMillis(0); |
|
|
|
|
|
|
|
gc1.gc(); |
|
|
|
|
|
|
|
test.commit().add("b", "b").create(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create a new Repository instance and trigger a gc
|
|
|
|
|
|
|
|
// from that instance. Reusing the existing repo instance
|
|
|
|
|
|
|
|
// tr.getRepository() would not show the problem.
|
|
|
|
|
|
|
|
FileRepository r2 = new FileRepository( |
|
|
|
|
|
|
|
tr.getRepository().getDirectory()); |
|
|
|
|
|
|
|
GC gc2 = new GC(r2); |
|
|
|
|
|
|
|
gc2.setPackExpireAgeMillis(0); |
|
|
|
|
|
|
|
gc2.gc(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
new GC(tr.getRepository()).getStatistics(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
public void repackAndUploadPack() throws Exception { |
|
|
|
|
|
|
|
TestRepository<FileRepository>.BranchBuilder test = tr.branch("test"); |
|
|
|
|
|
|
|
// RevCommit a = test.commit().add("a", "a").create();
|
|
|
|
|
|
|
|
test.commit().add("a", "a").create(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GC gc1 = new GC(tr.getRepository()); |
|
|
|
|
|
|
|
gc1.setPackExpireAgeMillis(0); |
|
|
|
|
|
|
|
gc1.gc(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RevCommit b = test.commit().add("b", "b").create(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FileRepository r2 = new FileRepository( |
|
|
|
|
|
|
|
tr.getRepository().getDirectory()); |
|
|
|
|
|
|
|
GC gc2 = new GC(r2); |
|
|
|
|
|
|
|
gc2.setPackExpireAgeMillis(0); |
|
|
|
|
|
|
|
gc2.gc(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Simulate parts of an UploadPack. This is the situation on
|
|
|
|
|
|
|
|
// server side (e.g. gerrit) when when clients are
|
|
|
|
|
|
|
|
// cloning/fetching while the server side repo's
|
|
|
|
|
|
|
|
// are gc'ed by an external process (e.g. scheduled
|
|
|
|
|
|
|
|
// native git gc)
|
|
|
|
|
|
|
|
try (PackWriter pw = new PackWriter(tr.getRepository())) { |
|
|
|
|
|
|
|
pw.setUseBitmaps(true); |
|
|
|
|
|
|
|
pw.preparePack(NullProgressMonitor.INSTANCE, Sets.of(b), |
|
|
|
|
|
|
|
Collections.<ObjectId> emptySet()); |
|
|
|
|
|
|
|
new GC(tr.getRepository()).getStatistics(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PackFile getSinglePack(FileRepository r) { |
|
|
|
|
|
|
|
Collection<PackFile> packs = r.getObjectDatabase().getPacks(); |
|
|
|
|
|
|
|
assertEquals(1, packs.size()); |
|
|
|
|
|
|
|
return packs.iterator().next(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
public void repackAndCheckBitmapUsage() throws Exception { |
|
|
|
|
|
|
|
// create a test repository with one commit and pack all objects. After
|
|
|
|
|
|
|
|
// packing create loose objects to trigger creation of a new packfile on
|
|
|
|
|
|
|
|
// the next gc
|
|
|
|
|
|
|
|
TestRepository<FileRepository>.BranchBuilder test = tr.branch("test"); |
|
|
|
|
|
|
|
test.commit().add("a", "a").create(); |
|
|
|
|
|
|
|
FileRepository repository = tr.getRepository(); |
|
|
|
|
|
|
|
GC gc1 = new GC(repository); |
|
|
|
|
|
|
|
gc1.setPackExpireAgeMillis(0); |
|
|
|
|
|
|
|
gc1.gc(); |
|
|
|
|
|
|
|
String oldPackName = getSinglePack(repository).getPackName(); |
|
|
|
|
|
|
|
RevCommit b = test.commit().add("b", "b").create(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// start the garbage collection on a new repository instance,
|
|
|
|
|
|
|
|
FileRepository repository2 = new FileRepository(repository.getDirectory()); |
|
|
|
|
|
|
|
GC gc2 = new GC(repository2); |
|
|
|
|
|
|
|
gc2.setPackExpireAgeMillis(0); |
|
|
|
|
|
|
|
gc2.gc(); |
|
|
|
|
|
|
|
String newPackName = getSinglePack(repository2).getPackName(); |
|
|
|
|
|
|
|
// make sure gc() has caused creation of a new packfile
|
|
|
|
|
|
|
|
assertNotEquals(oldPackName, newPackName); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Even when asking again for the set of packfiles outdated data
|
|
|
|
|
|
|
|
// will be returned. As long as the repository can work on cached data
|
|
|
|
|
|
|
|
// it will do so and not detect that a new packfile exists.
|
|
|
|
|
|
|
|
assertNotEquals(getSinglePack(repository).getPackName(), newPackName); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Only when accessing object content it is required to rescan the pack
|
|
|
|
|
|
|
|
// directory and the new packfile will be detected.
|
|
|
|
|
|
|
|
repository.getObjectDatabase().open(b).getSize(); |
|
|
|
|
|
|
|
assertEquals(getSinglePack(repository).getPackName(), newPackName); |
|
|
|
|
|
|
|
assertNotNull(getSinglePack(repository).getBitmapIndex()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|