diff --git a/internal/datastore/spanner/options.go b/internal/datastore/spanner/options.go index 06001501fa..8651ea078f 100644 --- a/internal/datastore/spanner/options.go +++ b/internal/datastore/spanner/options.go @@ -113,7 +113,7 @@ func RevisionQuantization(bucketSize time.Duration) Option { } } -// FollowerReadDelay is the time delay to apply to enable historial reads. +// FollowerReadDelay is the time delay to apply to enable historical reads. // // This value defaults to 0 seconds. func FollowerReadDelay(delay time.Duration) Option { diff --git a/internal/datastore/spanner/revisions.go b/internal/datastore/spanner/revisions.go index eadd7c809a..2f1c1abae7 100644 --- a/internal/datastore/spanner/revisions.go +++ b/internal/datastore/spanner/revisions.go @@ -11,28 +11,27 @@ import ( "github.com/authzed/spicedb/pkg/datastore" ) -var ParseRevisionString = revisions.RevisionParser(revisions.Timestamp) +var ( + ParseRevisionString = revisions.RevisionParser(revisions.Timestamp) + nowStmt = spanner.NewStatement("SELECT CURRENT_TIMESTAMP()") +) -func (sd *spannerDatastore) headRevisionInternal(ctx context.Context) (datastore.Revision, error) { - now, err := sd.now(ctx) - if err != nil { +func (sd *spannerDatastore) HeadRevision(ctx context.Context) (datastore.Revision, error) { + var timestamp time.Time + if err := sd.client.Single().Query(ctx, nowStmt).Do(func(r *spanner.Row) error { + return r.Columns(×tamp) + }); err != nil { return datastore.NoRevision, fmt.Errorf(errRevision, err) } - - return revisions.NewForTime(now), nil + return revisions.NewForTime(timestamp), nil } -func (sd *spannerDatastore) HeadRevision(ctx context.Context) (datastore.Revision, error) { - return sd.headRevisionInternal(ctx) -} - -func (sd *spannerDatastore) now(ctx context.Context) (time.Time, error) { +func (sd *spannerDatastore) staleHeadRevision(ctx context.Context) (datastore.Revision, error) { var timestamp time.Time - if err := sd.client.Single().Query(ctx, spanner.NewStatement("SELECT CURRENT_TIMESTAMP()")).Do(func(r *spanner.Row) error { + if err := sd.client.Single().WithTimestampBound(spanner.ExactStaleness(sd.config.followerReadDelay)).Query(ctx, nowStmt).Do(func(r *spanner.Row) error { return r.Columns(×tamp) }); err != nil { - return time.Time{}, err + return datastore.NoRevision, fmt.Errorf(errRevision, err) } - - return timestamp, nil + return revisions.NewForTime(timestamp), nil } diff --git a/internal/datastore/spanner/spanner.go b/internal/datastore/spanner/spanner.go index 3986b7ef6a..2296368d15 100644 --- a/internal/datastore/spanner/spanner.go +++ b/internal/datastore/spanner/spanner.go @@ -175,7 +175,11 @@ func NewSpannerDatastore(ctx context.Context, database string, opts ...Option) ( cachedEstimatedBytesPerRelationshipLock: sync.RWMutex{}, tableSizesStatsTable: tableSizesStatsTable, } - ds.RemoteClockRevisions.SetNowFunc(ds.headRevisionInternal) + // Optimized revision and revision checking use a stale read for the + // current timestamp. + // TODO: Still investigating whether a stale read can be used for + // HeadRevision for FullConsistency queries. + ds.RemoteClockRevisions.SetNowFunc(ds.staleHeadRevision) return ds, nil } diff --git a/tools/analyzers/go.work.sum b/tools/analyzers/go.work.sum index 13b98a2bd7..359bd9d651 100644 --- a/tools/analyzers/go.work.sum +++ b/tools/analyzers/go.work.sum @@ -1572,6 +1572,8 @@ github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= +github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= github.com/pkg/sftp v1.13.1 h1:I2qBYMChEhIjOgazfJmV3/mZM256btk6wkCDRmW7JYs= github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo=