summaryrefslogtreecommitdiff
path: root/vendor/github.com/authzed/spicedb/pkg/proto/dispatch/v1/02_resolvermeta.go
blob: 93742e06a7403978a8ab7eaa08e7557b97ec7f5c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package dispatchv1

import (
	"fmt"

	"github.com/authzed/spicedb/pkg/spiceerrors"

	"github.com/bits-and-blooms/bloom/v3"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

func (x *ResolverMeta) RecordTraversal(key string) (possiblyLoop bool, err error) {
	if key == "" {
		return false, spiceerrors.MustBugf("missing key to be recorded in traversal")
	}

	if x == nil || len(x.TraversalBloom) == 0 {
		return false, status.Error(codes.Internal, fmt.Errorf("required traversal bloom filter is missing").Error())
	}

	bf := &bloom.BloomFilter{}
	if err := bf.UnmarshalBinary(x.TraversalBloom); err != nil {
		return false, status.Error(codes.Internal, fmt.Errorf("unable to unmarshall traversal bloom filter: %w", err).Error())
	}

	if bf.TestString(key) {
		return true, nil
	}

	x.TraversalBloom, err = bf.AddString(key).MarshalBinary()
	if err != nil {
		return false, err
	}

	return false, nil
}

const defaultFalsePositiveRate = 0.001

// NewTraversalBloomFilter creates a new bloom filter sized to the provided number of elements and
// with a predefined false-positive ratio of 0.1%.
func NewTraversalBloomFilter(numElements uint) ([]byte, error) {
	bf := bloom.NewWithEstimates(numElements, defaultFalsePositiveRate)

	emptyBloomFilter, err := bf.MarshalBinary()
	if err != nil {
		return nil, spiceerrors.MustBugf("unexpected error while serializing empty bloom filter: %s", err.Error())
	}

	return emptyBloomFilter, nil
}

// MustNewTraversalBloomFilter creates a new bloom filter sized to the provided number of elements and
// with a predefined false-positive ratio of 0.1%.
func MustNewTraversalBloomFilter(numElements uint) []byte {
	bf, err := NewTraversalBloomFilter(numElements)
	if err != nil {
		panic(err)
	}

	return bf
}