feat(common): add zero buffer checker

cpu: Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz
BenchmarkIsZeroBuffer
BenchmarkIsZeroBuffer/1M-zero-all
BenchmarkIsZeroBuffer/1M-zero-all-4        50384       23927   ns/op  0 B/op  0 allocs/op
BenchmarkIsZeroBuffer/1M-not-zero-first
BenchmarkIsZeroBuffer/1M-not-zero-first-4  1000000000      0.4 ns/op  0 B/op  0 allocs/op
BenchmarkIsZeroBuffer/1M-not-zero-mid
BenchmarkIsZeroBuffer/1M-not-zero-mid-4    108770      10617   ns/op  0 B/op  0 allocs/op
BenchmarkIsZeroBuffer/1M-not-zero-last
BenchmarkIsZeroBuffer/1M-not-zero-last-4   48726       22504   ns/op  0 B/op  0 allocs/op

. #1000180877

Signed-off-by: slasher <shenjie1@oppo.com>
This commit is contained in:
slasher 2025-06-17 10:30:34 +08:00
parent 22bb533794
commit ed1b827156
2 changed files with 74 additions and 0 deletions

View File

@ -15,10 +15,14 @@
package crc32block
import (
"bytes"
"encoding/binary"
"errors"
"hash/crc32"
"io"
"sync"
"github.com/cubefs/cubefs/blobstore/util"
)
const (
@ -115,6 +119,7 @@ func readFullOrToEnd(r io.Reader, buffer []byte) (n int, err error) {
var (
_k16 = 16 << 10
_buffer16k = make([]byte, _k16)
_bufferZero = make([]byte, _k16)
_mapZeroCrc = sync.Map{}
)
@ -141,3 +146,20 @@ func ConstZeroCrc(size int) uint32 {
_mapZeroCrc.Store(size, crc)
return crc
}
func IsZeroBuffer(buffer []byte) bool {
const width = 8
if len(buffer) > width {
if binary.BigEndian.Uint64(buffer[:width]) != 0 {
return false
}
}
for len(buffer) > 0 {
minl := util.Min(len(buffer), _k16)
if !bytes.Equal(buffer[:minl], _bufferZero[:minl]) {
return false
}
buffer = buffer[minl:]
}
return true
}

View File

@ -15,6 +15,7 @@
package crc32block
import (
crand "crypto/rand"
"hash/crc32"
"math/rand"
"testing"
@ -92,3 +93,54 @@ func TestConstZeroCrc(t *testing.T) {
require.Equal(t, act, get2)
}
}
func TestIsZeroBuffer(t *testing.T) {
require.True(t, IsZeroBuffer(nil))
for _, size := range []int{1, 3, 1 << 10, 1 << 19} {
buffer := make([]byte, size)
require.True(t, IsZeroBuffer(buffer))
buffer[0] = 'a'
require.False(t, IsZeroBuffer(buffer))
buffer[0] = 0
buffer[len(buffer)-1] = 'z'
require.False(t, IsZeroBuffer(buffer))
buffer[len(buffer)-1] = 0
require.True(t, IsZeroBuffer(buffer))
crand.Read(buffer)
require.False(t, IsZeroBuffer(buffer))
}
}
func BenchmarkIsZeroBuffer(b *testing.B) {
b.Run("1M-zero-all", func(b *testing.B) {
buffer := make([]byte, 1<<20)
b.ResetTimer()
for ii := 0; ii <= b.N; ii++ {
IsZeroBuffer(buffer)
}
})
b.Run("1M-not-zero-first", func(b *testing.B) {
buffer := make([]byte, 1<<20)
buffer[7] = 1
b.ResetTimer()
for ii := 0; ii <= b.N; ii++ {
IsZeroBuffer(buffer)
}
})
b.Run("1M-not-zero-mid", func(b *testing.B) {
buffer := make([]byte, 1<<20)
buffer[1<<19] = 1
b.ResetTimer()
for ii := 0; ii <= b.N; ii++ {
IsZeroBuffer(buffer)
}
})
b.Run("1M-not-zero-last", func(b *testing.B) {
buffer := make([]byte, 1<<20)
buffer[(1<<20)-1] = 1
b.ResetTimer()
for ii := 0; ii <= b.N; ii++ {
IsZeroBuffer(buffer)
}
})
}