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

Commit 1ccc0fa

Browse files
committed
plumbing: format/index perf, buffered reads, reflection removal
Large performance increase by buffering reads. There were a few instances where binary.Read() would end up using reflection on &plumbing.Hash, rather than treating it as a byte slice. This has now been resolved. Signed-off-by: Arran Walker <[email protected]>
1 parent e5268e9 commit 1ccc0fa

File tree

2 files changed

+26
-24
lines changed

2 files changed

+26
-24
lines changed

plumbing/format/index/decoder.go

Lines changed: 24 additions & 23 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 {
@@ -351,14 +354,14 @@ func (d *treeExtensionDecoder) Decode(t *Tree) error {
351354
func (d *treeExtensionDecoder) readEntry() (*TreeEntry, error) {
352355
e := &TreeEntry{}
353356

354-
path, err := binary.ReadUntil(d.r, '\x00')
357+
path, err := d.r.ReadSlice('\x00')
355358
if err != nil {
356359
return nil, err
357360
}
358361

359362
e.Path = string(path)
360363

361-
count, err := binary.ReadUntil(d.r, ' ')
364+
count, err := d.r.ReadSlice(' ')
362365
if err != nil {
363366
return nil, err
364367
}
@@ -375,7 +378,7 @@ func (d *treeExtensionDecoder) readEntry() (*TreeEntry, error) {
375378
}
376379

377380
e.Entries = i
378-
trees, err := binary.ReadUntil(d.r, '\n')
381+
trees, err := d.r.ReadSlice('\n')
379382
if err != nil {
380383
return nil, err
381384
}
@@ -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 {
@@ -418,7 +418,7 @@ func (d *resolveUndoDecoder) readEntry() (*ResolveUndoEntry, error) {
418418
Stages: make(map[Stage]plumbing.Hash),
419419
}
420420

421-
path, err := binary.ReadUntil(d.r, '\x00')
421+
path, err := d.r.ReadSlice('\x00')
422422
if err != nil {
423423
return nil, err
424424
}
@@ -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

@@ -444,7 +444,7 @@ func (d *resolveUndoDecoder) readEntry() (*ResolveUndoEntry, error) {
444444
}
445445

446446
func (d *resolveUndoDecoder) readStage(e *ResolveUndoEntry, s Stage) error {
447-
ascii, err := binary.ReadUntil(d.r, '\x00')
447+
ascii, err := d.r.ReadSlice('\x00')
448448
if err != nil {
449449
return err
450450
}
@@ -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
}

0 commit comments

Comments
 (0)