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  }