@ -65,8 +65,6 @@ final class DeltaWindow {
private final ObjectReader reader ;
private final ObjectReader reader ;
private final ProgressMonitor monitor ;
private final ProgressMonitor monitor ;
private final DeltaWindowEntry [ ] window ;
/** Maximum number of bytes to admit to the window at once. */
/** Maximum number of bytes to admit to the window at once. */
private final long maxMemory ;
private final long maxMemory ;
@ -74,9 +72,7 @@ final class DeltaWindow {
private final int maxDepth ;
private final int maxDepth ;
private final ObjectToPack [ ] toSearch ;
private final ObjectToPack [ ] toSearch ;
private int cur ;
private int cur ;
private int end ;
private int end ;
/** Amount of memory we have loaded right now. */
/** Amount of memory we have loaded right now. */
@ -84,9 +80,6 @@ final class DeltaWindow {
// The object we are currently considering needs a lot of state:
// The object we are currently considering needs a lot of state:
/** Position of {@link #res} within {@link #window} array. */
private int resSlot ;
/ * *
/ * *
* Maximum delta chain depth the current object can have .
* Maximum delta chain depth the current object can have .
* < p >
* < p >
@ -100,8 +93,8 @@ final class DeltaWindow {
/** If we have a delta for {@link #res}, this is the shortest found yet. */
/** If we have a delta for {@link #res}, this is the shortest found yet. */
private TemporaryBuffer . Heap bestDelta ;
private TemporaryBuffer . Heap bestDelta ;
/** If we have {@link #bestDelta}, the window position it was created by . */
/** If we have {@link #bestDelta}, the window entry it was created from . */
private int bestSlot ;
private DeltaWindowEntry bestBase ;
/** Used to compress cached deltas. */
/** Used to compress cached deltas. */
private Deflater deflater ;
private Deflater deflater ;
@ -117,23 +110,9 @@ final class DeltaWindow {
cur = beginIndex ;
cur = beginIndex ;
end = endIndex ;
end = endIndex ;
// C Git increases the window size supplied by the user by 1.
// We don't know why it does this, but if the user asks for
// window=10, it actually processes with window=11. Because
// the window size has the largest direct impact on the final
// pack file size, we match this odd behavior here to give us
// a better chance of producing a similar sized pack as C Git.
//
// We would prefer to directly honor the user's request since
// PackWriter has a minimum of 2 for the window size, but then
// users might complain that JGit is creating a bigger pack file.
//
window = new DeltaWindowEntry [ config . getDeltaSearchWindowSize ( ) + 1 ] ;
for ( int i = 0 ; i < window . length ; i + + )
window [ i ] = new DeltaWindowEntry ( ) ;
maxMemory = Math . max ( 0 , config . getDeltaSearchMemoryLimit ( ) ) ;
maxMemory = Math . max ( 0 , config . getDeltaSearchMemoryLimit ( ) ) ;
maxDepth = config . getMaxDeltaDepth ( ) ;
maxDepth = config . getMaxDeltaDepth ( ) ;
res = DeltaWindowEntry . createWindow ( config . getDeltaSearchWindowSize ( ) ) ;
}
}
synchronized int remaining ( ) {
synchronized int remaining ( ) {
@ -167,15 +146,12 @@ final class DeltaWindow {
break ;
break ;
next = toSearch [ cur + + ] ;
next = toSearch [ cur + + ] ;
}
}
res = window [ resSlot ] ;
if ( maxMemory ! = 0 ) {
if ( maxMemory ! = 0 ) {
clear ( res ) ;
clear ( res ) ;
int tail = next ( resSlot ) ;
final long need = estimateSize ( next ) ;
final long need = estimateSize ( next ) ;
while ( maxMemory < loaded + need & & tail ! = resSlot ) {
DeltaWindowEntry n = res . next ;
clear ( window [ tail ] ) ;
for ( ; maxMemory < loaded + need & & n ! = res ; n = n . next )
tail = next ( tail ) ;
clear ( n ) ;
}
}
}
res . set ( next ) ;
res . set ( next ) ;
@ -231,11 +207,10 @@ final class DeltaWindow {
// Loop through the window backwards, considering every entry.
// Loop through the window backwards, considering every entry.
// This lets us look at the bigger objects that came before.
// This lets us look at the bigger objects that came before.
//
//
for ( int srcSlot = prior ( resSlot ) ; srcSlot ! = resSlot ; srcSlot = prior ( srcSlot ) ) {
for ( DeltaWindowEntry src = res . prev ; src ! = res ; src = src . prev ) {
DeltaWindowEntry src = window [ srcSlot ] ;
if ( src . empty ( ) )
if ( src . empty ( ) )
break ;
break ;
if ( delta ( src , srcSlot ) /* == NEXT_SRC */ )
if ( delta ( src ) /* == NEXT_SRC */ )
continue ;
continue ;
bestDelta = null ;
bestDelta = null ;
return ;
return ;
@ -251,7 +226,7 @@ final class DeltaWindow {
// Select this best matching delta as the base for the object.
// Select this best matching delta as the base for the object.
//
//
ObjectToPack srcObj = window [ bestSlot ] . object ;
ObjectToPack srcObj = bestBase . object ;
ObjectToPack resObj = res . object ;
ObjectToPack resObj = res . object ;
if ( srcObj . isEdge ( ) ) {
if ( srcObj . isEdge ( ) ) {
// The source (the delta base) is an edge object outside of the
// The source (the delta base) is an edge object outside of the
@ -285,7 +260,7 @@ final class DeltaWindow {
keepInWindow ( ) ;
keepInWindow ( ) ;
}
}
private boolean delta ( final DeltaWindowEntry src , final int srcSlot )
private boolean delta ( final DeltaWindowEntry src )
throws IOException {
throws IOException {
// Objects must use only the same type as their delta base.
// Objects must use only the same type as their delta base.
// If we are looking at something where that isn't true we
// If we are looking at something where that isn't true we
@ -319,12 +294,12 @@ final class DeltaWindow {
srcIndex = index ( src ) ;
srcIndex = index ( src ) ;
} catch ( LargeObjectException tooBig ) {
} catch ( LargeObjectException tooBig ) {
// If the source is too big to work on, skip it.
// If the source is too big to work on, skip it.
dropFromWindow ( srcSlot ) ;
dropFromWindow ( src ) ;
return NEXT_SRC ;
return NEXT_SRC ;
} catch ( IOException notAvailable ) {
} catch ( IOException notAvailable ) {
if ( src . object . isEdge ( ) ) {
if ( src . object . isEdge ( ) ) {
// This is an edge that is suddenly not available.
// This is an edge that is suddenly not available.
dropFromWindow ( srcSlot ) ;
dropFromWindow ( src ) ;
return NEXT_SRC ;
return NEXT_SRC ;
} else {
} else {
throw notAvailable ;
throw notAvailable ;
@ -355,7 +330,7 @@ final class DeltaWindow {
if ( isBetterDelta ( src , delta ) ) {
if ( isBetterDelta ( src , delta ) ) {
bestDelta = delta ;
bestDelta = delta ;
bestSlot = srcSlot ;
bestBase = src ;
}
}
return NEXT_SRC ;
return NEXT_SRC ;
@ -390,39 +365,17 @@ final class DeltaWindow {
}
}
private void shuffleBaseUpInPriority ( ) {
private void shuffleBaseUpInPriority ( ) {
// Shuffle the entire window so that the best match we just used
// Reorder the window so that the best match we just used
// is at our current index, and our current object is at the index
// is the current one, and the now current object is before.
// before it. Slide any entries in between to make space.
res . makeNext ( bestBase ) ;
//
res = bestBase ;
window [ resSlot ] = window [ bestSlot ] ;
DeltaWindowEntry next = res ;
int slot = prior ( resSlot ) ;
for ( ; slot ! = bestSlot ; slot = prior ( slot ) ) {
DeltaWindowEntry e = window [ slot ] ;
window [ slot ] = next ;
next = e ;
}
window [ slot ] = next ;
}
}
private void keepInWindow ( ) {
private void keepInWindow ( ) {
resSlot = next ( resSlot ) ;
res = res . next ;
}
private int next ( int slot ) {
if ( + + slot = = window . length )
return 0 ;
return slot ;
}
private int prior ( int slot ) {
if ( slot = = 0 )
return window . length - 1 ;
return slot - 1 ;
}
}
private void dropFromWindow ( @SuppressWarnings ( "unused" ) int srcSlot ) {
private void dropFromWindow ( @SuppressWarnings ( "unused" ) DeltaWindowEntry src ) {
// We should drop the current source entry from the window,
// We should drop the current source entry from the window,
// it is somehow invalid for us to work with.
// it is somehow invalid for us to work with.
}
}
@ -437,7 +390,7 @@ final class DeltaWindow {
// to access during reads.
// to access during reads.
//
//
if ( resDelta . length ( ) = = bestDelta . length ( ) )
if ( resDelta . length ( ) = = bestDelta . length ( ) )
return src . depth ( ) < window [ bestSlot ] . depth ( ) ;
return src . depth ( ) < bestBase . depth ( ) ;
return resDelta . length ( ) < bestDelta . length ( ) ;
return resDelta . length ( ) < bestDelta . length ( ) ;
}
}
@ -501,14 +454,12 @@ final class DeltaWindow {
if ( maxMemory = = 0 )
if ( maxMemory = = 0 )
return ;
return ;
int tail = next ( resSlot ) ;
DeltaWindowEntry n = res . next ;
while ( maxMemory < loaded + need ) {
for ( ; maxMemory < loaded + need ; n = n . next ) {
DeltaWindowEntry cur = window [ tail ] ;
clear ( n ) ;
clear ( cur ) ;
if ( n = = ent )
if ( cur = = ent )
throw new LargeObjectException . ExceedsLimit (
throw new LargeObjectException . ExceedsLimit (
maxMemory , loaded + need ) ;
maxMemory , loaded + need ) ;
tail = next ( tail ) ;
}
}
}
}