diff options
author | Javi Fontan <jfontan@gmail.com> | 2018-01-19 16:12:11 +0100 |
---|---|---|
committer | Javi Fontan <jfontan@gmail.com> | 2018-01-21 21:49:22 +0100 |
commit | f4e603f291c7badaa6489d0f9d00e71bd7fc579c (patch) | |
tree | d082f1ed9afe8014c9bbb2b74dcaae6a82c093b9 /plumbing/format | |
parent | f6aca0820fb0a44d4c4875a21581a09609d63a6b (diff) | |
download | go-git-f4e603f291c7badaa6489d0f9d00e71bd7fc579c.tar.gz |
plumbing: packfile, Add a buffer to crc writer.
crc update with block smaller than 16 bytes uses a slower version of the
function. ReadByte is heavily used by zlib inflate so most of the time
crc is update byte by byte.
A new Flush method is added to the scanner to flush this crc writer
cache. It is only called when the Scanner reader is a teeReader.
Signed-off-by: Javi Fontan <jfontan@gmail.com>
Diffstat (limited to 'plumbing/format')
-rw-r--r-- | plumbing/format/packfile/scanner.go | 40 |
1 files changed, 31 insertions, 9 deletions
diff --git a/plumbing/format/packfile/scanner.go b/plumbing/format/packfile/scanner.go index d2d776f..8c216f1 100644 --- a/plumbing/format/packfile/scanner.go +++ b/plumbing/format/packfile/scanner.go @@ -63,10 +63,7 @@ func NewScanner(r io.Reader) *Scanner { crc := crc32.NewIEEE() return &Scanner{ - r: &teeReader{ - newByteReadSeeker(seeker), - crc, - }, + r: newTeeReader(newByteReadSeeker(seeker), crc), crc: crc, IsSeekable: ok, } @@ -143,6 +140,8 @@ func (s *Scanner) readCount() (uint32, error) { // NextObjectHeader returns the ObjectHeader for the next object in the reader func (s *Scanner) NextObjectHeader() (*ObjectHeader, error) { + defer s.Flush() + if err := s.doPending(); err != nil { return nil, err } @@ -271,6 +270,7 @@ func (s *Scanner) NextObject(w io.Writer) (written int64, crc32 uint32, err erro s.pendingObject = nil written, err = s.copyObject(w) + s.Flush() crc32 = s.crc.Sum32() return } @@ -339,6 +339,16 @@ func (s *Scanner) Close() error { return err } +// Flush finishes writing the buffer to crc hasher in case we are using +// a teeReader. Otherwise it is a no-op. +func (s *Scanner) Flush() error { + tee, ok := s.r.(*teeReader) + if ok { + return tee.Flush() + } + return nil +} + type trackableReader struct { count int64 io.Reader @@ -400,10 +410,21 @@ type reader interface { type teeReader struct { reader - w hash.Hash32 + w hash.Hash32 + bufWriter *bufio.Writer +} + +func newTeeReader(r reader, h hash.Hash32) *teeReader { + return &teeReader{ + reader: r, + w: h, + bufWriter: bufio.NewWriter(h), + } } func (r *teeReader) Read(p []byte) (n int, err error) { + r.Flush() + n, err = r.reader.Read(p) if n > 0 { if n, err := r.w.Write(p[:n]); err != nil { @@ -416,11 +437,12 @@ func (r *teeReader) Read(p []byte) (n int, err error) { func (r *teeReader) ReadByte() (b byte, err error) { b, err = r.reader.ReadByte() if err == nil { - _, err := r.w.Write([]byte{b}) - if err != nil { - return 0, err - } + return b, r.bufWriter.WriteByte(b) } return } + +func (r *teeReader) Flush() (err error) { + return r.bufWriter.Flush() +} |