github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/dispatch/keys/hasher_ristretto.go (about) 1 //go:build !wasm 2 // +build !wasm 3 4 package keys 5 6 import ( 7 "fmt" 8 "unsafe" 9 10 "github.com/cespare/xxhash/v2" 11 ) 12 13 // dispatchCacheKeyHash computres a DispatchCheckKey for the given prefix and any hashable values. 14 func dispatchCacheKeyHash(prefix cachePrefix, atRevision string, computeOption dispatchCacheKeyHashComputeOption, args ...hashableValue) DispatchCacheKey { 15 hasher := newDispatchCacheKeyHasher(prefix, computeOption) 16 17 for _, arg := range args { 18 arg.AppendToHash(hasher) 19 hasher.WriteString("@") 20 } 21 22 hasher.WriteString(atRevision) 23 return hasher.BuildKey() 24 } 25 26 type dispatchCacheKeyHasher struct { 27 stableHasher *xxhash.Digest 28 computeOption dispatchCacheKeyHashComputeOption 29 processSpecificSum uint64 30 } 31 32 func newDispatchCacheKeyHasher(prefix cachePrefix, computeOption dispatchCacheKeyHashComputeOption) *dispatchCacheKeyHasher { 33 h := &dispatchCacheKeyHasher{ 34 stableHasher: xxhash.New(), 35 computeOption: computeOption, 36 } 37 38 prefixString := string(prefix) 39 h.WriteString(prefixString) 40 h.WriteString("/") 41 return h 42 } 43 44 // WriteString writes a single string to the hasher. 45 func (h *dispatchCacheKeyHasher) WriteString(value string) { 46 h.mustWriteString(value) 47 } 48 49 func (h *dispatchCacheKeyHasher) mustWriteString(value string) { 50 // NOTE: xxhash doesn't seem to ever return an error for WriteString, but we check it just 51 // to be on the safe side. 52 _, err := h.stableHasher.WriteString(value) 53 if err != nil { 54 panic(fmt.Errorf("got an error from writing to the stable hasher: %w", err)) 55 } 56 57 if h.computeOption == computeBothHashes { 58 h.processSpecificSum = runMemHash(h.processSpecificSum, []byte(value)) 59 } 60 } 61 62 // From: https://github.com/outcaste-io/ristretto/blob/master/z/rtutil.go 63 type stringStruct struct { 64 str unsafe.Pointer 65 len int 66 } 67 68 //go:noescape 69 //go:linkname memhash runtime.memhash 70 func memhash(p unsafe.Pointer, h, s uintptr) uintptr 71 72 func runMemHash(seed uint64, data []byte) uint64 { 73 ss := (*stringStruct)(unsafe.Pointer(&data)) 74 return uint64(memhash(ss.str, uintptr(seed), uintptr(ss.len))) 75 } 76 77 // BuildKey returns the constructed DispatchCheckKey. 78 func (h *dispatchCacheKeyHasher) BuildKey() DispatchCacheKey { 79 return DispatchCacheKey{ 80 stableSum: h.stableHasher.Sum64(), 81 processSpecificSum: h.processSpecificSum, 82 } 83 }