@ -68,9 +68,15 @@ class DeltaWindow {
private final DeltaWindowEntry [ ] window ;
private final DeltaWindowEntry [ ] window ;
/** Maximum number of bytes to admit to the window at once. */
private final long maxMemory ;
/** Maximum depth we should create for any delta chain. */
/** Maximum depth we should create for any delta chain. */
private final int maxDepth ;
private final int maxDepth ;
/** Amount of memory we have loaded right now. */
private long loaded ;
// 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. */
/** Position of {@link #res} within {@link #window} array. */
@ -115,6 +121,7 @@ class DeltaWindow {
for ( int i = 0 ; i < window . length ; i + + )
for ( int i = 0 ; i < window . length ; i + + )
window [ i ] = new DeltaWindowEntry ( ) ;
window [ i ] = new DeltaWindowEntry ( ) ;
maxMemory = pw . getDeltaSearchMemoryLimit ( ) ;
maxDepth = pw . getMaxDeltaDepth ( ) ;
maxDepth = pw . getMaxDeltaDepth ( ) ;
}
}
@ -125,6 +132,15 @@ class DeltaWindow {
monitor . update ( 1 ) ;
monitor . update ( 1 ) ;
res = window [ resSlot ] ;
res = window [ resSlot ] ;
if ( 0 < maxMemory ) {
clear ( res ) ;
int tail = next ( resSlot ) ;
final long need = estimateSize ( toSearch [ off ] ) ;
while ( maxMemory < loaded + need & & tail ! = resSlot ) {
clear ( window [ tail ] ) ;
tail = next ( tail ) ;
}
}
res . set ( toSearch [ off ] ) ;
res . set ( toSearch [ off ] ) ;
if ( res . object . isDoNotDelta ( ) ) {
if ( res . object . isDoNotDelta ( ) ) {
@ -148,6 +164,18 @@ class DeltaWindow {
}
}
}
}
private static long estimateSize ( ObjectToPack ent ) {
return DeltaIndex . estimateIndexSize ( ent . getWeight ( ) ) ;
}
private void clear ( DeltaWindowEntry ent ) {
if ( ent . index ! = null )
loaded - = ent . index . getIndexSize ( ) ;
else if ( res . buffer ! = null )
loaded - = ent . buffer . length ;
ent . set ( null ) ;
}
private void search ( ) throws IOException {
private void search ( ) throws IOException {
// TODO(spearce) If the object is used as a base for other
// TODO(spearce) If the object is used as a base for other
// objects in this pack we should limit the depth we create
// objects in this pack we should limit the depth we create
@ -336,8 +364,13 @@ class DeltaWindow {
}
}
private void keepInWindow ( ) {
private void keepInWindow ( ) {
if ( + + resSlot = = window . length )
resSlot = next ( resSlot ) ;
resSlot = 0 ;
}
private int next ( int slot ) {
if ( + + slot = = window . length )
return 0 ;
return slot ;
}
}
private int prior ( int slot ) {
private int prior ( int slot ) {
@ -397,6 +430,8 @@ class DeltaWindow {
e . initCause ( noMemory ) ;
e . initCause ( noMemory ) ;
throw e ;
throw e ;
}
}
if ( 0 < maxMemory )
loaded + = idx . getIndexSize ( ) - idx . getSourceSize ( ) ;
ent . index = idx ;
ent . index = idx ;
}
}
return idx ;
return idx ;
@ -405,8 +440,12 @@ class DeltaWindow {
private byte [ ] buffer ( DeltaWindowEntry ent ) throws MissingObjectException ,
private byte [ ] buffer ( DeltaWindowEntry ent ) throws MissingObjectException ,
IncorrectObjectTypeException , IOException , LargeObjectException {
IncorrectObjectTypeException , IOException , LargeObjectException {
byte [ ] buf = ent . buffer ;
byte [ ] buf = ent . buffer ;
if ( buf = = null )
if ( buf = = null ) {
ent . buffer = buf = writer . buffer ( reader , ent . object ) ;
buf = writer . buffer ( reader , ent . object ) ;
if ( 0 < maxMemory )
loaded + = buf . length ;
ent . buffer = buf ;
}
return buf ;
return buf ;
}
}