Browse Source
* master: Implement rebase.autostash CLI status should support --porcelain More helpful InvalidPathException messages (include reason) Fix IgnoreRule#isMatch returning wrong result due to missing reset Fix exception on conflicts with recursive merge Add pgm test for checkout of existing branch with checkout conflict Fix broken symbolic links on Cygwin. Do not allow non-ff-rebase if there are uncommitted changes Manage CheckoutConflictException in pgm Fix handling of file/folder conflicts during a checkout Mention null return in Javadoc of Config#getString Fix applying stash on other commit Use static factory methods instead of overloaded constructors Break up GCTest to run in parallel Modify T0004_PackReaderTest to use existing pack Move SampleDataRepositoryTestCase to org.eclipse.jgit.test Support running from JARs in JGitTestUtil Cache SimpleDateFormat in GitDateParser per locale Fix FIXUP error for blank lines in interactive rebase Fix parsing Rebase todo lines when commit message is missing Add close() method to API Update Jetty to 7.6.14.v20131031 Document that path parameters should use '/' as separator Improve Javadoc for typeHint parameter Do not update the ref hot bit when checking isIndexLoaded Don't delete .idx file if .pack file can't be deleted Change-Id: I02abfc09000d0fe9bdf4331c65bec7046f586179 Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>stable-3.2
Matthias Sohn
11 years ago
89 changed files with 2740 additions and 1040 deletions
@ -1,741 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright (C) 2012, Christian Halstrick <christian.halstrick@sap.com> |
|
||||||
* and other copyright owners as documented in the project's IP log. |
|
||||||
* |
|
||||||
* This program and the accompanying materials are made available |
|
||||||
* under the terms of the Eclipse Distribution License v1.0 which |
|
||||||
* accompanies this distribution, is reproduced below, and is |
|
||||||
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
|
||||||
* |
|
||||||
* All rights reserved. |
|
||||||
* |
|
||||||
* Redistribution and use in source and binary forms, with or |
|
||||||
* without modification, are permitted provided that the following |
|
||||||
* conditions are met: |
|
||||||
* |
|
||||||
* - Redistributions of source code must retain the above copyright |
|
||||||
* notice, this list of conditions and the following disclaimer. |
|
||||||
* |
|
||||||
* - Redistributions in binary form must reproduce the above |
|
||||||
* copyright notice, this list of conditions and the following |
|
||||||
* disclaimer in the documentation and/or other materials provided |
|
||||||
* with the distribution. |
|
||||||
* |
|
||||||
* - Neither the name of the Eclipse Foundation, Inc. nor the |
|
||||||
* names of its contributors may be used to endorse or promote |
|
||||||
* products derived from this software without specific prior |
|
||||||
* written permission. |
|
||||||
* |
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
|
||||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
|
||||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
|
||||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
|
||||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
|
||||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
|
||||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
|
||||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||||
*/ |
|
||||||
package org.eclipse.jgit.internal.storage.file; |
|
||||||
|
|
||||||
import static java.lang.Integer.valueOf; |
|
||||||
import static org.junit.Assert.assertEquals; |
|
||||||
import static org.junit.Assert.assertFalse; |
|
||||||
import static org.junit.Assert.assertSame; |
|
||||||
import static org.junit.Assert.assertTrue; |
|
||||||
|
|
||||||
import java.io.File; |
|
||||||
import java.io.IOException; |
|
||||||
import java.util.Collection; |
|
||||||
import java.util.Collections; |
|
||||||
import java.util.Date; |
|
||||||
import java.util.Iterator; |
|
||||||
import java.util.concurrent.BrokenBarrierException; |
|
||||||
import java.util.concurrent.Callable; |
|
||||||
import java.util.concurrent.CyclicBarrier; |
|
||||||
import java.util.concurrent.ExecutorService; |
|
||||||
import java.util.concurrent.Executors; |
|
||||||
import java.util.concurrent.Future; |
|
||||||
import java.util.concurrent.TimeUnit; |
|
||||||
|
|
||||||
import org.eclipse.jgit.api.Git; |
|
||||||
import org.eclipse.jgit.internal.JGitText; |
|
||||||
import org.eclipse.jgit.internal.storage.file.GC.RepoStatistics; |
|
||||||
import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry; |
|
||||||
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; |
|
||||||
import org.eclipse.jgit.junit.RepositoryTestCase; |
|
||||||
import org.eclipse.jgit.junit.TestRepository; |
|
||||||
import org.eclipse.jgit.junit.TestRepository.BranchBuilder; |
|
||||||
import org.eclipse.jgit.junit.TestRepository.CommitBuilder; |
|
||||||
import org.eclipse.jgit.lib.AnyObjectId; |
|
||||||
import org.eclipse.jgit.lib.Constants; |
|
||||||
import org.eclipse.jgit.lib.EmptyProgressMonitor; |
|
||||||
import org.eclipse.jgit.lib.ObjectId; |
|
||||||
import org.eclipse.jgit.lib.Ref.Storage; |
|
||||||
import org.eclipse.jgit.lib.RefUpdate; |
|
||||||
import org.eclipse.jgit.lib.RefUpdate.Result; |
|
||||||
import org.eclipse.jgit.merge.MergeStrategy; |
|
||||||
import org.eclipse.jgit.merge.Merger; |
|
||||||
import org.eclipse.jgit.revwalk.RevBlob; |
|
||||||
import org.eclipse.jgit.revwalk.RevCommit; |
|
||||||
import org.eclipse.jgit.revwalk.RevTag; |
|
||||||
import org.eclipse.jgit.revwalk.RevTree; |
|
||||||
import org.eclipse.jgit.util.FileUtils; |
|
||||||
import org.junit.After; |
|
||||||
import org.junit.Before; |
|
||||||
import org.junit.Test; |
|
||||||
|
|
||||||
public class GCTest extends LocalDiskRepositoryTestCase { |
|
||||||
private TestRepository<FileRepository> tr; |
|
||||||
|
|
||||||
private FileRepository repo; |
|
||||||
|
|
||||||
private GC gc; |
|
||||||
|
|
||||||
private RepoStatistics stats; |
|
||||||
|
|
||||||
@Before |
|
||||||
public void setUp() throws Exception { |
|
||||||
super.setUp(); |
|
||||||
repo = createWorkRepository(); |
|
||||||
tr = new TestRepository<FileRepository>((repo)); |
|
||||||
gc = new GC(repo); |
|
||||||
} |
|
||||||
|
|
||||||
@After |
|
||||||
public void tearDown() throws Exception { |
|
||||||
super.tearDown(); |
|
||||||
} |
|
||||||
|
|
||||||
// GC.packRefs tests
|
|
||||||
|
|
||||||
@Test |
|
||||||
public void packRefs_looseRefPacked() throws Exception { |
|
||||||
RevBlob a = tr.blob("a"); |
|
||||||
tr.lightweightTag("t", a); |
|
||||||
|
|
||||||
gc.packRefs(); |
|
||||||
assertSame(repo.getRef("t").getStorage(), Storage.PACKED); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void concurrentPackRefs_onlyOneWritesPackedRefs() throws Exception { |
|
||||||
RevBlob a = tr.blob("a"); |
|
||||||
tr.lightweightTag("t", a); |
|
||||||
|
|
||||||
final CyclicBarrier syncPoint = new CyclicBarrier(2); |
|
||||||
|
|
||||||
Callable<Integer> packRefs = new Callable<Integer>() { |
|
||||||
|
|
||||||
/** @return 0 for success, 1 in case of error when writing pack */ |
|
||||||
public Integer call() throws Exception { |
|
||||||
syncPoint.await(); |
|
||||||
try { |
|
||||||
gc.packRefs(); |
|
||||||
return valueOf(0); |
|
||||||
} catch (IOException e) { |
|
||||||
return valueOf(1); |
|
||||||
} |
|
||||||
} |
|
||||||
}; |
|
||||||
ExecutorService pool = Executors.newFixedThreadPool(2); |
|
||||||
try { |
|
||||||
Future<Integer> p1 = pool.submit(packRefs); |
|
||||||
Future<Integer> p2 = pool.submit(packRefs); |
|
||||||
assertEquals(1, p1.get().intValue() + p2.get().intValue()); |
|
||||||
} finally { |
|
||||||
pool.shutdown(); |
|
||||||
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void packRefsWhileRefLocked_refNotPackedNoError() |
|
||||||
throws Exception { |
|
||||||
RevBlob a = tr.blob("a"); |
|
||||||
tr.lightweightTag("t1", a); |
|
||||||
tr.lightweightTag("t2", a); |
|
||||||
LockFile refLock = new LockFile(new File(repo.getDirectory(), |
|
||||||
"refs/tags/t1"), repo.getFS()); |
|
||||||
try { |
|
||||||
refLock.lock(); |
|
||||||
gc.packRefs(); |
|
||||||
} finally { |
|
||||||
refLock.unlock(); |
|
||||||
} |
|
||||||
|
|
||||||
assertSame(repo.getRef("refs/tags/t1").getStorage(), Storage.LOOSE); |
|
||||||
assertSame(repo.getRef("refs/tags/t2").getStorage(), Storage.PACKED); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void packRefsWhileRefUpdated_refUpdateSucceeds() |
|
||||||
throws Exception { |
|
||||||
RevBlob a = tr.blob("a"); |
|
||||||
tr.lightweightTag("t", a); |
|
||||||
final RevBlob b = tr.blob("b"); |
|
||||||
|
|
||||||
final CyclicBarrier refUpdateLockedRef = new CyclicBarrier(2); |
|
||||||
final CyclicBarrier packRefsDone = new CyclicBarrier(2); |
|
||||||
ExecutorService pool = Executors.newFixedThreadPool(2); |
|
||||||
try { |
|
||||||
Future<Result> result = pool.submit(new Callable<Result>() { |
|
||||||
|
|
||||||
public Result call() throws Exception { |
|
||||||
RefUpdate update = new RefDirectoryUpdate( |
|
||||||
(RefDirectory) repo.getRefDatabase(), |
|
||||||
repo.getRef("refs/tags/t")) { |
|
||||||
@Override |
|
||||||
public boolean isForceUpdate() { |
|
||||||
try { |
|
||||||
refUpdateLockedRef.await(); |
|
||||||
packRefsDone.await(); |
|
||||||
} catch (InterruptedException e) { |
|
||||||
Thread.currentThread().interrupt(); |
|
||||||
} catch (BrokenBarrierException e) { |
|
||||||
Thread.currentThread().interrupt(); |
|
||||||
} |
|
||||||
return super.isForceUpdate(); |
|
||||||
} |
|
||||||
}; |
|
||||||
update.setForceUpdate(true); |
|
||||||
update.setNewObjectId(b); |
|
||||||
return update.update(); |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
pool.submit(new Callable<Void>() { |
|
||||||
public Void call() throws Exception { |
|
||||||
refUpdateLockedRef.await(); |
|
||||||
gc.packRefs(); |
|
||||||
packRefsDone.await(); |
|
||||||
return null; |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
assertSame(result.get(), Result.FORCED); |
|
||||||
|
|
||||||
} finally { |
|
||||||
pool.shutdownNow(); |
|
||||||
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); |
|
||||||
} |
|
||||||
|
|
||||||
assertEquals(repo.getRef("refs/tags/t").getObjectId(), b); |
|
||||||
} |
|
||||||
|
|
||||||
// GC.repack tests
|
|
||||||
|
|
||||||
@Test |
|
||||||
public void repackEmptyRepo_noPackCreated() throws IOException { |
|
||||||
gc.repack(); |
|
||||||
assertEquals(0, repo.getObjectDatabase().getPacks().size()); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void concurrentRepack() throws Exception { |
|
||||||
final CyclicBarrier syncPoint = new CyclicBarrier(2); |
|
||||||
|
|
||||||
class DoRepack extends EmptyProgressMonitor implements |
|
||||||
Callable<Integer> { |
|
||||||
|
|
||||||
public void beginTask(String title, int totalWork) { |
|
||||||
if (title.equals(JGitText.get().writingObjects)) { |
|
||||||
try { |
|
||||||
syncPoint.await(); |
|
||||||
} catch (InterruptedException e) { |
|
||||||
Thread.currentThread().interrupt(); |
|
||||||
} catch (BrokenBarrierException ignored) { |
|
||||||
//
|
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** @return 0 for success, 1 in case of error when writing pack */ |
|
||||||
public Integer call() throws Exception { |
|
||||||
try { |
|
||||||
gc.setProgressMonitor(this); |
|
||||||
gc.repack(); |
|
||||||
return valueOf(0); |
|
||||||
} catch (IOException e) { |
|
||||||
// leave the syncPoint in broken state so any awaiting
|
|
||||||
// threads and any threads that call await in the future get
|
|
||||||
// the BrokenBarrierException
|
|
||||||
Thread.currentThread().interrupt(); |
|
||||||
try { |
|
||||||
syncPoint.await(); |
|
||||||
} catch (InterruptedException ignored) { |
|
||||||
//
|
|
||||||
} |
|
||||||
return valueOf(1); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
RevBlob a = tr.blob("a"); |
|
||||||
tr.lightweightTag("t", a); |
|
||||||
|
|
||||||
ExecutorService pool = Executors.newFixedThreadPool(2); |
|
||||||
try { |
|
||||||
DoRepack repack1 = new DoRepack(); |
|
||||||
DoRepack repack2 = new DoRepack(); |
|
||||||
Future<Integer> result1 = pool.submit(repack1); |
|
||||||
Future<Integer> result2 = pool.submit(repack2); |
|
||||||
assertEquals(0, result1.get().intValue() + result2.get().intValue()); |
|
||||||
} finally { |
|
||||||
pool.shutdown(); |
|
||||||
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// GC.prune tests
|
|
||||||
|
|
||||||
@Test |
|
||||||
public void nonReferencedNonExpiredObject_notPruned() throws Exception { |
|
||||||
RevBlob a = tr.blob("a"); |
|
||||||
gc.setExpire(new Date(lastModified(a))); |
|
||||||
gc.prune(Collections.<ObjectId> emptySet()); |
|
||||||
assertTrue(repo.hasObject(a)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void nonReferencedExpiredObject_pruned() throws Exception { |
|
||||||
RevBlob a = tr.blob("a"); |
|
||||||
gc.setExpireAgeMillis(0); |
|
||||||
fsTick(); |
|
||||||
gc.prune(Collections.<ObjectId> emptySet()); |
|
||||||
assertFalse(repo.hasObject(a)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void nonReferencedExpiredObjectTree_pruned() throws Exception { |
|
||||||
RevBlob a = tr.blob("a"); |
|
||||||
RevTree t = tr.tree(tr.file("a", a)); |
|
||||||
gc.setExpireAgeMillis(0); |
|
||||||
fsTick(); |
|
||||||
gc.prune(Collections.<ObjectId> emptySet()); |
|
||||||
assertFalse(repo.hasObject(t)); |
|
||||||
assertFalse(repo.hasObject(a)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void nonReferencedObjects_onlyExpiredPruned() throws Exception { |
|
||||||
RevBlob a = tr.blob("a"); |
|
||||||
gc.setExpire(new Date(lastModified(a) + 1)); |
|
||||||
|
|
||||||
fsTick(); |
|
||||||
RevBlob b = tr.blob("b"); |
|
||||||
|
|
||||||
gc.prune(Collections.<ObjectId> emptySet()); |
|
||||||
assertFalse(repo.hasObject(a)); |
|
||||||
assertTrue(repo.hasObject(b)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void lightweightTag_objectNotPruned() throws Exception { |
|
||||||
RevBlob a = tr.blob("a"); |
|
||||||
tr.lightweightTag("t", a); |
|
||||||
gc.setExpireAgeMillis(0); |
|
||||||
fsTick(); |
|
||||||
gc.prune(Collections.<ObjectId> emptySet()); |
|
||||||
assertTrue(repo.hasObject(a)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void annotatedTag_objectNotPruned() throws Exception { |
|
||||||
RevBlob a = tr.blob("a"); |
|
||||||
RevTag t = tr.tag("t", a); // this doesn't create the refs/tags/t ref
|
|
||||||
tr.lightweightTag("t", t); |
|
||||||
|
|
||||||
gc.setExpireAgeMillis(0); |
|
||||||
fsTick(); |
|
||||||
gc.prune(Collections.<ObjectId> emptySet()); |
|
||||||
assertTrue(repo.hasObject(t)); |
|
||||||
assertTrue(repo.hasObject(a)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void branch_historyNotPruned() throws Exception { |
|
||||||
RevCommit tip = commitChain(10); |
|
||||||
tr.branch("b").update(tip); |
|
||||||
gc.setExpireAgeMillis(0); |
|
||||||
fsTick(); |
|
||||||
gc.prune(Collections.<ObjectId> emptySet()); |
|
||||||
do { |
|
||||||
assertTrue(repo.hasObject(tip)); |
|
||||||
tr.parseBody(tip); |
|
||||||
RevTree t = tip.getTree(); |
|
||||||
assertTrue(repo.hasObject(t)); |
|
||||||
assertTrue(repo.hasObject(tr.get(t, "a"))); |
|
||||||
tip = tip.getParentCount() > 0 ? tip.getParent(0) : null; |
|
||||||
} while (tip != null); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void deleteBranch_historyPruned() throws Exception { |
|
||||||
RevCommit tip = commitChain(10); |
|
||||||
tr.branch("b").update(tip); |
|
||||||
RefUpdate update = repo.updateRef("refs/heads/b"); |
|
||||||
update.setForceUpdate(true); |
|
||||||
update.delete(); |
|
||||||
gc.setExpireAgeMillis(0); |
|
||||||
fsTick(); |
|
||||||
gc.prune(Collections.<ObjectId> emptySet()); |
|
||||||
assertTrue(gc.getStatistics().numberOfLooseObjects == 0); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void deleteMergedBranch_historyNotPruned() throws Exception { |
|
||||||
RevCommit parent = tr.commit().create(); |
|
||||||
RevCommit b1Tip = tr.branch("b1").commit().parent(parent).add("x", "x") |
|
||||||
.create(); |
|
||||||
RevCommit b2Tip = tr.branch("b2").commit().parent(parent).add("y", "y") |
|
||||||
.create(); |
|
||||||
|
|
||||||
// merge b1Tip and b2Tip and update refs/heads/b1 to the merge commit
|
|
||||||
Merger merger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(repo); |
|
||||||
merger.merge(b1Tip, b2Tip); |
|
||||||
CommitBuilder cb = tr.commit(); |
|
||||||
cb.parent(b1Tip).parent(b2Tip); |
|
||||||
cb.setTopLevelTree(merger.getResultTreeId()); |
|
||||||
RevCommit mergeCommit = cb.create(); |
|
||||||
RefUpdate u = repo.updateRef("refs/heads/b1"); |
|
||||||
u.setNewObjectId(mergeCommit); |
|
||||||
u.update(); |
|
||||||
|
|
||||||
RefUpdate update = repo.updateRef("refs/heads/b2"); |
|
||||||
update.setForceUpdate(true); |
|
||||||
update.delete(); |
|
||||||
|
|
||||||
gc.setExpireAgeMillis(0); |
|
||||||
fsTick(); |
|
||||||
gc.prune(Collections.<ObjectId> emptySet()); |
|
||||||
assertTrue(repo.hasObject(b2Tip)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testPackAllObjectsInOnePack() 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); |
|
||||||
gc.gc(); |
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(0, stats.numberOfLooseObjects); |
|
||||||
assertEquals(4, stats.numberOfPackedObjects); |
|
||||||
assertEquals(1, stats.numberOfPackFiles); |
|
||||||
|
|
||||||
// Do the gc again and check that it hasn't changed anything
|
|
||||||
gc.gc(); |
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(0, stats.numberOfLooseObjects); |
|
||||||
assertEquals(4, stats.numberOfPackedObjects); |
|
||||||
assertEquals(1, stats.numberOfPackFiles); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testPackRepoWithCorruptReflog() throws Exception { |
|
||||||
// create a reflog entry "0000... 0000... foobar" by doing an initial
|
|
||||||
// refupdate for HEAD which points to a non-existing ref. The
|
|
||||||
// All-Projects repo of gerrit instances had such entries
|
|
||||||
RefUpdate ru = repo.updateRef(Constants.HEAD); |
|
||||||
ru.link("refs/to/garbage"); |
|
||||||
tr.branch("refs/heads/master").commit().add("A", "A").add("B", "B") |
|
||||||
.create(); |
|
||||||
// make sure HEAD exists
|
|
||||||
Git.wrap(repo).checkout().setName("refs/heads/master").call(); |
|
||||||
gc.gc(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testKeepFiles() throws Exception { |
|
||||||
BranchBuilder bb = tr.branch("refs/heads/master"); |
|
||||||
bb.commit().add("A", "A").add("B", "B").create(); |
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(4, stats.numberOfLooseObjects); |
|
||||||
assertEquals(0, stats.numberOfPackedObjects); |
|
||||||
assertEquals(0, stats.numberOfPackFiles); |
|
||||||
gc.gc(); |
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(0, stats.numberOfLooseObjects); |
|
||||||
assertEquals(4, stats.numberOfPackedObjects); |
|
||||||
assertEquals(1, stats.numberOfPackFiles); |
|
||||||
|
|
||||||
Iterator<PackFile> packIt = repo.getObjectDatabase().getPacks() |
|
||||||
.iterator(); |
|
||||||
PackFile singlePack = packIt.next(); |
|
||||||
assertFalse(packIt.hasNext()); |
|
||||||
File keepFile = new File(singlePack.getPackFile().getPath() + ".keep"); |
|
||||||
assertFalse(keepFile.exists()); |
|
||||||
assertTrue(keepFile.createNewFile()); |
|
||||||
bb.commit().add("A", "A2").add("B", "B2").create(); |
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(4, stats.numberOfLooseObjects); |
|
||||||
assertEquals(4, stats.numberOfPackedObjects); |
|
||||||
assertEquals(1, stats.numberOfPackFiles); |
|
||||||
gc.gc(); |
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(0, stats.numberOfLooseObjects); |
|
||||||
assertEquals(8, stats.numberOfPackedObjects); |
|
||||||
assertEquals(2, stats.numberOfPackFiles); |
|
||||||
|
|
||||||
// check that no object is packed twice
|
|
||||||
Iterator<PackFile> packs = repo.getObjectDatabase().getPacks() |
|
||||||
.iterator(); |
|
||||||
PackIndex ind1 = packs.next().getIndex(); |
|
||||||
assertEquals(4, ind1.getObjectCount()); |
|
||||||
PackIndex ind2 = packs.next().getIndex(); |
|
||||||
assertEquals(4, ind2.getObjectCount()); |
|
||||||
for (MutableEntry e: ind1) |
|
||||||
if (ind2.hasObject(e.toObjectId())) |
|
||||||
assertFalse( |
|
||||||
"the following object is in both packfiles: " |
|
||||||
+ e.toObjectId(), |
|
||||||
ind2.hasObject(e.toObjectId())); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testPackRepoWithNoRefs() throws Exception { |
|
||||||
tr.commit().add("A", "A").add("B", "B").create(); |
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(4, stats.numberOfLooseObjects); |
|
||||||
assertEquals(0, stats.numberOfPackedObjects); |
|
||||||
gc.gc(); |
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(4, stats.numberOfLooseObjects); |
|
||||||
assertEquals(0, stats.numberOfPackedObjects); |
|
||||||
assertEquals(0, stats.numberOfPackFiles); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testPack2Commits() 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(); |
|
||||||
|
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(8, stats.numberOfLooseObjects); |
|
||||||
assertEquals(0, stats.numberOfPackedObjects); |
|
||||||
gc.gc(); |
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(0, stats.numberOfLooseObjects); |
|
||||||
assertEquals(8, stats.numberOfPackedObjects); |
|
||||||
assertEquals(1, stats.numberOfPackFiles); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testPackCommitsAndLooseOne() 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(); |
|
||||||
tr.update("refs/heads/master", first); |
|
||||||
|
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(8, stats.numberOfLooseObjects); |
|
||||||
assertEquals(0, stats.numberOfPackedObjects); |
|
||||||
gc.gc(); |
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(0, stats.numberOfLooseObjects); |
|
||||||
assertEquals(8, stats.numberOfPackedObjects); |
|
||||||
assertEquals(2, stats.numberOfPackFiles); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testNotPackTwice() 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(); |
|
||||||
bb.commit().message("A").add("A", "A").create(); |
|
||||||
RevCommit second = tr.commit().parent(first).message("R").add("R", "Q") |
|
||||||
.create(); |
|
||||||
tr.update("refs/tags/t1", second); |
|
||||||
|
|
||||||
Collection<PackFile> oldPacks = tr.getRepository().getObjectDatabase() |
|
||||||
.getPacks(); |
|
||||||
assertEquals(0, oldPacks.size()); |
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(11, stats.numberOfLooseObjects); |
|
||||||
assertEquals(0, stats.numberOfPackedObjects); |
|
||||||
|
|
||||||
gc.setExpireAgeMillis(0); |
|
||||||
fsTick(); |
|
||||||
gc.gc(); |
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(0, stats.numberOfLooseObjects); |
|
||||||
|
|
||||||
Iterator<PackFile> pIt = repo.getObjectDatabase().getPacks().iterator(); |
|
||||||
long c = pIt.next().getObjectCount(); |
|
||||||
if (c == 9) |
|
||||||
assertEquals(2, pIt.next().getObjectCount()); |
|
||||||
else { |
|
||||||
assertEquals(2, c); |
|
||||||
assertEquals(9, pIt.next().getObjectCount()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testPackCommitsAndLooseOneNoReflog() 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(); |
|
||||||
tr.update("refs/heads/master", first); |
|
||||||
|
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(8, stats.numberOfLooseObjects); |
|
||||||
assertEquals(0, stats.numberOfPackedObjects); |
|
||||||
|
|
||||||
FileUtils.delete(new File(repo.getDirectory(), "logs/HEAD"), |
|
||||||
FileUtils.RETRY | FileUtils.SKIP_MISSING); |
|
||||||
FileUtils.delete( |
|
||||||
new File(repo.getDirectory(), "logs/refs/heads/master"), |
|
||||||
FileUtils.RETRY | FileUtils.SKIP_MISSING); |
|
||||||
gc.gc(); |
|
||||||
|
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(4, stats.numberOfLooseObjects); |
|
||||||
assertEquals(4, stats.numberOfPackedObjects); |
|
||||||
assertEquals(1, stats.numberOfPackFiles); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testPackCommitsAndLooseOneWithPruneNow() 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(); |
|
||||||
tr.update("refs/heads/master", first); |
|
||||||
|
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(8, stats.numberOfLooseObjects); |
|
||||||
assertEquals(0, stats.numberOfPackedObjects); |
|
||||||
gc.setExpireAgeMillis(0); |
|
||||||
fsTick(); |
|
||||||
gc.gc(); |
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(0, stats.numberOfLooseObjects); |
|
||||||
assertEquals(8, stats.numberOfPackedObjects); |
|
||||||
assertEquals(2, stats.numberOfPackFiles); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testPackCommitsAndLooseOneWithPruneNowNoReflog() |
|
||||||
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(); |
|
||||||
tr.update("refs/heads/master", first); |
|
||||||
|
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(8, stats.numberOfLooseObjects); |
|
||||||
assertEquals(0, stats.numberOfPackedObjects); |
|
||||||
|
|
||||||
FileUtils.delete(new File(repo.getDirectory(), "logs/HEAD"), |
|
||||||
FileUtils.RETRY | FileUtils.SKIP_MISSING); |
|
||||||
FileUtils.delete( |
|
||||||
new File(repo.getDirectory(), "logs/refs/heads/master"), |
|
||||||
FileUtils.RETRY | FileUtils.SKIP_MISSING); |
|
||||||
gc.setExpireAgeMillis(0); |
|
||||||
gc.gc(); |
|
||||||
|
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(0, stats.numberOfLooseObjects); |
|
||||||
assertEquals(4, stats.numberOfPackedObjects); |
|
||||||
assertEquals(1, stats.numberOfPackFiles); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testIndexSavesObjects() 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(); |
|
||||||
bb.commit().add("A", "A3"); // this new content in index should survive
|
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(9, stats.numberOfLooseObjects); |
|
||||||
assertEquals(0, stats.numberOfPackedObjects); |
|
||||||
gc.gc(); |
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(1, stats.numberOfLooseObjects); |
|
||||||
assertEquals(8, stats.numberOfPackedObjects); |
|
||||||
assertEquals(1, stats.numberOfPackFiles); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testIndexSavesObjectsWithPruneNow() 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(); |
|
||||||
bb.commit().add("A", "A3"); // this new content in index should survive
|
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(9, stats.numberOfLooseObjects); |
|
||||||
assertEquals(0, stats.numberOfPackedObjects); |
|
||||||
gc.setExpireAgeMillis(0); |
|
||||||
fsTick(); |
|
||||||
gc.gc(); |
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(0, stats.numberOfLooseObjects); |
|
||||||
assertEquals(8, stats.numberOfPackedObjects); |
|
||||||
assertEquals(1, stats.numberOfPackFiles); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testPruneNone() 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(); |
|
||||||
new File(repo.getDirectory(), Constants.LOGS + "/refs/heads/master") |
|
||||||
.delete(); |
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(8, stats.numberOfLooseObjects); |
|
||||||
gc.setExpireAgeMillis(0); |
|
||||||
fsTick(); |
|
||||||
gc.prune(Collections.<ObjectId> emptySet()); |
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(8, stats.numberOfLooseObjects); |
|
||||||
tr.blob("x"); |
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(9, stats.numberOfLooseObjects); |
|
||||||
gc.prune(Collections.<ObjectId> emptySet()); |
|
||||||
stats = gc.getStatistics(); |
|
||||||
assertEquals(8, stats.numberOfLooseObjects); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Create a chain of commits of given depth. |
|
||||||
* <p> |
|
||||||
* Each commit contains one file named "a" containing the index of the |
|
||||||
* commit in the chain as its content. The created commit chain is |
|
||||||
* referenced from any ref. |
|
||||||
* <p> |
|
||||||
* A chain of depth = N will create 3*N objects in Gits object database. For |
|
||||||
* each depth level three objects are created: the commit object, the |
|
||||||
* top-level tree object and a blob for the content of the file "a". |
|
||||||
* |
|
||||||
* @param depth |
|
||||||
* the depth of the commit chain. |
|
||||||
* @return the commit that is the tip of the commit chain |
|
||||||
* @throws Exception |
|
||||||
*/ |
|
||||||
private RevCommit commitChain(int depth) throws Exception { |
|
||||||
if (depth <= 0) |
|
||||||
throw new IllegalArgumentException("Chain depth must be > 0"); |
|
||||||
CommitBuilder cb = tr.commit(); |
|
||||||
RevCommit tip; |
|
||||||
do { |
|
||||||
--depth; |
|
||||||
tip = cb.add("a", "" + depth).message("" + depth).create(); |
|
||||||
cb = cb.child(); |
|
||||||
} while (depth > 0); |
|
||||||
return tip; |
|
||||||
} |
|
||||||
|
|
||||||
private long lastModified(AnyObjectId objectId) { |
|
||||||
return repo.getObjectDatabase().fileFor(objectId).lastModified(); |
|
||||||
} |
|
||||||
|
|
||||||
private static void fsTick() throws InterruptedException, IOException { |
|
||||||
RepositoryTestCase.fsTick(null); |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,162 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2012, Christian Halstrick <christian.halstrick@sap.com> |
||||||
|
* and other copyright owners as documented in the project's IP log. |
||||||
|
* |
||||||
|
* This program and the accompanying materials are made available |
||||||
|
* under the terms of the Eclipse Distribution License v1.0 which |
||||||
|
* accompanies this distribution, is reproduced below, and is |
||||||
|
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||||
|
* |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or |
||||||
|
* without modification, are permitted provided that the following |
||||||
|
* conditions are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above |
||||||
|
* copyright notice, this list of conditions and the following |
||||||
|
* disclaimer in the documentation and/or other materials provided |
||||||
|
* with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||||
|
* names of its contributors may be used to endorse or promote |
||||||
|
* products derived from this software without specific prior |
||||||
|
* written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.eclipse.jgit.internal.storage.file; |
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.util.Collection; |
||||||
|
import java.util.Iterator; |
||||||
|
|
||||||
|
import org.eclipse.jgit.junit.TestRepository.BranchBuilder; |
||||||
|
import org.eclipse.jgit.revwalk.RevCommit; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
public class GcBasicPackingTest extends GcTestCase { |
||||||
|
@Test |
||||||
|
public void repackEmptyRepo_noPackCreated() throws IOException { |
||||||
|
gc.repack(); |
||||||
|
assertEquals(0, repo.getObjectDatabase().getPacks().size()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testPackRepoWithNoRefs() throws Exception { |
||||||
|
tr.commit().add("A", "A").add("B", "B").create(); |
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(4, stats.numberOfLooseObjects); |
||||||
|
assertEquals(0, stats.numberOfPackedObjects); |
||||||
|
gc.gc(); |
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(4, stats.numberOfLooseObjects); |
||||||
|
assertEquals(0, stats.numberOfPackedObjects); |
||||||
|
assertEquals(0, stats.numberOfPackFiles); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testPack2Commits() 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(); |
||||||
|
|
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(8, stats.numberOfLooseObjects); |
||||||
|
assertEquals(0, stats.numberOfPackedObjects); |
||||||
|
gc.gc(); |
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(0, stats.numberOfLooseObjects); |
||||||
|
assertEquals(8, stats.numberOfPackedObjects); |
||||||
|
assertEquals(1, stats.numberOfPackFiles); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testPackAllObjectsInOnePack() 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); |
||||||
|
gc.gc(); |
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(0, stats.numberOfLooseObjects); |
||||||
|
assertEquals(4, stats.numberOfPackedObjects); |
||||||
|
assertEquals(1, stats.numberOfPackFiles); |
||||||
|
|
||||||
|
// Do the gc again and check that it hasn't changed anything
|
||||||
|
gc.gc(); |
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(0, stats.numberOfLooseObjects); |
||||||
|
assertEquals(4, stats.numberOfPackedObjects); |
||||||
|
assertEquals(1, stats.numberOfPackFiles); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testPackCommitsAndLooseOne() 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(); |
||||||
|
tr.update("refs/heads/master", first); |
||||||
|
|
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(8, stats.numberOfLooseObjects); |
||||||
|
assertEquals(0, stats.numberOfPackedObjects); |
||||||
|
gc.gc(); |
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(0, stats.numberOfLooseObjects); |
||||||
|
assertEquals(8, stats.numberOfPackedObjects); |
||||||
|
assertEquals(2, stats.numberOfPackFiles); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testNotPackTwice() 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(); |
||||||
|
bb.commit().message("A").add("A", "A").create(); |
||||||
|
RevCommit second = tr.commit().parent(first).message("R").add("R", "Q") |
||||||
|
.create(); |
||||||
|
tr.update("refs/tags/t1", second); |
||||||
|
|
||||||
|
Collection<PackFile> oldPacks = tr.getRepository().getObjectDatabase() |
||||||
|
.getPacks(); |
||||||
|
assertEquals(0, oldPacks.size()); |
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(11, stats.numberOfLooseObjects); |
||||||
|
assertEquals(0, stats.numberOfPackedObjects); |
||||||
|
|
||||||
|
gc.setExpireAgeMillis(0); |
||||||
|
fsTick(); |
||||||
|
gc.gc(); |
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(0, stats.numberOfLooseObjects); |
||||||
|
|
||||||
|
Iterator<PackFile> pIt = repo.getObjectDatabase().getPacks().iterator(); |
||||||
|
long c = pIt.next().getObjectCount(); |
||||||
|
if (c == 9) |
||||||
|
assertEquals(2, pIt.next().getObjectCount()); |
||||||
|
else { |
||||||
|
assertEquals(2, c); |
||||||
|
assertEquals(9, pIt.next().getObjectCount()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,119 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2012, Christian Halstrick <christian.halstrick@sap.com> |
||||||
|
* and other copyright owners as documented in the project's IP log. |
||||||
|
* |
||||||
|
* This program and the accompanying materials are made available |
||||||
|
* under the terms of the Eclipse Distribution License v1.0 which |
||||||
|
* accompanies this distribution, is reproduced below, and is |
||||||
|
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||||
|
* |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or |
||||||
|
* without modification, are permitted provided that the following |
||||||
|
* conditions are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above |
||||||
|
* copyright notice, this list of conditions and the following |
||||||
|
* disclaimer in the documentation and/or other materials provided |
||||||
|
* with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||||
|
* names of its contributors may be used to endorse or promote |
||||||
|
* products derived from this software without specific prior |
||||||
|
* written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.eclipse.jgit.internal.storage.file; |
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue; |
||||||
|
|
||||||
|
import java.util.Collections; |
||||||
|
|
||||||
|
import org.eclipse.jgit.junit.TestRepository.CommitBuilder; |
||||||
|
import org.eclipse.jgit.lib.ObjectId; |
||||||
|
import org.eclipse.jgit.lib.RefUpdate; |
||||||
|
import org.eclipse.jgit.merge.MergeStrategy; |
||||||
|
import org.eclipse.jgit.merge.Merger; |
||||||
|
import org.eclipse.jgit.revwalk.RevCommit; |
||||||
|
import org.eclipse.jgit.revwalk.RevTree; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
public class GcBranchPrunedTest extends GcTestCase { |
||||||
|
|
||||||
|
@Test |
||||||
|
public void branch_historyNotPruned() throws Exception { |
||||||
|
RevCommit tip = commitChain(10); |
||||||
|
tr.branch("b").update(tip); |
||||||
|
gc.setExpireAgeMillis(0); |
||||||
|
fsTick(); |
||||||
|
gc.prune(Collections.<ObjectId> emptySet()); |
||||||
|
do { |
||||||
|
assertTrue(repo.hasObject(tip)); |
||||||
|
tr.parseBody(tip); |
||||||
|
RevTree t = tip.getTree(); |
||||||
|
assertTrue(repo.hasObject(t)); |
||||||
|
assertTrue(repo.hasObject(tr.get(t, "a"))); |
||||||
|
tip = tip.getParentCount() > 0 ? tip.getParent(0) : null; |
||||||
|
} while (tip != null); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void deleteBranch_historyPruned() throws Exception { |
||||||
|
RevCommit tip = commitChain(10); |
||||||
|
tr.branch("b").update(tip); |
||||||
|
RefUpdate update = repo.updateRef("refs/heads/b"); |
||||||
|
update.setForceUpdate(true); |
||||||
|
update.delete(); |
||||||
|
gc.setExpireAgeMillis(0); |
||||||
|
fsTick(); |
||||||
|
gc.prune(Collections.<ObjectId> emptySet()); |
||||||
|
assertTrue(gc.getStatistics().numberOfLooseObjects == 0); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void deleteMergedBranch_historyNotPruned() throws Exception { |
||||||
|
RevCommit parent = tr.commit().create(); |
||||||
|
RevCommit b1Tip = tr.branch("b1").commit().parent(parent).add("x", "x") |
||||||
|
.create(); |
||||||
|
RevCommit b2Tip = tr.branch("b2").commit().parent(parent).add("y", "y") |
||||||
|
.create(); |
||||||
|
|
||||||
|
// merge b1Tip and b2Tip and update refs/heads/b1 to the merge commit
|
||||||
|
Merger merger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(repo); |
||||||
|
merger.merge(b1Tip, b2Tip); |
||||||
|
CommitBuilder cb = tr.commit(); |
||||||
|
cb.parent(b1Tip).parent(b2Tip); |
||||||
|
cb.setTopLevelTree(merger.getResultTreeId()); |
||||||
|
RevCommit mergeCommit = cb.create(); |
||||||
|
RefUpdate u = repo.updateRef("refs/heads/b1"); |
||||||
|
u.setNewObjectId(mergeCommit); |
||||||
|
u.update(); |
||||||
|
|
||||||
|
RefUpdate update = repo.updateRef("refs/heads/b2"); |
||||||
|
update.setForceUpdate(true); |
||||||
|
update.delete(); |
||||||
|
|
||||||
|
gc.setExpireAgeMillis(0); |
||||||
|
fsTick(); |
||||||
|
gc.prune(Collections.<ObjectId> emptySet()); |
||||||
|
assertTrue(repo.hasObject(b2Tip)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,119 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2012, Christian Halstrick <christian.halstrick@sap.com> |
||||||
|
* and other copyright owners as documented in the project's IP log. |
||||||
|
* |
||||||
|
* This program and the accompanying materials are made available |
||||||
|
* under the terms of the Eclipse Distribution License v1.0 which |
||||||
|
* accompanies this distribution, is reproduced below, and is |
||||||
|
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||||
|
* |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or |
||||||
|
* without modification, are permitted provided that the following |
||||||
|
* conditions are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above |
||||||
|
* copyright notice, this list of conditions and the following |
||||||
|
* disclaimer in the documentation and/or other materials provided |
||||||
|
* with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||||
|
* names of its contributors may be used to endorse or promote |
||||||
|
* products derived from this software without specific prior |
||||||
|
* written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.eclipse.jgit.internal.storage.file; |
||||||
|
|
||||||
|
import static java.lang.Integer.valueOf; |
||||||
|
import static org.junit.Assert.assertEquals; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.util.concurrent.BrokenBarrierException; |
||||||
|
import java.util.concurrent.Callable; |
||||||
|
import java.util.concurrent.CyclicBarrier; |
||||||
|
import java.util.concurrent.ExecutorService; |
||||||
|
import java.util.concurrent.Executors; |
||||||
|
import java.util.concurrent.Future; |
||||||
|
import java.util.concurrent.TimeUnit; |
||||||
|
|
||||||
|
import org.eclipse.jgit.internal.JGitText; |
||||||
|
import org.eclipse.jgit.lib.EmptyProgressMonitor; |
||||||
|
import org.eclipse.jgit.revwalk.RevBlob; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
public class GcConcurrentTest extends GcTestCase { |
||||||
|
@Test |
||||||
|
public void concurrentRepack() throws Exception { |
||||||
|
final CyclicBarrier syncPoint = new CyclicBarrier(2); |
||||||
|
|
||||||
|
class DoRepack extends EmptyProgressMonitor implements |
||||||
|
Callable<Integer> { |
||||||
|
|
||||||
|
public void beginTask(String title, int totalWork) { |
||||||
|
if (title.equals(JGitText.get().writingObjects)) { |
||||||
|
try { |
||||||
|
syncPoint.await(); |
||||||
|
} catch (InterruptedException e) { |
||||||
|
Thread.currentThread().interrupt(); |
||||||
|
} catch (BrokenBarrierException ignored) { |
||||||
|
//
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** @return 0 for success, 1 in case of error when writing pack */ |
||||||
|
public Integer call() throws Exception { |
||||||
|
try { |
||||||
|
gc.setProgressMonitor(this); |
||||||
|
gc.repack(); |
||||||
|
return valueOf(0); |
||||||
|
} catch (IOException e) { |
||||||
|
// leave the syncPoint in broken state so any awaiting
|
||||||
|
// threads and any threads that call await in the future get
|
||||||
|
// the BrokenBarrierException
|
||||||
|
Thread.currentThread().interrupt(); |
||||||
|
try { |
||||||
|
syncPoint.await(); |
||||||
|
} catch (InterruptedException ignored) { |
||||||
|
//
|
||||||
|
} |
||||||
|
return valueOf(1); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
RevBlob a = tr.blob("a"); |
||||||
|
tr.lightweightTag("t", a); |
||||||
|
|
||||||
|
ExecutorService pool = Executors.newFixedThreadPool(2); |
||||||
|
try { |
||||||
|
DoRepack repack1 = new DoRepack(); |
||||||
|
DoRepack repack2 = new DoRepack(); |
||||||
|
Future<Integer> result1 = pool.submit(repack1); |
||||||
|
Future<Integer> result2 = pool.submit(repack2); |
||||||
|
assertEquals(0, result1.get().intValue() + result2.get().intValue()); |
||||||
|
} finally { |
||||||
|
pool.shutdown(); |
||||||
|
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,85 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2012, Christian Halstrick <christian.halstrick@sap.com> |
||||||
|
* and other copyright owners as documented in the project's IP log. |
||||||
|
* |
||||||
|
* This program and the accompanying materials are made available |
||||||
|
* under the terms of the Eclipse Distribution License v1.0 which |
||||||
|
* accompanies this distribution, is reproduced below, and is |
||||||
|
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||||
|
* |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or |
||||||
|
* without modification, are permitted provided that the following |
||||||
|
* conditions are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above |
||||||
|
* copyright notice, this list of conditions and the following |
||||||
|
* disclaimer in the documentation and/or other materials provided |
||||||
|
* with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||||
|
* names of its contributors may be used to endorse or promote |
||||||
|
* products derived from this software without specific prior |
||||||
|
* written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.eclipse.jgit.internal.storage.file; |
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals; |
||||||
|
|
||||||
|
import org.eclipse.jgit.junit.TestRepository.BranchBuilder; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
public class GcDirCacheSavesObjectsTest extends GcTestCase { |
||||||
|
@Test |
||||||
|
public void testDirCacheSavesObjects() 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(); |
||||||
|
bb.commit().add("A", "A3"); // this new content in index should survive
|
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(9, stats.numberOfLooseObjects); |
||||||
|
assertEquals(0, stats.numberOfPackedObjects); |
||||||
|
gc.gc(); |
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(1, stats.numberOfLooseObjects); |
||||||
|
assertEquals(8, stats.numberOfPackedObjects); |
||||||
|
assertEquals(1, stats.numberOfPackFiles); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testDirCacheSavesObjectsWithPruneNow() 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(); |
||||||
|
bb.commit().add("A", "A3"); // this new content in index should survive
|
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(9, stats.numberOfLooseObjects); |
||||||
|
assertEquals(0, stats.numberOfPackedObjects); |
||||||
|
gc.setExpireAgeMillis(0); |
||||||
|
fsTick(); |
||||||
|
gc.gc(); |
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(0, stats.numberOfLooseObjects); |
||||||
|
assertEquals(8, stats.numberOfPackedObjects); |
||||||
|
assertEquals(1, stats.numberOfPackFiles); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,104 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2012, Christian Halstrick <christian.halstrick@sap.com> |
||||||
|
* and other copyright owners as documented in the project's IP log. |
||||||
|
* |
||||||
|
* This program and the accompanying materials are made available |
||||||
|
* under the terms of the Eclipse Distribution License v1.0 which |
||||||
|
* accompanies this distribution, is reproduced below, and is |
||||||
|
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||||
|
* |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or |
||||||
|
* without modification, are permitted provided that the following |
||||||
|
* conditions are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above |
||||||
|
* copyright notice, this list of conditions and the following |
||||||
|
* disclaimer in the documentation and/or other materials provided |
||||||
|
* with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||||
|
* names of its contributors may be used to endorse or promote |
||||||
|
* products derived from this software without specific prior |
||||||
|
* written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.eclipse.jgit.internal.storage.file; |
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals; |
||||||
|
import static org.junit.Assert.assertFalse; |
||||||
|
import static org.junit.Assert.assertTrue; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.util.Iterator; |
||||||
|
|
||||||
|
import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry; |
||||||
|
import org.eclipse.jgit.junit.TestRepository.BranchBuilder; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
public class GcKeepFilesTest extends GcTestCase { |
||||||
|
@Test |
||||||
|
public void testKeepFiles() throws Exception { |
||||||
|
BranchBuilder bb = tr.branch("refs/heads/master"); |
||||||
|
bb.commit().add("A", "A").add("B", "B").create(); |
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(4, stats.numberOfLooseObjects); |
||||||
|
assertEquals(0, stats.numberOfPackedObjects); |
||||||
|
assertEquals(0, stats.numberOfPackFiles); |
||||||
|
gc.gc(); |
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(0, stats.numberOfLooseObjects); |
||||||
|
assertEquals(4, stats.numberOfPackedObjects); |
||||||
|
assertEquals(1, stats.numberOfPackFiles); |
||||||
|
|
||||||
|
Iterator<PackFile> packIt = repo.getObjectDatabase().getPacks() |
||||||
|
.iterator(); |
||||||
|
PackFile singlePack = packIt.next(); |
||||||
|
assertFalse(packIt.hasNext()); |
||||||
|
File keepFile = new File(singlePack.getPackFile().getPath() + ".keep"); |
||||||
|
assertFalse(keepFile.exists()); |
||||||
|
assertTrue(keepFile.createNewFile()); |
||||||
|
bb.commit().add("A", "A2").add("B", "B2").create(); |
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(4, stats.numberOfLooseObjects); |
||||||
|
assertEquals(4, stats.numberOfPackedObjects); |
||||||
|
assertEquals(1, stats.numberOfPackFiles); |
||||||
|
gc.gc(); |
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(0, stats.numberOfLooseObjects); |
||||||
|
assertEquals(8, stats.numberOfPackedObjects); |
||||||
|
assertEquals(2, stats.numberOfPackFiles); |
||||||
|
|
||||||
|
// check that no object is packed twice
|
||||||
|
Iterator<PackFile> packs = repo.getObjectDatabase().getPacks() |
||||||
|
.iterator(); |
||||||
|
PackIndex ind1 = packs.next().getIndex(); |
||||||
|
assertEquals(4, ind1.getObjectCount()); |
||||||
|
PackIndex ind2 = packs.next().getIndex(); |
||||||
|
assertEquals(4, ind2.getObjectCount()); |
||||||
|
for (MutableEntry e: ind1) |
||||||
|
if (ind2.hasObject(e.toObjectId())) |
||||||
|
assertFalse( |
||||||
|
"the following object is in both packfiles: " |
||||||
|
+ e.toObjectId(), |
||||||
|
ind2.hasObject(e.toObjectId())); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,180 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2012, Christian Halstrick <christian.halstrick@sap.com> |
||||||
|
* and other copyright owners as documented in the project's IP log. |
||||||
|
* |
||||||
|
* This program and the accompanying materials are made available |
||||||
|
* under the terms of the Eclipse Distribution License v1.0 which |
||||||
|
* accompanies this distribution, is reproduced below, and is |
||||||
|
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||||
|
* |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or |
||||||
|
* without modification, are permitted provided that the following |
||||||
|
* conditions are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above |
||||||
|
* copyright notice, this list of conditions and the following |
||||||
|
* disclaimer in the documentation and/or other materials provided |
||||||
|
* with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||||
|
* names of its contributors may be used to endorse or promote |
||||||
|
* products derived from this software without specific prior |
||||||
|
* written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.eclipse.jgit.internal.storage.file; |
||||||
|
|
||||||
|
import static java.lang.Integer.valueOf; |
||||||
|
import static org.junit.Assert.assertEquals; |
||||||
|
import static org.junit.Assert.assertSame; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.io.IOException; |
||||||
|
import java.util.concurrent.BrokenBarrierException; |
||||||
|
import java.util.concurrent.Callable; |
||||||
|
import java.util.concurrent.CyclicBarrier; |
||||||
|
import java.util.concurrent.ExecutorService; |
||||||
|
import java.util.concurrent.Executors; |
||||||
|
import java.util.concurrent.Future; |
||||||
|
import java.util.concurrent.TimeUnit; |
||||||
|
|
||||||
|
import org.eclipse.jgit.lib.Ref.Storage; |
||||||
|
import org.eclipse.jgit.lib.RefUpdate; |
||||||
|
import org.eclipse.jgit.lib.RefUpdate.Result; |
||||||
|
import org.eclipse.jgit.revwalk.RevBlob; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
public class GcPackRefsTest extends GcTestCase { |
||||||
|
@Test |
||||||
|
public void looseRefPacked() throws Exception { |
||||||
|
RevBlob a = tr.blob("a"); |
||||||
|
tr.lightweightTag("t", a); |
||||||
|
|
||||||
|
gc.packRefs(); |
||||||
|
assertSame(repo.getRef("t").getStorage(), Storage.PACKED); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void concurrentOnlyOneWritesPackedRefs() throws Exception { |
||||||
|
RevBlob a = tr.blob("a"); |
||||||
|
tr.lightweightTag("t", a); |
||||||
|
|
||||||
|
final CyclicBarrier syncPoint = new CyclicBarrier(2); |
||||||
|
|
||||||
|
Callable<Integer> packRefs = new Callable<Integer>() { |
||||||
|
|
||||||
|
/** @return 0 for success, 1 in case of error when writing pack */ |
||||||
|
public Integer call() throws Exception { |
||||||
|
syncPoint.await(); |
||||||
|
try { |
||||||
|
gc.packRefs(); |
||||||
|
return valueOf(0); |
||||||
|
} catch (IOException e) { |
||||||
|
return valueOf(1); |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
ExecutorService pool = Executors.newFixedThreadPool(2); |
||||||
|
try { |
||||||
|
Future<Integer> p1 = pool.submit(packRefs); |
||||||
|
Future<Integer> p2 = pool.submit(packRefs); |
||||||
|
assertEquals(1, p1.get().intValue() + p2.get().intValue()); |
||||||
|
} finally { |
||||||
|
pool.shutdown(); |
||||||
|
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void whileRefLockedRefNotPackedNoError() |
||||||
|
throws Exception { |
||||||
|
RevBlob a = tr.blob("a"); |
||||||
|
tr.lightweightTag("t1", a); |
||||||
|
tr.lightweightTag("t2", a); |
||||||
|
LockFile refLock = new LockFile(new File(repo.getDirectory(), |
||||||
|
"refs/tags/t1"), repo.getFS()); |
||||||
|
try { |
||||||
|
refLock.lock(); |
||||||
|
gc.packRefs(); |
||||||
|
} finally { |
||||||
|
refLock.unlock(); |
||||||
|
} |
||||||
|
|
||||||
|
assertSame(repo.getRef("refs/tags/t1").getStorage(), Storage.LOOSE); |
||||||
|
assertSame(repo.getRef("refs/tags/t2").getStorage(), Storage.PACKED); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void whileRefUpdatedRefUpdateSucceeds() |
||||||
|
throws Exception { |
||||||
|
RevBlob a = tr.blob("a"); |
||||||
|
tr.lightweightTag("t", a); |
||||||
|
final RevBlob b = tr.blob("b"); |
||||||
|
|
||||||
|
final CyclicBarrier refUpdateLockedRef = new CyclicBarrier(2); |
||||||
|
final CyclicBarrier packRefsDone = new CyclicBarrier(2); |
||||||
|
ExecutorService pool = Executors.newFixedThreadPool(2); |
||||||
|
try { |
||||||
|
Future<Result> result = pool.submit(new Callable<Result>() { |
||||||
|
|
||||||
|
public Result call() throws Exception { |
||||||
|
RefUpdate update = new RefDirectoryUpdate( |
||||||
|
(RefDirectory) repo.getRefDatabase(), |
||||||
|
repo.getRef("refs/tags/t")) { |
||||||
|
@Override |
||||||
|
public boolean isForceUpdate() { |
||||||
|
try { |
||||||
|
refUpdateLockedRef.await(); |
||||||
|
packRefsDone.await(); |
||||||
|
} catch (InterruptedException e) { |
||||||
|
Thread.currentThread().interrupt(); |
||||||
|
} catch (BrokenBarrierException e) { |
||||||
|
Thread.currentThread().interrupt(); |
||||||
|
} |
||||||
|
return super.isForceUpdate(); |
||||||
|
} |
||||||
|
}; |
||||||
|
update.setForceUpdate(true); |
||||||
|
update.setNewObjectId(b); |
||||||
|
return update.update(); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
pool.submit(new Callable<Void>() { |
||||||
|
public Void call() throws Exception { |
||||||
|
refUpdateLockedRef.await(); |
||||||
|
gc.packRefs(); |
||||||
|
packRefsDone.await(); |
||||||
|
return null; |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
assertSame(result.get(), Result.FORCED); |
||||||
|
|
||||||
|
} finally { |
||||||
|
pool.shutdownNow(); |
||||||
|
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); |
||||||
|
} |
||||||
|
|
||||||
|
assertEquals(repo.getRef("refs/tags/t").getObjectId(), b); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,120 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2012, Christian Halstrick <christian.halstrick@sap.com> |
||||||
|
* and other copyright owners as documented in the project's IP log. |
||||||
|
* |
||||||
|
* This program and the accompanying materials are made available |
||||||
|
* under the terms of the Eclipse Distribution License v1.0 which |
||||||
|
* accompanies this distribution, is reproduced below, and is |
||||||
|
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||||
|
* |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or |
||||||
|
* without modification, are permitted provided that the following |
||||||
|
* conditions are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above |
||||||
|
* copyright notice, this list of conditions and the following |
||||||
|
* disclaimer in the documentation and/or other materials provided |
||||||
|
* with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||||
|
* names of its contributors may be used to endorse or promote |
||||||
|
* products derived from this software without specific prior |
||||||
|
* written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.eclipse.jgit.internal.storage.file; |
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals; |
||||||
|
import static org.junit.Assert.assertFalse; |
||||||
|
import static org.junit.Assert.assertTrue; |
||||||
|
|
||||||
|
import java.util.Collections; |
||||||
|
import java.util.Date; |
||||||
|
|
||||||
|
import org.eclipse.jgit.junit.TestRepository.BranchBuilder; |
||||||
|
import org.eclipse.jgit.lib.ObjectId; |
||||||
|
import org.eclipse.jgit.revwalk.RevBlob; |
||||||
|
import org.eclipse.jgit.revwalk.RevCommit; |
||||||
|
import org.eclipse.jgit.revwalk.RevTree; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
public class GcPruneNonReferencedTest extends GcTestCase { |
||||||
|
@Test |
||||||
|
public void nonReferencedNonExpiredObject_notPruned() throws Exception { |
||||||
|
RevBlob a = tr.blob("a"); |
||||||
|
gc.setExpire(new Date(lastModified(a))); |
||||||
|
gc.prune(Collections.<ObjectId> emptySet()); |
||||||
|
assertTrue(repo.hasObject(a)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void nonReferencedExpiredObject_pruned() throws Exception { |
||||||
|
RevBlob a = tr.blob("a"); |
||||||
|
gc.setExpireAgeMillis(0); |
||||||
|
fsTick(); |
||||||
|
gc.prune(Collections.<ObjectId> emptySet()); |
||||||
|
assertFalse(repo.hasObject(a)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void nonReferencedExpiredObjectTree_pruned() throws Exception { |
||||||
|
RevBlob a = tr.blob("a"); |
||||||
|
RevTree t = tr.tree(tr.file("a", a)); |
||||||
|
gc.setExpireAgeMillis(0); |
||||||
|
fsTick(); |
||||||
|
gc.prune(Collections.<ObjectId> emptySet()); |
||||||
|
assertFalse(repo.hasObject(t)); |
||||||
|
assertFalse(repo.hasObject(a)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void nonReferencedObjects_onlyExpiredPruned() throws Exception { |
||||||
|
RevBlob a = tr.blob("a"); |
||||||
|
gc.setExpire(new Date(lastModified(a) + 1)); |
||||||
|
|
||||||
|
fsTick(); |
||||||
|
RevBlob b = tr.blob("b"); |
||||||
|
|
||||||
|
gc.prune(Collections.<ObjectId> emptySet()); |
||||||
|
assertFalse(repo.hasObject(a)); |
||||||
|
assertTrue(repo.hasObject(b)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testPackCommitsAndLooseOneWithPruneNow() 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(); |
||||||
|
tr.update("refs/heads/master", first); |
||||||
|
|
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(8, stats.numberOfLooseObjects); |
||||||
|
assertEquals(0, stats.numberOfPackedObjects); |
||||||
|
gc.setExpireAgeMillis(0); |
||||||
|
fsTick(); |
||||||
|
gc.gc(); |
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(0, stats.numberOfLooseObjects); |
||||||
|
assertEquals(8, stats.numberOfPackedObjects); |
||||||
|
assertEquals(2, stats.numberOfPackFiles); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,146 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2012, Christian Halstrick <christian.halstrick@sap.com> |
||||||
|
* and other copyright owners as documented in the project's IP log. |
||||||
|
* |
||||||
|
* This program and the accompanying materials are made available |
||||||
|
* under the terms of the Eclipse Distribution License v1.0 which |
||||||
|
* accompanies this distribution, is reproduced below, and is |
||||||
|
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||||
|
* |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or |
||||||
|
* without modification, are permitted provided that the following |
||||||
|
* conditions are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above |
||||||
|
* copyright notice, this list of conditions and the following |
||||||
|
* disclaimer in the documentation and/or other materials provided |
||||||
|
* with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||||
|
* names of its contributors may be used to endorse or promote |
||||||
|
* products derived from this software without specific prior |
||||||
|
* written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.eclipse.jgit.internal.storage.file; |
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.util.Collections; |
||||||
|
|
||||||
|
import org.eclipse.jgit.api.Git; |
||||||
|
import org.eclipse.jgit.junit.TestRepository.BranchBuilder; |
||||||
|
import org.eclipse.jgit.lib.Constants; |
||||||
|
import org.eclipse.jgit.lib.ObjectId; |
||||||
|
import org.eclipse.jgit.lib.RefUpdate; |
||||||
|
import org.eclipse.jgit.revwalk.RevCommit; |
||||||
|
import org.eclipse.jgit.util.FileUtils; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
public class GcReflogTest extends GcTestCase { |
||||||
|
@Test |
||||||
|
public void testPruneNone() 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(); |
||||||
|
new File(repo.getDirectory(), Constants.LOGS + "/refs/heads/master") |
||||||
|
.delete(); |
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(8, stats.numberOfLooseObjects); |
||||||
|
gc.setExpireAgeMillis(0); |
||||||
|
fsTick(); |
||||||
|
gc.prune(Collections.<ObjectId> emptySet()); |
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(8, stats.numberOfLooseObjects); |
||||||
|
tr.blob("x"); |
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(9, stats.numberOfLooseObjects); |
||||||
|
gc.prune(Collections.<ObjectId> emptySet()); |
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(8, stats.numberOfLooseObjects); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testPackRepoWithCorruptReflog() throws Exception { |
||||||
|
// create a reflog entry "0000... 0000... foobar" by doing an initial
|
||||||
|
// refupdate for HEAD which points to a non-existing ref. The
|
||||||
|
// All-Projects repo of gerrit instances had such entries
|
||||||
|
RefUpdate ru = repo.updateRef(Constants.HEAD); |
||||||
|
ru.link("refs/to/garbage"); |
||||||
|
tr.branch("refs/heads/master").commit().add("A", "A").add("B", "B") |
||||||
|
.create(); |
||||||
|
// make sure HEAD exists
|
||||||
|
Git.wrap(repo).checkout().setName("refs/heads/master").call(); |
||||||
|
gc.gc(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testPackCommitsAndLooseOneNoReflog() 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(); |
||||||
|
tr.update("refs/heads/master", first); |
||||||
|
|
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(8, stats.numberOfLooseObjects); |
||||||
|
assertEquals(0, stats.numberOfPackedObjects); |
||||||
|
|
||||||
|
FileUtils.delete(new File(repo.getDirectory(), "logs/HEAD"), |
||||||
|
FileUtils.RETRY | FileUtils.SKIP_MISSING); |
||||||
|
FileUtils.delete( |
||||||
|
new File(repo.getDirectory(), "logs/refs/heads/master"), |
||||||
|
FileUtils.RETRY | FileUtils.SKIP_MISSING); |
||||||
|
gc.gc(); |
||||||
|
|
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(4, stats.numberOfLooseObjects); |
||||||
|
assertEquals(4, stats.numberOfPackedObjects); |
||||||
|
assertEquals(1, stats.numberOfPackFiles); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testPackCommitsAndLooseOneWithPruneNowNoReflog() |
||||||
|
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(); |
||||||
|
tr.update("refs/heads/master", first); |
||||||
|
|
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(8, stats.numberOfLooseObjects); |
||||||
|
assertEquals(0, stats.numberOfPackedObjects); |
||||||
|
|
||||||
|
FileUtils.delete(new File(repo.getDirectory(), "logs/HEAD"), |
||||||
|
FileUtils.RETRY | FileUtils.SKIP_MISSING); |
||||||
|
FileUtils.delete( |
||||||
|
new File(repo.getDirectory(), "logs/refs/heads/master"), |
||||||
|
FileUtils.RETRY | FileUtils.SKIP_MISSING); |
||||||
|
gc.setExpireAgeMillis(0); |
||||||
|
gc.gc(); |
||||||
|
|
||||||
|
stats = gc.getStatistics(); |
||||||
|
assertEquals(0, stats.numberOfLooseObjects); |
||||||
|
assertEquals(4, stats.numberOfPackedObjects); |
||||||
|
assertEquals(1, stats.numberOfPackFiles); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,78 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2012, Christian Halstrick <christian.halstrick@sap.com> |
||||||
|
* and other copyright owners as documented in the project's IP log. |
||||||
|
* |
||||||
|
* This program and the accompanying materials are made available |
||||||
|
* under the terms of the Eclipse Distribution License v1.0 which |
||||||
|
* accompanies this distribution, is reproduced below, and is |
||||||
|
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||||
|
* |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or |
||||||
|
* without modification, are permitted provided that the following |
||||||
|
* conditions are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above |
||||||
|
* copyright notice, this list of conditions and the following |
||||||
|
* disclaimer in the documentation and/or other materials provided |
||||||
|
* with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||||
|
* names of its contributors may be used to endorse or promote |
||||||
|
* products derived from this software without specific prior |
||||||
|
* written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.eclipse.jgit.internal.storage.file; |
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue; |
||||||
|
|
||||||
|
import java.util.Collections; |
||||||
|
|
||||||
|
import org.eclipse.jgit.lib.ObjectId; |
||||||
|
import org.eclipse.jgit.revwalk.RevBlob; |
||||||
|
import org.eclipse.jgit.revwalk.RevTag; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
public class GcTagTest extends GcTestCase { |
||||||
|
@Test |
||||||
|
public void lightweightTag_objectNotPruned() throws Exception { |
||||||
|
RevBlob a = tr.blob("a"); |
||||||
|
tr.lightweightTag("t", a); |
||||||
|
gc.setExpireAgeMillis(0); |
||||||
|
fsTick(); |
||||||
|
gc.prune(Collections.<ObjectId> emptySet()); |
||||||
|
assertTrue(repo.hasObject(a)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void annotatedTag_objectNotPruned() throws Exception { |
||||||
|
RevBlob a = tr.blob("a"); |
||||||
|
RevTag t = tr.tag("t", a); // this doesn't create the refs/tags/t ref
|
||||||
|
tr.lightweightTag("t", t); |
||||||
|
|
||||||
|
gc.setExpireAgeMillis(0); |
||||||
|
fsTick(); |
||||||
|
gc.prune(Collections.<ObjectId> emptySet()); |
||||||
|
assertTrue(repo.hasObject(t)); |
||||||
|
assertTrue(repo.hasObject(a)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,113 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2012, Christian Halstrick <christian.halstrick@sap.com> |
||||||
|
* and other copyright owners as documented in the project's IP log. |
||||||
|
* |
||||||
|
* This program and the accompanying materials are made available |
||||||
|
* under the terms of the Eclipse Distribution License v1.0 which |
||||||
|
* accompanies this distribution, is reproduced below, and is |
||||||
|
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||||
|
* |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or |
||||||
|
* without modification, are permitted provided that the following |
||||||
|
* conditions are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above |
||||||
|
* copyright notice, this list of conditions and the following |
||||||
|
* disclaimer in the documentation and/or other materials provided |
||||||
|
* with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||||
|
* names of its contributors may be used to endorse or promote |
||||||
|
* products derived from this software without specific prior |
||||||
|
* written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.eclipse.jgit.internal.storage.file; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
import org.eclipse.jgit.internal.storage.file.GC.RepoStatistics; |
||||||
|
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; |
||||||
|
import org.eclipse.jgit.junit.RepositoryTestCase; |
||||||
|
import org.eclipse.jgit.junit.TestRepository; |
||||||
|
import org.eclipse.jgit.junit.TestRepository.CommitBuilder; |
||||||
|
import org.eclipse.jgit.lib.AnyObjectId; |
||||||
|
import org.eclipse.jgit.revwalk.RevCommit; |
||||||
|
import org.junit.After; |
||||||
|
import org.junit.Before; |
||||||
|
|
||||||
|
public abstract class GcTestCase extends LocalDiskRepositoryTestCase { |
||||||
|
protected TestRepository<FileRepository> tr; |
||||||
|
protected FileRepository repo; |
||||||
|
protected GC gc; |
||||||
|
protected RepoStatistics stats; |
||||||
|
|
||||||
|
@Before |
||||||
|
public void setUp() throws Exception { |
||||||
|
super.setUp(); |
||||||
|
repo = createWorkRepository(); |
||||||
|
tr = new TestRepository<FileRepository>((repo)); |
||||||
|
gc = new GC(repo); |
||||||
|
} |
||||||
|
|
||||||
|
@After |
||||||
|
public void tearDown() throws Exception { |
||||||
|
super.tearDown(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a chain of commits of given depth. |
||||||
|
* <p> |
||||||
|
* Each commit contains one file named "a" containing the index of the |
||||||
|
* commit in the chain as its content. The created commit chain is |
||||||
|
* referenced from any ref. |
||||||
|
* <p> |
||||||
|
* A chain of depth = N will create 3*N objects in Gits object database. For |
||||||
|
* each depth level three objects are created: the commit object, the |
||||||
|
* top-level tree object and a blob for the content of the file "a". |
||||||
|
* |
||||||
|
* @param depth |
||||||
|
* the depth of the commit chain. |
||||||
|
* @return the commit that is the tip of the commit chain |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
protected RevCommit commitChain(int depth) throws Exception { |
||||||
|
if (depth <= 0) |
||||||
|
throw new IllegalArgumentException("Chain depth must be > 0"); |
||||||
|
CommitBuilder cb = tr.commit(); |
||||||
|
RevCommit tip; |
||||||
|
do { |
||||||
|
--depth; |
||||||
|
tip = cb.add("a", "" + depth).message("" + depth).create(); |
||||||
|
cb = cb.child(); |
||||||
|
} while (depth > 0); |
||||||
|
return tip; |
||||||
|
} |
||||||
|
|
||||||
|
protected long lastModified(AnyObjectId objectId) { |
||||||
|
return repo.getObjectDatabase().fileFor(objectId).lastModified(); |
||||||
|
} |
||||||
|
|
||||||
|
protected static void fsTick() throws InterruptedException, IOException { |
||||||
|
RepositoryTestCase.fsTick(null); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue