If the heap limit was set to something smaller than 8 KiB, we were still allocating the full 8 KiB block size, and accepting up to the amount we allocated by. Instead actually put a hard cap on the limit. Change-Id: Id1da26fde2102e76510b1da4ede8493928a981cc Signed-off-by: Shawn O. Pearce <spearce@spearce.org>tags/v0.9.1
@@ -255,7 +255,7 @@ public class ReceivePackRefFilterTest extends LocalDiskRepositoryTestCase { | |||
} | |||
public void testUsingHiddenDeltaBaseFails() throws Exception { | |||
final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(64); | |||
final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024); | |||
packHeader(pack, 1); | |||
pack.write((Constants.OBJ_REF_DELTA) << 4 | 4); | |||
b.copyRawTo(pack); | |||
@@ -297,13 +297,13 @@ public class ReceivePackRefFilterTest extends LocalDiskRepositoryTestCase { | |||
// But don't include it in the pack. | |||
// | |||
final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(64); | |||
final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024); | |||
packHeader(pack, 2); | |||
copy(pack, src.open(N)); | |||
copy(pack,src.open(s.parseBody(N).getTree())); | |||
digest(pack); | |||
final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(256); | |||
final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024); | |||
final PacketLineOut inPckLine = new PacketLineOut(inBuf); | |||
inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name() + ' ' | |||
+ "refs/heads/s" + '\0' | |||
@@ -339,13 +339,13 @@ public class ReceivePackRefFilterTest extends LocalDiskRepositoryTestCase { | |||
// But don't include it in the pack. | |||
// | |||
final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(64); | |||
final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024); | |||
packHeader(pack, 2); | |||
copy(pack, src.open(N)); | |||
copy(pack,src.open(s.parseBody(N).getTree())); | |||
digest(pack); | |||
final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(256); | |||
final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024); | |||
final PacketLineOut inPckLine = new PacketLineOut(inBuf); | |||
inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name() + ' ' | |||
+ "refs/heads/s" + '\0' | |||
@@ -379,12 +379,12 @@ public class ReceivePackRefFilterTest extends LocalDiskRepositoryTestCase { | |||
// Don't include the tree in the pack. | |||
// | |||
final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(64); | |||
final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024); | |||
packHeader(pack, 1); | |||
copy(pack, src.open(N)); | |||
digest(pack); | |||
final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(256); | |||
final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024); | |||
final PacketLineOut inPckLine = new PacketLineOut(inBuf); | |||
inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name() + ' ' | |||
+ "refs/heads/s" + '\0' |
@@ -126,7 +126,7 @@ public abstract class TemporaryBuffer extends OutputStream { | |||
blocks.add(s); | |||
} | |||
final int n = Math.min(Block.SZ - s.count, len); | |||
final int n = Math.min(s.buffer.length - s.count, len); | |||
System.arraycopy(b, off, s.buffer, s.count, n); | |||
s.count += n; | |||
len -= n; | |||
@@ -171,7 +171,7 @@ public abstract class TemporaryBuffer extends OutputStream { | |||
blocks.add(s); | |||
} | |||
final int n = in.read(s.buffer, s.count, Block.SZ - s.count); | |||
int n = in.read(s.buffer, s.count, s.buffer.length - s.count); | |||
if (n < 1) | |||
return; | |||
s.count += n; | |||
@@ -192,8 +192,12 @@ public abstract class TemporaryBuffer extends OutputStream { | |||
* @return total length of the buffer, in bytes. | |||
*/ | |||
public long length() { | |||
return inCoreLength(); | |||
} | |||
private long inCoreLength() { | |||
final Block last = last(); | |||
return ((long) blocks.size()) * Block.SZ - (Block.SZ - last.count); | |||
return ((long) blocks.size() - 1) * Block.SZ + last.count; | |||
} | |||
/** | |||
@@ -251,8 +255,13 @@ public abstract class TemporaryBuffer extends OutputStream { | |||
if (overflow != null) { | |||
destroy(); | |||
} | |||
blocks = new ArrayList<Block>(inCoreLimit / Block.SZ); | |||
blocks.add(new Block()); | |||
if (inCoreLimit < Block.SZ) { | |||
blocks = new ArrayList<Block>(1); | |||
blocks.add(new Block(inCoreLimit)); | |||
} else { | |||
blocks = new ArrayList<Block>(inCoreLimit / Block.SZ); | |||
blocks.add(new Block()); | |||
} | |||
} | |||
/** | |||
@@ -270,7 +279,7 @@ public abstract class TemporaryBuffer extends OutputStream { | |||
} | |||
private boolean reachedInCoreLimit() throws IOException { | |||
if (blocks.size() * Block.SZ < inCoreLimit) | |||
if (inCoreLength() < inCoreLimit) | |||
return false; | |||
switchToOverflow(); | |||
@@ -444,12 +453,20 @@ public abstract class TemporaryBuffer extends OutputStream { | |||
static class Block { | |||
static final int SZ = 8 * 1024; | |||
final byte[] buffer = new byte[SZ]; | |||
final byte[] buffer; | |||
int count; | |||
Block() { | |||
buffer = new byte[SZ]; | |||
} | |||
Block(int sz) { | |||
buffer = new byte[sz]; | |||
} | |||
boolean isFull() { | |||
return count == SZ; | |||
return count == buffer.length; | |||
} | |||
} | |||
} |