aboutsummaryrefslogtreecommitdiffstats
path: root/plumbing
diff options
context:
space:
mode:
authorJavi Fontan <jfontan@gmail.com>2018-01-19 16:12:11 +0100
committerJavi Fontan <jfontan@gmail.com>2018-01-21 21:49:22 +0100
commitf4e603f291c7badaa6489d0f9d00e71bd7fc579c (patch)
treed082f1ed9afe8014c9bbb2b74dcaae6a82c093b9 /plumbing
parentf6aca0820fb0a44d4c4875a21581a09609d63a6b (diff)
downloadgo-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')
-rw-r--r--plumbing/format/packfile/scanner.go40
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()
+}