aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--packfile/reader.go36
1 files changed, 24 insertions, 12 deletions
diff --git a/packfile/reader.go b/packfile/reader.go
index 3725822..4c110b4 100644
--- a/packfile/reader.go
+++ b/packfile/reader.go
@@ -123,7 +123,13 @@ func (p *PackfileReader) readInt32() (uint32, error) {
}
func (p *PackfileReader) readObjects(packfile *Packfile) error {
+ // This code has 50-80 µs of overhead per object not counting zlib inflation.
+ // Together with zlib inflation, it's 400-410 µs for small objects.
+ // That's 1 sec for ~2450 objects, ~4.20 MB, or ~250 ms per MB,
+ // of which 12-20 % is _not_ zlib inflation (ie. is our code).
+
p.startedGivingBack = true
+ var unknownForBytes [4]byte
offset := 12
for i := 0; i < packfile.ObjectCount; i++ {
@@ -135,8 +141,7 @@ func (p *PackfileReader) readObjects(packfile *Packfile) error {
p.offsets[offset] = r.hash
offset += r.counter + 4
- unknownForBytes := make([]byte, 4)
- p.r.Read(unknownForBytes)
+ p.r.Read(unknownForBytes[:])
if err == io.EOF {
break
@@ -195,8 +200,8 @@ func (p *PackfileReader) readObject(packfile *Packfile, offset int) (*objectRead
func newObjectReader(pr *PackfileReader, pf *Packfile, offset int) (*objectReader, error) {
o := &objectReader{pr: pr, pf: pf, offset: offset}
- buf := make([]byte, 1)
- if _, err := o.Read(buf); err != nil {
+ var buf [1]byte
+ if _, err := o.Read(buf[:]); err != nil {
return nil, err
}
@@ -205,7 +210,7 @@ func newObjectReader(pr *PackfileReader, pf *Packfile, offset int) (*objectReade
var shift uint = 4
for buf[0]&0x80 == 0x80 {
- if _, err := o.Read(buf); err != nil {
+ if _, err := o.Read(buf[:]); err != nil {
return nil, err
}
@@ -217,8 +222,8 @@ func newObjectReader(pr *PackfileReader, pf *Packfile, offset int) (*objectReade
}
func (o *objectReader) readREFDelta() error {
- ref := make([]byte, 20)
- o.Read(ref)
+ var ref [20]byte
+ o.Read(ref[:])
buf, err := o.inflate()
if err != nil {
@@ -228,9 +233,9 @@ func (o *objectReader) readREFDelta() error {
refhash := fmt.Sprintf("%x", ref)
referenced, ok := o.pr.objects[refhash]
if !ok {
- o.pr.deltas = append(o.pr.deltas, packfileDelta{hash: refhash, delta: buf})
+ o.pr.deltas = append(o.pr.deltas, packfileDelta{hash: refhash, delta: buf[:]})
} else {
- patched := PatchDelta(referenced.bytes, buf)
+ patched := PatchDelta(referenced.bytes, buf[:])
if patched == nil {
return NewError("error while patching %x", ref)
}
@@ -329,8 +334,8 @@ func (o *objectReader) addObject(bytes []byte) error {
func (o *objectReader) inflate() ([]byte, error) {
//Quick fix "Invalid git object tag '\x00'" when the length of a object is 0
if o.size == 0 {
- buf := make([]byte, 4)
- if _, err := o.Read(buf); err != nil {
+ var buf [4]byte
+ if _, err := o.Read(buf[:]); err != nil {
return nil, err
}
@@ -352,7 +357,14 @@ func (o *objectReader) inflate() ([]byte, error) {
return nil, NewError("the object size exceeed the allowed limit: %d", o.size)
}
- buf := make([]byte, o.size)
+ var arrbuf [4096]byte // Stack-allocated for <4 KB objects.
+ var buf []byte
+ if uint64(len(arrbuf)) >= o.size {
+ buf = arrbuf[:o.size]
+ } else {
+ buf = make([]byte, o.size)
+ }
+
read := 0
for read < int(o.size) {
n, err := zr.Read(buf[read:])