@ -46,12 +46,11 @@ package org.eclipse.jgit.storage.dfs;
import static org.eclipse.jgit.storage.dfs.DfsObjDatabase.PackSource.GC ;
import static org.eclipse.jgit.storage.dfs.DfsObjDatabase.PackSource.UNREACHABLE_GARBAGE ;
import static org.eclipse.jgit.storage.pack.PackExt.BITMAP_INDEX ;
import static org.eclipse.jgit.storage.pack.PackExt.PACK ;
import static org.eclipse.jgit.storage.pack.PackExt.INDEX ;
import static org.eclipse.jgit.storage.pack.PackExt.PACK ;
import java.io.IOException ;
import java.util.ArrayList ;
import java.util.Arrays ;
import java.util.Collections ;
import java.util.HashSet ;
import java.util.List ;
@ -69,6 +68,7 @@ import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.dfs.DfsObjDatabase.PackSource ;
import org.eclipse.jgit.storage.file.PackIndex ;
import org.eclipse.jgit.storage.pack.PackConfig ;
import org.eclipse.jgit.storage.pack.PackExt ;
import org.eclipse.jgit.storage.pack.PackWriter ;
import org.eclipse.jgit.util.io.CountingOutputStream ;
@ -90,6 +90,8 @@ public class DfsGarbageCollector {
private PackConfig packConfig ;
private long coalesceGarbageLimit = 50 < < 20 ;
private Map < String , Ref > refsBefore ;
private List < DfsPackFile > packsBefore ;
@ -139,6 +141,38 @@ public class DfsGarbageCollector {
return this ;
}
/** @return garbage packs smaller than this size will be repacked. */
public long getCoalesceGarbageLimit ( ) {
return coalesceGarbageLimit ;
}
/ * *
* Set the byte size limit for garbage packs to be repacked .
* < p >
* Any UNREACHABLE_GARBAGE pack smaller than this limit will be repacked at
* the end of the run . This allows the garbage collector to coalesce
* unreachable objects into a single file .
* < p >
* If an UNREACHABLE_GARBAGE pack is already larger than this limit it will
* be left alone by the garbage collector . This avoids unnecessary disk IO
* reading and copying the objects .
* < p >
* If limit is set to 0 the UNREACHABLE_GARBAGE coalesce is disabled . < br >
* If limit is set to { @link Long # MAX_VALUE } , everything is coalesced .
* < p >
* Keeping unreachable garbage prevents race conditions with repository
* changes that may suddenly need an object whose only copy was stored in
* the UNREACHABLE_GARBAGE pack .
*
* @param limit
* size in bytes .
* @return { @code this }
* /
public DfsGarbageCollector setCoalesceGarbageLimit ( long limit ) {
coalesceGarbageLimit = limit ;
return this ;
}
/ * *
* Create a single new pack file containing all of the live objects .
* < p >
@ -167,7 +201,7 @@ public class DfsGarbageCollector {
objdb . clearCache ( ) ;
refsBefore = repo . getAllRefs ( ) ;
packsBefore = Arrays . asList ( objdb . getPacks ( ) ) ;
packsBefore = packsToRebuild ( ) ;
if ( packsBefore . isEmpty ( ) )
return true ;
@ -203,6 +237,19 @@ public class DfsGarbageCollector {
}
}
private List < DfsPackFile > packsToRebuild ( ) throws IOException {
DfsPackFile [ ] packs = objdb . getPacks ( ) ;
List < DfsPackFile > out = new ArrayList < DfsPackFile > ( packs . length ) ;
for ( DfsPackFile p : packs ) {
DfsPackDescription d = p . getPackDescription ( ) ;
if ( d . getPackSource ( ) ! = UNREACHABLE_GARBAGE )
out . add ( p ) ;
else if ( d . getFileSize ( PackExt . PACK ) < coalesceGarbageLimit )
out . add ( p ) ;
}
return out ;
}
/** @return all of the source packs that fed into this compaction. */
public List < DfsPackDescription > getSourcePacks ( ) {
return toPrune ( ) ;
@ -264,9 +311,9 @@ public class DfsGarbageCollector {
PackWriter pw = newPackWriter ( ) ;
try {
RevWalk pool = new RevWalk ( ctx ) ;
pm . beginTask ( "Finding garbage" , ( int ) getObjectsBefore ( ) ) ;
for ( DfsPackFile oldPack : packsBefore ) {
PackIndex oldIdx = oldPack . getPackIndex ( ctx ) ;
pm . beginTask ( "Finding garbage" , ( int ) oldIdx . getObjectCount ( ) ) ;
for ( PackIndex . MutableEntry ent : oldIdx ) {
pm . update ( 1 ) ;
ObjectId id = ent . toObjectId ( ) ;
@ -276,8 +323,8 @@ public class DfsGarbageCollector {
int type = oldPack . getObjectType ( ctx , ent . getOffset ( ) ) ;
pw . addObject ( pool . lookupAny ( id , type ) ) ;
}
pm . endTask ( ) ;
}
pm . endTask ( ) ;
if ( 0 < pw . getObjectCount ( ) )
writePack ( UNREACHABLE_GARBAGE , pw , pm ) ;
} finally {