aboutsummaryrefslogtreecommitdiffstats
path: root/plumbing/format
diff options
context:
space:
mode:
authorAntonio Navarro Perez <antnavper@gmail.com>2017-01-25 14:29:39 +0100
committerSantiago M. Mola <santi@mola.io>2017-01-25 14:29:39 +0100
commitec28bd3808d42f523eeb05e23909dbfc54eb9bcd (patch)
treec7c5470a3f0089f01c5c9e2d80fef60da16a3c94 /plumbing/format
parentdc45de29f87a43078356a5be4c4b5aa24f626ee0 (diff)
downloadgo-git-ec28bd3808d42f523eeb05e23909dbfc54eb9bcd.tar.gz
packfile: cache undeltified objects to improve decode performance (#218)
* Simple object cache that keeps in memory the last undeltified objects. When no more objects can be kept into memory, the oldest one is deleted (FIFO). This speeds up packfile operations preventing redundant seeks and decodes.
Diffstat (limited to 'plumbing/format')
-rw-r--r--plumbing/format/packfile/decoder.go41
1 files changed, 33 insertions, 8 deletions
diff --git a/plumbing/format/packfile/decoder.go b/plumbing/format/packfile/decoder.go
index 70d41ef..5793fdd 100644
--- a/plumbing/format/packfile/decoder.go
+++ b/plumbing/format/packfile/decoder.go
@@ -3,6 +3,7 @@ package packfile
import (
"bytes"
+ "gopkg.in/src-d/go-git.v4/cache"
"gopkg.in/src-d/go-git.v4/plumbing"
"gopkg.in/src-d/go-git.v4/plumbing/storer"
)
@@ -62,6 +63,8 @@ type Decoder struct {
offsetToType map[int64]plumbing.ObjectType
decoderType plumbing.ObjectType
+
+ cache cache.Object
}
// NewDecoder returns a new Decoder that decodes a Packfile using the given
@@ -105,6 +108,8 @@ func NewDecoderForType(s *Scanner, o storer.EncodedObjectStorer,
offsetToType: make(map[int64]plumbing.ObjectType, 0),
decoderType: t,
+
+ cache: cache.NewObjectFIFO(cache.MaxSize),
}, nil
}
@@ -341,13 +346,20 @@ func (d *Decoder) fillREFDeltaObjectContent(obj plumbing.EncodedObject, ref plum
return 0, err
}
- base, err := d.recallByHash(ref)
- if err != nil {
- return 0, err
+ base := d.cache.Get(ref)
+
+ if base == nil {
+ base, err = d.recallByHash(ref)
+ if err != nil {
+ return 0, err
+ }
}
obj.SetType(base.Type())
- return crc, ApplyDelta(obj, base, buf.Bytes())
+ err = ApplyDelta(obj, base, buf.Bytes())
+ d.cache.Add(obj)
+
+ return crc, err
}
func (d *Decoder) fillOFSDeltaObjectContent(obj plumbing.EncodedObject, offset int64) (uint32, error) {
@@ -357,13 +369,24 @@ func (d *Decoder) fillOFSDeltaObjectContent(obj plumbing.EncodedObject, offset i
return 0, err
}
- base, err := d.recallByOffset(offset)
- if err != nil {
- return 0, err
+ h := d.offsetToHash[offset]
+ var base plumbing.EncodedObject
+ if h != plumbing.ZeroHash {
+ base = d.cache.Get(h)
+ }
+
+ if base == nil {
+ base, err = d.recallByOffset(offset)
+ if err != nil {
+ return 0, err
+ }
}
obj.SetType(base.Type())
- return crc, ApplyDelta(obj, base, buf.Bytes())
+ err = ApplyDelta(obj, base, buf.Bytes())
+ d.cache.Add(obj)
+
+ return crc, err
}
func (d *Decoder) setOffset(h plumbing.Hash, offset int64) {
@@ -434,5 +457,7 @@ func (d *Decoder) CRCs() map[plumbing.Hash]uint32 {
// Close close the Scanner, usually this mean that the whole reader is read and
// discarded
func (d *Decoder) Close() error {
+ d.cache.Clear()
+
return d.s.Close()
}