Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit 7b3220f

Browse files
authored
Merge pull request #1126 from saracen/index-performance-improvements
plumbing: format/index perf, buffered reads, reflection removal
2 parents 6d4408a + 262179b commit 7b3220f

File tree

4 files changed

+46
-19
lines changed

4 files changed

+46
-19
lines changed

plumbing/format/index/decoder.go

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package index
22

33
import (
4+
"bufio"
45
"bytes"
56
"crypto/sha1"
67
"errors"
@@ -42,14 +43,17 @@ type Decoder struct {
4243
r io.Reader
4344
hash hash.Hash
4445
lastEntry *Entry
46+
47+
extReader *bufio.Reader
4548
}
4649

4750
// NewDecoder returns a new decoder that reads from r.
4851
func NewDecoder(r io.Reader) *Decoder {
4952
h := sha1.New()
5053
return &Decoder{
51-
r: io.TeeReader(r, h),
52-
hash: h,
54+
r: io.TeeReader(r, h),
55+
hash: h,
56+
extReader: bufio.NewReader(nil),
5357
}
5458
}
5559

@@ -184,11 +188,9 @@ func (d *Decoder) doReadEntryNameV4() (string, error) {
184188

185189
func (d *Decoder) doReadEntryName(len uint16) (string, error) {
186190
name := make([]byte, len)
187-
if err := binary.Read(d.r, &name); err != nil {
188-
return "", err
189-
}
191+
_, err := io.ReadFull(d.r, name[:])
190192

191-
return string(name), nil
193+
return string(name), err
192194
}
193195

194196
// Index entries are padded out to the next 8 byte alignment
@@ -279,20 +281,21 @@ func (d *Decoder) readExtension(idx *Index, header []byte) error {
279281
return nil
280282
}
281283

282-
func (d *Decoder) getExtensionReader() (io.Reader, error) {
284+
func (d *Decoder) getExtensionReader() (*bufio.Reader, error) {
283285
len, err := binary.ReadUint32(d.r)
284286
if err != nil {
285287
return nil, err
286288
}
287289

288-
return &io.LimitedReader{R: d.r, N: int64(len)}, nil
290+
d.extReader.Reset(&io.LimitedReader{R: d.r, N: int64(len)})
291+
return d.extReader, nil
289292
}
290293

291294
func (d *Decoder) readChecksum(expected []byte, alreadyRead [4]byte) error {
292295
var h plumbing.Hash
293296
copy(h[:4], alreadyRead[:])
294297

295-
if err := binary.Read(d.r, h[4:]); err != nil {
298+
if _, err := io.ReadFull(d.r, h[4:]); err != nil {
296299
return err
297300
}
298301

@@ -326,7 +329,7 @@ func validateHeader(r io.Reader) (version uint32, err error) {
326329
}
327330

328331
type treeExtensionDecoder struct {
329-
r io.Reader
332+
r *bufio.Reader
330333
}
331334

332335
func (d *treeExtensionDecoder) Decode(t *Tree) error {
@@ -386,16 +389,13 @@ func (d *treeExtensionDecoder) readEntry() (*TreeEntry, error) {
386389
}
387390

388391
e.Trees = i
389-
390-
if err := binary.Read(d.r, &e.Hash); err != nil {
391-
return nil, err
392-
}
392+
_, err = io.ReadFull(d.r, e.Hash[:])
393393

394394
return e, nil
395395
}
396396

397397
type resolveUndoDecoder struct {
398-
r io.Reader
398+
r *bufio.Reader
399399
}
400400

401401
func (d *resolveUndoDecoder) Decode(ru *ResolveUndo) error {
@@ -433,7 +433,7 @@ func (d *resolveUndoDecoder) readEntry() (*ResolveUndoEntry, error) {
433433

434434
for s := range e.Stages {
435435
var hash plumbing.Hash
436-
if err := binary.Read(d.r, hash[:]); err != nil {
436+
if _, err := io.ReadFull(d.r, hash[:]); err != nil {
437437
return nil, err
438438
}
439439

@@ -462,7 +462,7 @@ func (d *resolveUndoDecoder) readStage(e *ResolveUndoEntry, s Stage) error {
462462
}
463463

464464
type endOfIndexEntryDecoder struct {
465-
r io.Reader
465+
r *bufio.Reader
466466
}
467467

468468
func (d *endOfIndexEntryDecoder) Decode(e *EndOfIndexEntry) error {
@@ -472,5 +472,6 @@ func (d *endOfIndexEntryDecoder) Decode(e *EndOfIndexEntry) error {
472472
return err
473473
}
474474

475-
return binary.Read(d.r, &e.Hash)
475+
_, err = io.ReadFull(d.r, e.Hash[:])
476+
return err
476477
}

storage/filesystem/index.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package filesystem
22

33
import (
4+
"bufio"
45
"os"
56

67
"gopkg.in/src-d/go-git.v4/plumbing/format/index"
@@ -41,7 +42,7 @@ func (s *IndexStorage) Index() (i *index.Index, err error) {
4142

4243
defer ioutil.CheckClose(f, &err)
4344

44-
d := index.NewDecoder(f)
45+
d := index.NewDecoder(bufio.NewReader(f))
4546
err = d.Decode(idx)
4647
return idx, err
4748
}

utils/binary/read.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ func Read(r io.Reader, data ...interface{}) error {
2525

2626
// ReadUntil reads from r untin delim is found
2727
func ReadUntil(r io.Reader, delim byte) ([]byte, error) {
28+
if bufr, ok := r.(*bufio.Reader); ok {
29+
return ReadUntilFromBufioReader(bufr, delim)
30+
}
31+
2832
var buf [1]byte
2933
value := make([]byte, 0, 16)
3034
for {
@@ -44,6 +48,17 @@ func ReadUntil(r io.Reader, delim byte) ([]byte, error) {
4448
}
4549
}
4650

51+
// ReadUntilFromBufioReader is like bufio.ReadBytes but drops the delimiter
52+
// from the result.
53+
func ReadUntilFromBufioReader(r *bufio.Reader, delim byte) ([]byte, error) {
54+
value, err := r.ReadBytes(delim)
55+
if err != nil || len(value) == 0 {
56+
return nil, err
57+
}
58+
59+
return value[:len(value)-1], nil
60+
}
61+
4762
// ReadVariableWidthInt reads and returns an int in Git VLQ special format:
4863
//
4964
// Ordinary VLQ has some redundancies, example: the number 358 can be

utils/binary/read_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package binary
22

33
import (
4+
"bufio"
45
"bytes"
56
"encoding/binary"
67
"testing"
@@ -39,6 +40,15 @@ func (s *BinarySuite) TestReadUntil(c *C) {
3940
c.Assert(string(b), Equals, "foo")
4041
}
4142

43+
func (s *BinarySuite) TestReadUntilFromBufioReader(c *C) {
44+
buf := bufio.NewReader(bytes.NewBuffer([]byte("foo bar")))
45+
46+
b, err := ReadUntilFromBufioReader(buf, ' ')
47+
c.Assert(err, IsNil)
48+
c.Assert(b, HasLen, 3)
49+
c.Assert(string(b), Equals, "foo")
50+
}
51+
4252
func (s *BinarySuite) TestReadVariableWidthInt(c *C) {
4353
buf := bytes.NewBuffer([]byte{129, 110})
4454

0 commit comments

Comments
 (0)