aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiguel Molina <miguel@erizocosmi.co>2017-09-06 12:13:41 +0200
committerMiguel Molina <miguel@erizocosmi.co>2017-09-06 12:13:41 +0200
commit0b68b0fd8e8a0f57419a72479ddeb8d267f15f72 (patch)
treea6b49669163d3a0a1c85141513eeb52c3ee6561e
parent2dc59a6925f47e9d1bc99dd64d86e37b79b65d11 (diff)
downloadgo-git-0b68b0fd8e8a0f57419a72479ddeb8d267f15f72.tar.gz
packfile: reuse delta indexes when possible
Signed-off-by: Miguel Molina <miguel@erizocosmi.co>
-rw-r--r--plumbing/format/packfile/delta_selector.go11
-rw-r--r--plumbing/format/packfile/delta_test.go4
-rw-r--r--plumbing/format/packfile/diff_delta.go17
3 files changed, 22 insertions, 10 deletions
diff --git a/plumbing/format/packfile/delta_selector.go b/plumbing/format/packfile/delta_selector.go
index cc0ae0f..78b5733 100644
--- a/plumbing/format/packfile/delta_selector.go
+++ b/plumbing/format/packfile/delta_selector.go
@@ -172,6 +172,7 @@ func (dw *deltaSelector) sort(objectsToPack []*ObjectToPack) {
}
func (dw *deltaSelector) walk(objectsToPack []*ObjectToPack) error {
+ indexMap := make(map[plumbing.Hash]deltaIndex)
for i := 0; i < len(objectsToPack); i++ {
target := objectsToPack[i]
@@ -196,7 +197,7 @@ func (dw *deltaSelector) walk(objectsToPack []*ObjectToPack) error {
break
}
- if err := dw.tryToDeltify(base, target); err != nil {
+ if err := dw.tryToDeltify(indexMap, base, target); err != nil {
return err
}
}
@@ -205,7 +206,7 @@ func (dw *deltaSelector) walk(objectsToPack []*ObjectToPack) error {
return nil
}
-func (dw *deltaSelector) tryToDeltify(base, target *ObjectToPack) error {
+func (dw *deltaSelector) tryToDeltify(indexMap map[plumbing.Hash]deltaIndex, base, target *ObjectToPack) error {
// If the sizes are radically different, this is a bad pairing.
if target.Size() < base.Size()>>4 {
return nil
@@ -238,8 +239,12 @@ func (dw *deltaSelector) tryToDeltify(base, target *ObjectToPack) error {
return err
}
+ if _, ok := indexMap[base.Hash()]; !ok {
+ indexMap[base.Hash()] = make(deltaIndex)
+ }
+
// Now we can generate the delta using originals
- delta, err := GetDelta(base.Original, target.Original)
+ delta, err := getDelta(indexMap[base.Hash()], base.Original, target.Original)
if err != nil {
return err
}
diff --git a/plumbing/format/packfile/delta_test.go b/plumbing/format/packfile/delta_test.go
index 42b777a..f6e93d2 100644
--- a/plumbing/format/packfile/delta_test.go
+++ b/plumbing/format/packfile/delta_test.go
@@ -84,7 +84,7 @@ func (s *DeltaSuite) TestAddDelta(c *C) {
for _, t := range s.testCases {
baseBuf := genBytes(t.base)
targetBuf := genBytes(t.target)
- delta := DiffDelta(baseBuf, targetBuf)
+ delta := DiffDelta(make(deltaIndex), baseBuf, targetBuf)
result, err := PatchDelta(baseBuf, delta)
c.Log("Executing test case:", t.description)
@@ -98,7 +98,7 @@ func (s *DeltaSuite) TestIncompleteDelta(c *C) {
c.Log("Incomplete delta on:", t.description)
baseBuf := genBytes(t.base)
targetBuf := genBytes(t.target)
- delta := DiffDelta(baseBuf, targetBuf)
+ delta := DiffDelta(make(deltaIndex), baseBuf, targetBuf)
delta = delta[:len(delta)-2]
result, err := PatchDelta(baseBuf, delta)
c.Assert(err, NotNil)
diff --git a/plumbing/format/packfile/diff_delta.go b/plumbing/format/packfile/diff_delta.go
index 7e9f822..d0db46b 100644
--- a/plumbing/format/packfile/diff_delta.go
+++ b/plumbing/format/packfile/diff_delta.go
@@ -26,6 +26,10 @@ const (
// To generate target again, you will need the obtained object and "base" one.
// Error will be returned if base or target object cannot be read.
func GetDelta(base, target plumbing.EncodedObject) (plumbing.EncodedObject, error) {
+ return getDelta(make(deltaIndex), base, target)
+}
+
+func getDelta(index deltaIndex, base, target plumbing.EncodedObject) (plumbing.EncodedObject, error) {
br, err := base.Reader()
if err != nil {
return nil, err
@@ -45,7 +49,7 @@ func GetDelta(base, target plumbing.EncodedObject) (plumbing.EncodedObject, erro
return nil, err
}
- db := DiffDelta(bb, tb)
+ db := DiffDelta(index, bb, tb)
delta := &plumbing.MemoryObject{}
_, err = delta.Write(db)
if err != nil {
@@ -59,13 +63,15 @@ func GetDelta(base, target plumbing.EncodedObject) (plumbing.EncodedObject, erro
}
// DiffDelta returns the delta that transforms src into tgt.
-func DiffDelta(src []byte, tgt []byte) []byte {
+func DiffDelta(sindex deltaIndex, src []byte, tgt []byte) []byte {
buf := bufPool.Get().(*bytes.Buffer)
buf.Reset()
buf.Write(deltaEncodeSize(len(src)))
buf.Write(deltaEncodeSize(len(tgt)))
- sindex := initMatch(src)
+ if len(sindex) == 0 {
+ initMatch(sindex, src)
+ }
ibuf := bufPool.Get().(*bytes.Buffer)
ibuf.Reset()
@@ -126,9 +132,8 @@ func encodeInsertOperation(ibuf, buf *bytes.Buffer) {
ibuf.Reset()
}
-func initMatch(src []byte) map[uint32]int {
+func initMatch(index map[uint32]int, src []byte) map[uint32]int {
i := 0
- index := make(map[uint32]int)
for {
if i+s > len(src) {
break
@@ -213,3 +218,5 @@ func encodeCopyOperation(offset, length int) []byte {
return append([]byte{byte(code)}, opcodes...)
}
+
+type deltaIndex map[uint32]int