github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/pkg/proto/dispatch/v1/02_resolvermeta.go (about) 1 package dispatchv1 2 3 import ( 4 "fmt" 5 6 "github.com/authzed/spicedb/pkg/spiceerrors" 7 8 "github.com/bits-and-blooms/bloom/v3" 9 "google.golang.org/grpc/codes" 10 "google.golang.org/grpc/status" 11 ) 12 13 func (x *ResolverMeta) RecordTraversal(key string) (possiblyLoop bool, err error) { 14 if key == "" { 15 return false, spiceerrors.MustBugf("missing key to be recorded in traversal") 16 } 17 18 if x == nil || len(x.TraversalBloom) == 0 { 19 return false, status.Error(codes.Internal, fmt.Errorf("required traversal bloom filter is missing").Error()) 20 } 21 22 bf := &bloom.BloomFilter{} 23 if err := bf.UnmarshalBinary(x.TraversalBloom); err != nil { 24 return false, status.Error(codes.Internal, fmt.Errorf("unable to unmarshall traversal bloom filter: %w", err).Error()) 25 } 26 27 if bf.TestString(key) { 28 return true, nil 29 } 30 31 x.TraversalBloom, err = bf.AddString(key).MarshalBinary() 32 if err != nil { 33 return false, err 34 } 35 36 return false, nil 37 } 38 39 const defaultFalsePositiveRate = 0.001 40 41 // NewTraversalBloomFilter creates a new bloom filter sized to the provided number of elements and 42 // with a predefined false-positive ratio of 0.1%. 43 func NewTraversalBloomFilter(numElements uint) ([]byte, error) { 44 bf := bloom.NewWithEstimates(numElements, defaultFalsePositiveRate) 45 46 emptyBloomFilter, err := bf.MarshalBinary() 47 if err != nil { 48 return nil, spiceerrors.MustBugf("unexpected error while serializing empty bloom filter: %s", err.Error()) 49 } 50 51 return emptyBloomFilter, nil 52 } 53 54 // MustNewTraversalBloomFilter creates a new bloom filter sized to the provided number of elements and 55 // with a predefined false-positive ratio of 0.1%. 56 func MustNewTraversalBloomFilter(numElements uint) []byte { 57 bf, err := NewTraversalBloomFilter(numElements) 58 if err != nil { 59 panic(err) 60 } 61 62 return bf 63 }