From 92f079f415b5fede65c4eb8c49be9c2f1bf7ada5 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 10 Aug 2020 20:18:57 -0700 Subject: [PATCH] Optimize discarding in ScanForLinks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This gives a pretty significant speedup and drops us down to an allocation per link. name old time/op new time/op delta LinkScan-4 4.03µs ± 3% 1.26µs ±12% -68.79% (p=0.000 n=10+10) name old alloc/op new alloc/op delta LinkScan-4 881B ± 0% 112B ± 0% -87.29% (p=0.002 n=8+10) name old allocs/op new allocs/op delta LinkScan-4 25.0 ± 0% 1.0 ± 0% -96.00% (p=0.000 n=10+10) --- utils.go | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/utils.go b/utils.go index 1d38cdf..be71c37 100644 --- a/utils.go +++ b/utils.go @@ -16,6 +16,33 @@ import ( const maxCidLength = 100 const maxHeaderSize = 9 +// discard is a helper function to discard data from a reader, special-casing +// the most common readers we encounter in this library for a significant +// performance boost. +func discard(br io.Reader, n int) error { + switch r := br.(type) { + case *bytes.Buffer: + buf := r.Next(n) + if len(buf) < n { + return io.ErrUnexpectedEOF + } + return nil + case *bytes.Reader: + if r.Len() < n { + _, _ = r.Seek(0, io.SeekEnd) + return io.ErrUnexpectedEOF + } + _, err := r.Seek(int64(n), io.SeekCurrent) + return err + case *bufio.Reader: + _, err := r.Discard(n) + return err + default: + _, err := io.CopyN(ioutil.Discard, br, int64(n)) + return err + } +} + func ScanForLinks(br io.Reader, cb func(cid.Cid)) error { scratch := make([]byte, maxCidLength) for remaining := uint64(1); remaining > 0; remaining-- { @@ -27,7 +54,7 @@ func ScanForLinks(br io.Reader, cb func(cid.Cid)) error { switch maj { case MajUnsignedInt, MajNegativeInt, MajOther: case MajByteString, MajTextString: - _, err := io.CopyN(ioutil.Discard, br, int64(extra)) + err := discard(br, int(extra)) if err != nil { return err } -- GitLab