Reduce size of PackedObjectLoader by dropping long to int

Rather than keep track of both the position of the object, and the
position of its data, just keep track of the number of bytes used
by the object's header in the pack.  This shaves 4 bytes out of the
size of the PackedObjectLoader instances.

We also can defer the addition instruction to the materialize()
operation, avoiding it entirely if the caller never actually uses
the loader.  This may be relevant for PackWriter invocations,
where only 1 loader gets chosen for a given object, even though
the object may appear on disk in more than one pack file.

Error reporting is now simplified, as we can rely on the object
offset rather than its data offset.  This is the value displayed
by pack debugging tools like `git verify-pack -v`, so its better
to use that in our own errors.

Because nobody needs getDataOffset() now, we can drop that from
the public API.

Change-Id: Ic639c0d5a722315f4f5c8ffda6e26643d90e5f42
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
This commit is contained in:
Shawn O. Pearce 2010-05-15 17:37:14 -07:00
parent 9c4d42e94d
commit cb5bc19540
7 changed files with 43 additions and 49 deletions

View File

@ -67,7 +67,7 @@ public void test003_lookupCompressedObject() throws IOException {
assertNotNull(or); assertNotNull(or);
assertEquals(Constants.OBJ_TREE, or.getType()); assertEquals(Constants.OBJ_TREE, or.getType());
assertEquals(35, or.getSize()); assertEquals(35, or.getSize());
assertEquals(7738, or.getDataOffset()); assertEquals(7736, or.getObjectOffset());
pr.close(); pr.close();
} }
@ -81,6 +81,6 @@ public void test004_lookupDeltifiedObject() throws IOException {
assertTrue(or instanceof PackedObjectLoader); assertTrue(or instanceof PackedObjectLoader);
assertEquals(Constants.OBJ_BLOB, or.getType()); assertEquals(Constants.OBJ_BLOB, or.getType());
assertEquals(18009, or.getSize()); assertEquals(18009, or.getSize());
assertEquals(537, ((PackedObjectLoader) or).getDataOffset()); assertEquals(516, ((PackedObjectLoader) or).getObjectOffset());
} }
} }

View File

@ -54,10 +54,9 @@
class DeltaOfsPackedObjectLoader extends DeltaPackedObjectLoader { class DeltaOfsPackedObjectLoader extends DeltaPackedObjectLoader {
private final long deltaBase; private final long deltaBase;
DeltaOfsPackedObjectLoader(final PackFile pr, DeltaOfsPackedObjectLoader(final PackFile pr, final long objectOffset,
final long dataOffset, final long objectOffset, final int deltaSz, final int headerSz, final int deltaSz, final long base) {
final long base) { super(pr, objectOffset, headerSz, deltaSz);
super(pr, dataOffset, objectOffset, deltaSz);
deltaBase = base; deltaBase = base;
} }

View File

@ -57,9 +57,9 @@ abstract class DeltaPackedObjectLoader extends PackedObjectLoader {
private final int deltaSize; private final int deltaSize;
DeltaPackedObjectLoader(final PackFile pr, final long dataOffset, DeltaPackedObjectLoader(final PackFile pr, final long objectOffset,
final long objectOffset, final int deltaSz) { final int headerSize, final int deltaSz) {
super(pr, dataOffset, objectOffset); super(pr, objectOffset, headerSize);
objectType = -1; objectType = -1;
deltaSize = deltaSz; deltaSize = deltaSz;
} }
@ -71,7 +71,7 @@ public void materialize(final WindowCursor curs) throws IOException {
} }
if (objectType != OBJ_COMMIT) { if (objectType != OBJ_COMMIT) {
final UnpackedObjectCache.Entry cache = pack.readCache(dataOffset); UnpackedObjectCache.Entry cache = pack.readCache(objectOffset);
if (cache != null) { if (cache != null) {
curs.release(); curs.release();
objectType = cache.type; objectType = cache.type;
@ -84,17 +84,17 @@ public void materialize(final WindowCursor curs) throws IOException {
try { try {
final PackedObjectLoader baseLoader = getBaseLoader(curs); final PackedObjectLoader baseLoader = getBaseLoader(curs);
baseLoader.materialize(curs); baseLoader.materialize(curs);
cachedBytes = BinaryDelta.apply(baseLoader.getCachedBytes(), cachedBytes = BinaryDelta.apply(baseLoader.getCachedBytes(), pack
pack.decompress(dataOffset, deltaSize, curs)); .decompress(objectOffset + headerSize, deltaSize, curs));
curs.release(); curs.release();
objectType = baseLoader.getType(); objectType = baseLoader.getType();
objectSize = cachedBytes.length; objectSize = cachedBytes.length;
if (objectType != OBJ_COMMIT) if (objectType != OBJ_COMMIT)
pack.saveCache(dataOffset, cachedBytes, objectType); pack.saveCache(objectOffset, cachedBytes, objectType);
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
final CorruptObjectException coe; final CorruptObjectException coe;
coe = new CorruptObjectException("Object at " + dataOffset + " in " coe = new CorruptObjectException("Object at " + objectOffset
+ pack.getPackFile() + " has bad zlib stream"); + " in " + pack.getPackFile() + " has bad zlib stream");
coe.initCause(dfe); coe.initCause(dfe);
throw coe; throw coe;
} }

View File

@ -54,10 +54,9 @@
class DeltaRefPackedObjectLoader extends DeltaPackedObjectLoader { class DeltaRefPackedObjectLoader extends DeltaPackedObjectLoader {
private final ObjectId deltaBase; private final ObjectId deltaBase;
DeltaRefPackedObjectLoader(final PackFile pr, DeltaRefPackedObjectLoader(final PackFile pr, final long objectOffset,
final long dataOffset, final long objectOffset, final int deltaSz, final int headerSz, final int deltaSz, final ObjectId base) {
final ObjectId base) { super(pr, objectOffset, headerSz, deltaSz);
super(pr, dataOffset, objectOffset, deltaSz);
deltaBase = base; deltaBase = base;
} }

View File

@ -269,13 +269,13 @@ final void copyRawData(final PackedObjectLoader loader,
final OutputStream out, final byte buf[], final WindowCursor curs) final OutputStream out, final byte buf[], final WindowCursor curs)
throws IOException { throws IOException {
final long objectOffset = loader.objectOffset; final long objectOffset = loader.objectOffset;
final long dataOffset = loader.dataOffset; final long dataOffset = objectOffset + loader.headerSize;
final int cnt = (int) (findEndOffset(objectOffset) - dataOffset); final int cnt = (int) (findEndOffset(objectOffset) - dataOffset);
final PackIndex idx = idx(); final PackIndex idx = idx();
if (idx.hasCRC32Support()) { if (idx.hasCRC32Support()) {
final CRC32 crc = new CRC32(); final CRC32 crc = new CRC32();
int headerCnt = (int) (dataOffset - objectOffset); int headerCnt = loader.headerSize;
while (headerCnt > 0) { while (headerCnt > 0) {
final int toRead = Math.min(headerCnt, buf.length); final int toRead = Math.min(headerCnt, buf.length);
readFully(objectOffset, buf, 0, toRead, curs); readFully(objectOffset, buf, 0, toRead, curs);
@ -289,14 +289,14 @@ final void copyRawData(final PackedObjectLoader loader,
final ObjectId id = findObjectForOffset(objectOffset); final ObjectId id = findObjectForOffset(objectOffset);
final long expected = idx.findCRC32(id); final long expected = idx.findCRC32(id);
if (computed != expected) if (computed != expected)
throw new CorruptObjectException("Object at " + dataOffset throw new CorruptObjectException("Object at " + objectOffset
+ " in " + getPackFile() + " has bad zlib stream"); + " in " + getPackFile() + " has bad zlib stream");
} else { } else {
try { try {
curs.inflateVerify(this, dataOffset); curs.inflateVerify(this, dataOffset);
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
final CorruptObjectException coe; final CorruptObjectException coe;
coe = new CorruptObjectException("Object at " + dataOffset coe = new CorruptObjectException("Object at " + objectOffset
+ " in " + getPackFile() + " has bad zlib stream"); + " in " + getPackFile() + " has bad zlib stream");
coe.initCause(dfe); coe.initCause(dfe);
throw coe; throw coe;
@ -473,8 +473,8 @@ private PackedObjectLoader reader(final WindowCursor curs,
case Constants.OBJ_TREE: case Constants.OBJ_TREE:
case Constants.OBJ_BLOB: case Constants.OBJ_BLOB:
case Constants.OBJ_TAG: case Constants.OBJ_TAG:
return new WholePackedObjectLoader(this, objOffset + p, objOffset, return new WholePackedObjectLoader(this, objOffset, p, typeCode,
typeCode, (int) dataSize); (int) dataSize);
case Constants.OBJ_OFS_DELTA: { case Constants.OBJ_OFS_DELTA: {
c = ib[p++] & 0xff; c = ib[p++] & 0xff;
@ -485,13 +485,13 @@ private PackedObjectLoader reader(final WindowCursor curs,
ofs <<= 7; ofs <<= 7;
ofs += (c & 127); ofs += (c & 127);
} }
return new DeltaOfsPackedObjectLoader(this, objOffset + p, return new DeltaOfsPackedObjectLoader(this, objOffset, p,
objOffset, (int) dataSize, objOffset - ofs); (int) dataSize, objOffset - ofs);
} }
case Constants.OBJ_REF_DELTA: { case Constants.OBJ_REF_DELTA: {
readFully(objOffset + p, ib, 0, 20, curs); readFully(objOffset + p, ib, 0, 20, curs);
return new DeltaRefPackedObjectLoader(this, objOffset + p + 20, return new DeltaRefPackedObjectLoader(this, objOffset, p + 20,
objOffset, (int) dataSize, ObjectId.fromRaw(ib)); (int) dataSize, ObjectId.fromRaw(ib));
} }
default: default:
throw new IOException("Unknown object type " + typeCode + "."); throw new IOException("Unknown object type " + typeCode + ".");

View File

@ -55,21 +55,23 @@
abstract class PackedObjectLoader extends ObjectLoader { abstract class PackedObjectLoader extends ObjectLoader {
protected final PackFile pack; protected final PackFile pack;
protected final long dataOffset; /** Position of the first byte of the object's header. */
protected final long objectOffset; protected final long objectOffset;
/** Bytes used to express the object header, including delta reference. */
protected final int headerSize;
protected int objectType; protected int objectType;
protected int objectSize; protected int objectSize;
protected byte[] cachedBytes; protected byte[] cachedBytes;
PackedObjectLoader(final PackFile pr, final long dataOffset, PackedObjectLoader(final PackFile pr, final long objectOffset,
final long objectOffset) { final int headerSize) {
pack = pr; pack = pr;
this.dataOffset = dataOffset;
this.objectOffset = objectOffset; this.objectOffset = objectOffset;
this.headerSize = headerSize;
} }
/** /**
@ -113,13 +115,6 @@ public final long getObjectOffset() {
return objectOffset; return objectOffset;
} }
/**
* @return offset of object data within pack file
*/
public final long getDataOffset() {
return dataOffset;
}
/** /**
* Peg the pack file open to support data copying. * Peg the pack file open to support data copying.
* <p> * <p>

View File

@ -54,9 +54,9 @@
class WholePackedObjectLoader extends PackedObjectLoader { class WholePackedObjectLoader extends PackedObjectLoader {
private static final int OBJ_COMMIT = Constants.OBJ_COMMIT; private static final int OBJ_COMMIT = Constants.OBJ_COMMIT;
WholePackedObjectLoader(final PackFile pr, final long dataOffset, WholePackedObjectLoader(final PackFile pr, final long objectOffset,
final long objectOffset, final int type, final int size) { final int headerSize, final int type, final int size) {
super(pr, dataOffset, objectOffset); super(pr, objectOffset, headerSize);
objectType = type; objectType = type;
objectSize = size; objectSize = size;
} }
@ -68,7 +68,7 @@ public void materialize(final WindowCursor curs) throws IOException {
} }
if (objectType != OBJ_COMMIT) { if (objectType != OBJ_COMMIT) {
final UnpackedObjectCache.Entry cache = pack.readCache(dataOffset); UnpackedObjectCache.Entry cache = pack.readCache(objectOffset);
if (cache != null) { if (cache != null) {
curs.release(); curs.release();
cachedBytes = cache.data; cachedBytes = cache.data;
@ -77,14 +77,15 @@ public void materialize(final WindowCursor curs) throws IOException {
} }
try { try {
cachedBytes = pack.decompress(dataOffset, objectSize, curs); cachedBytes = pack.decompress(objectOffset + headerSize,
objectSize, curs);
curs.release(); curs.release();
if (objectType != OBJ_COMMIT) if (objectType != OBJ_COMMIT)
pack.saveCache(dataOffset, cachedBytes, objectType); pack.saveCache(objectOffset, cachedBytes, objectType);
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
final CorruptObjectException coe; final CorruptObjectException coe;
coe = new CorruptObjectException("Object at " + dataOffset + " in " coe = new CorruptObjectException("Object at " + objectOffset
+ pack.getPackFile() + " has bad zlib stream"); + " in " + pack.getPackFile() + " has bad zlib stream");
coe.initCause(dfe); coe.initCause(dfe);
throw coe; throw coe;
} }