github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/datastore/proxy/singleflight.go (about) 1 package proxy 2 3 import ( 4 "context" 5 6 "resenje.org/singleflight" 7 8 "github.com/authzed/spicedb/pkg/datastore" 9 "github.com/authzed/spicedb/pkg/datastore/options" 10 ) 11 12 // NewSingleflightDatastoreProxy creates a new Datastore proxy which 13 // deduplicates calls to Datastore methods that can share results. 14 func NewSingleflightDatastoreProxy(d datastore.Datastore) datastore.Datastore { 15 return &singleflightProxy{delegate: d} 16 } 17 18 type singleflightProxy struct { 19 headRevGroup singleflight.Group[string, datastore.Revision] 20 optRevGroup singleflight.Group[string, datastore.Revision] 21 checkRevGroup singleflight.Group[string, string] 22 statsGroup singleflight.Group[string, datastore.Stats] 23 delegate datastore.Datastore 24 } 25 26 var _ datastore.Datastore = (*singleflightProxy)(nil) 27 28 func (p *singleflightProxy) SnapshotReader(rev datastore.Revision) datastore.Reader { 29 return p.delegate.SnapshotReader(rev) 30 } 31 32 func (p *singleflightProxy) ReadWriteTx(ctx context.Context, f datastore.TxUserFunc, opts ...options.RWTOptionsOption) (datastore.Revision, error) { 33 return p.delegate.ReadWriteTx(ctx, f, opts...) 34 } 35 36 func (p *singleflightProxy) OptimizedRevision(ctx context.Context) (datastore.Revision, error) { 37 rev, _, err := p.optRevGroup.Do(ctx, "", func(ctx context.Context) (datastore.Revision, error) { 38 return p.delegate.OptimizedRevision(ctx) 39 }) 40 return rev, err 41 } 42 43 func (p *singleflightProxy) CheckRevision(ctx context.Context, revision datastore.Revision) error { 44 _, _, err := p.checkRevGroup.Do(ctx, revision.String(), func(ctx context.Context) (string, error) { 45 return "", p.delegate.CheckRevision(ctx, revision) 46 }) 47 return err 48 } 49 50 func (p *singleflightProxy) HeadRevision(ctx context.Context) (datastore.Revision, error) { 51 rev, _, err := p.headRevGroup.Do(ctx, "", func(ctx context.Context) (datastore.Revision, error) { 52 return p.delegate.HeadRevision(ctx) 53 }) 54 return rev, err 55 } 56 57 func (p *singleflightProxy) RevisionFromString(serialized string) (datastore.Revision, error) { 58 return p.delegate.RevisionFromString(serialized) 59 } 60 61 func (p *singleflightProxy) Watch(ctx context.Context, afterRevision datastore.Revision, options datastore.WatchOptions) (<-chan *datastore.RevisionChanges, <-chan error) { 62 return p.delegate.Watch(ctx, afterRevision, options) 63 } 64 65 func (p *singleflightProxy) Statistics(ctx context.Context) (datastore.Stats, error) { 66 stats, _, err := p.statsGroup.Do(ctx, "", func(ctx context.Context) (datastore.Stats, error) { 67 return p.delegate.Statistics(ctx) 68 }) 69 return stats, err 70 } 71 72 func (p *singleflightProxy) Features(ctx context.Context) (*datastore.Features, error) { 73 return p.delegate.Features(ctx) 74 } 75 76 func (p *singleflightProxy) ReadyState(ctx context.Context) (datastore.ReadyState, error) { 77 return p.delegate.ReadyState(ctx) 78 } 79 80 func (p *singleflightProxy) Close() error { return p.delegate.Close() } 81 func (p *singleflightProxy) Unwrap() datastore.Datastore { return p.delegate }