Browse Source

lib/scanner: Simplify, optimize and document Validate (#6674) (#6688)

greatroar 5 years ago
parent
commit
9c0825c0d9
2 changed files with 48 additions and 13 deletions
  1. 6 13
      lib/scanner/blocks.go
  2. 42 0
      lib/scanner/blocks_test.go

+ 6 - 13
lib/scanner/blocks.go

@@ -108,26 +108,19 @@ func Blocks(ctx context.Context, r io.Reader, blocksize int, sizehint int64, cou
 	return blocks, nil
 }
 
+// Validate quickly validates buf against the cryptohash hash (if len(hash)>0)
+// and the 32-bit hash weakHash (if not zero). It is satisfied if either hash
+// matches, or neither is given.
 func Validate(buf, hash []byte, weakHash uint32) bool {
-	rd := bytes.NewReader(buf)
 	if weakHash != 0 {
-		whf := adler32.New()
-		if _, err := io.Copy(whf, rd); err == nil && whf.Sum32() == weakHash {
-			return true
-		}
-		// Copy error or mismatch, go to next algo.
-		rd.Seek(0, io.SeekStart)
+		return adler32.Checksum(buf) == weakHash
 	}
 
 	if len(hash) > 0 {
-		hf := sha256.New()
-		if _, err := io.Copy(hf, rd); err == nil {
-			// Sum allocates, so let's hope we don't hit this often.
-			return bytes.Equal(hf.Sum(nil), hash)
-		}
+		hbuf := sha256.Sum256(buf)
+		return bytes.Equal(hbuf[:], hash)
 	}
 
-	// Both algos failed or no hashes were specified. Assume it's all good.
 	return true
 }
 

+ 42 - 0
lib/scanner/blocks_test.go

@@ -12,11 +12,13 @@ import (
 	"crypto/rand"
 	"fmt"
 	origAdler32 "hash/adler32"
+	mrand "math/rand"
 	"testing"
 	"testing/quick"
 
 	rollingAdler32 "github.com/chmduquesne/rollinghash/adler32"
 	"github.com/syncthing/syncthing/lib/protocol"
+	"github.com/syncthing/syncthing/lib/sha256"
 )
 
 var blocksTestData = []struct {
@@ -165,3 +167,43 @@ func TestAdler32Variants(t *testing.T) {
 		hf3.Roll(data[i])
 	}
 }
+
+func BenchmarkValidate(b *testing.B) {
+	type block struct {
+		data     []byte
+		hash     [sha256.Size]byte
+		weakhash uint32
+	}
+	var blocks []block
+	const blocksPerType = 100
+
+	r := mrand.New(mrand.NewSource(0x136bea689e851))
+
+	// Valid blocks.
+	for i := 0; i < blocksPerType; i++ {
+		var b block
+		b.data = make([]byte, 128<<10)
+		r.Read(b.data[:])
+		b.hash = sha256.Sum256(b.data[:])
+		b.weakhash = origAdler32.Checksum(b.data[:])
+		blocks = append(blocks, b)
+	}
+	// Blocks where the hash matches, but the weakhash doesn't.
+	for i := 0; i < blocksPerType; i++ {
+		var b block
+		b.data = make([]byte, 128<<10)
+		r.Read(b.data[:])
+		b.hash = sha256.Sum256(b.data[:])
+		b.weakhash = 1 // Zeros causes Validate to skip the weakhash.
+		blocks = append(blocks, b)
+	}
+
+	b.ReportAllocs()
+	b.ResetTimer()
+
+	for i := 0; i < b.N; i++ {
+		for _, b := range blocks {
+			Validate(b.data[:], b.hash[:], b.weakhash)
+		}
+	}
+}