Skip to content

Commit

Permalink
avro: fix fingerprint to avoid data race
Browse files Browse the repository at this point in the history
  • Loading branch information
getumen authored Jan 23, 2021
1 parent f94d2b1 commit c13a80d
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 18 deletions.
29 changes: 12 additions & 17 deletions schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,13 @@ import (
"hash"
"strconv"
"strings"
"sync/atomic"

"github.com/hamba/avro/pkg/crc64"
"github.com/modern-go/concurrent"
)

var (
emptyFgpt = [32]byte{}
nullDefault = struct{}{}
)
var nullDefault = struct{}{}

// Type is a schema type.
type Type string
Expand Down Expand Up @@ -211,28 +209,25 @@ func (n name) FullName() string {
}

type fingerprinter struct {
fingerprint [32]byte
cache map[FingerprintType][]byte
fingerprint atomic.Value // [32]byte
cache concurrent.Map // map[FingerprintType][]byte
}

// Fingerprint returns the SHA256 fingerprint of the schema.
func (f *fingerprinter) Fingerprint(stringer fmt.Stringer) [32]byte {
if f.fingerprint != emptyFgpt {
return f.fingerprint
if v := f.fingerprint.Load(); v != nil {
return v.([32]byte)
}

f.fingerprint = sha256.Sum256([]byte(stringer.String()))
return f.fingerprint
fingerprint := sha256.Sum256([]byte(stringer.String()))
f.fingerprint.Store(fingerprint)
return fingerprint
}

// FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error.
func (f *fingerprinter) FingerprintUsing(typ FingerprintType, stringer fmt.Stringer) ([]byte, error) {
if f.cache == nil {
f.cache = map[FingerprintType][]byte{}
}

if b, ok := f.cache[typ]; ok {
return b, nil
if v, ok := f.cache.Load(typ); ok {
return v.([]byte), nil
}

h, ok := fingerprinters[typ]
Expand All @@ -243,7 +238,7 @@ func (f *fingerprinter) FingerprintUsing(typ FingerprintType, stringer fmt.Strin
h.Reset()
_, _ = h.Write([]byte(stringer.String()))
fingerprint := h.Sum(make([]byte, 0, h.Size()))
f.cache[typ] = fingerprint
f.cache.Store(typ, fingerprint)
return fingerprint, nil
}

Expand Down
4 changes: 3 additions & 1 deletion schema_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,8 @@ func TestSchema_FingerprintUsingCaches(t *testing.T) {

got, _ := schema.FingerprintUsing(CRC64Avro)

assert.Equal(t, want, schema.cache[CRC64Avro])
value, ok := schema.cache.Load(CRC64Avro)
assert.True(t, ok)
assert.Equal(t, want, value)
assert.Equal(t, want, got)
}

0 comments on commit c13a80d

Please sign in to comment.