Skip to content

Commit

Permalink
deduplicate simultaneous requests for the same namespace
Browse files Browse the repository at this point in the history
  • Loading branch information
jakedt committed Dec 17, 2021
1 parent 3b8904f commit 073a16b
Showing 1 changed file with 23 additions and 14 deletions.
37 changes: 23 additions & 14 deletions internal/namespace/caching.go
Expand Up @@ -9,6 +9,7 @@ import (
v0 "github.com/authzed/authzed-go/proto/authzed/api/v0"
"github.com/dgraph-io/ristretto"
"github.com/shopspring/decimal"
"golang.org/x/sync/singleflight"
"google.golang.org/protobuf/proto"

"github.com/authzed/spicedb/internal/datastore"
Expand All @@ -20,9 +21,10 @@ const (
)

type cachingManager struct {
delegate datastore.Datastore
expiration time.Duration
c *ristretto.Cache
delegate datastore.Datastore
expiration time.Duration
c *ristretto.Cache
readNsGroup singleflight.Group
}

func cacheKey(nsName string, revision decimal.Decimal) string {
Expand Down Expand Up @@ -70,29 +72,36 @@ func (nsc cachingManager) ReadNamespace(ctx context.Context, nsName string, revi
defer span.End()

// Check the cache.
value, found := nsc.c.Get(cacheKey(nsName, revision))
nsRevisionKey := cacheKey(nsName, revision)
value, found := nsc.c.Get(nsRevisionKey)
if found {
return value.(*v0.NamespaceDefinition), nil
}

// We couldn't use the cached entry, load one
loaded, _, err := nsc.delegate.ReadNamespace(ctx, nsName, revision)
loadedRaw, err, _ := nsc.readNsGroup.Do(nsRevisionKey, func() (interface{}, error) {
loaded, _, err := nsc.delegate.ReadNamespace(ctx, nsName, revision)
if err != nil {
return nil, err
}

// Remove user-defined metadata.
loaded = namespace.FilterUserDefinedMetadata(loaded)

// Save it to the cache
nsc.c.Set(cacheKey(nsName, revision), loaded, int64(proto.Size(loaded)))
span.AddEvent("Saved to cache")

return loaded, err
})
if errors.As(err, &datastore.ErrNamespaceNotFound{}) {
return nil, NewNamespaceNotFoundErr(nsName)
}
if err != nil {
return nil, err
}

// Remove user-defined metadata.
loaded = namespace.FilterUserDefinedMetadata(loaded)

// Save it to the cache
nsc.c.Set(cacheKey(nsName, revision), loaded, int64(proto.Size(loaded)))

span.AddEvent("Saved to cache")

return loaded, nil
return loadedRaw.(*v0.NamespaceDefinition), nil
}

func (nsc cachingManager) CheckNamespaceAndRelation(ctx context.Context, namespace, relation string, allowEllipsis bool, revision decimal.Decimal) error {
Expand Down

0 comments on commit 073a16b

Please sign in to comment.