diff --git a/internal/middleware/consistency/consistency.go b/internal/middleware/consistency/consistency.go index ac6e222870..365d2cf9ca 100644 --- a/internal/middleware/consistency/consistency.go +++ b/internal/middleware/consistency/consistency.go @@ -73,13 +73,24 @@ func RevisionFromContext(ctx context.Context) (datastore.Revision, *v1.ZedToken, return nil, nil, fmt.Errorf("consistency middleware did not inject revision") } +// MismatchingTokenOption is the option specifying the behavior of the consistency middleware +// when a ZedToken provided references a different datastore instance than the current +// datastore instance. type MismatchingTokenOption int const ( + // TreatMismatchingTokensAsFullConsistency specifies that the middleware should treat + // a ZedToken that references a different datastore instance as a request for full + // consistency. TreatMismatchingTokensAsFullConsistency MismatchingTokenOption = iota + // TreatMismatchingTokensAsMinLatency specifies that the middleware should treat + // a ZedToken that references a different datastore instance as a request for min + // latency. TreatMismatchingTokensAsMinLatency + // TreatMismatchingTokensAsError specifies that the middleware should raise an error + // when a ZedToken that references a different datastore instance is provided. TreatMismatchingTokensAsError ) @@ -174,8 +185,7 @@ func addRevisionToContextFromConsistency(ctx context.Context, req hasConsistency } if status == zedtoken.StatusMismatchedDatastoreID { - log.Error().Str("zedtoken", consistency.GetAtExactSnapshot().Token).Msg("ZedToken specified references an older datastore but at-exact-snapshot was requested") - return fmt.Errorf("ZedToken specified references an older datastore but at-exact-snapshot was requested") + return fmt.Errorf("ZedToken specified references a different datastore instance but at-exact-snapshot was requested") } err = ds.CheckRevision(ctx, requestedRev) @@ -267,7 +277,7 @@ func pickBestRevision(ctx context.Context, requested *v1.ZedToken, ds datastore. if status == zedtoken.StatusMismatchedDatastoreID { switch option { case TreatMismatchingTokensAsFullConsistency: - log.Warn().Str("zedtoken", requested.Token).Msg("ZedToken specified references an older datastore and SpiceDB is configured to treat this as a full consistency request") + log.Warn().Str("zedtoken", requested.Token).Msg("ZedToken specified references a different datastore instance and SpiceDB is configured to treat this as a full consistency request") headRev, err := ds.HeadRevision(ctx) if err != nil { return datastore.NoRevision, false, err @@ -276,12 +286,12 @@ func pickBestRevision(ctx context.Context, requested *v1.ZedToken, ds datastore. return headRev, false, nil case TreatMismatchingTokensAsMinLatency: - log.Warn().Str("zedtoken", requested.Token).Msg("ZedToken specified references an older datastore and SpiceDB is configured to treat this as a min latency request") + log.Warn().Str("zedtoken", requested.Token).Msg("ZedToken specified references a different datastore instance and SpiceDB is configured to treat this as a min latency request") return databaseRev, false, nil case TreatMismatchingTokensAsError: - log.Error().Str("zedtoken", requested.Token).Msg("ZedToken specified references an older datastore and SpiceDB is configured to raise an error in this scenario") - return datastore.NoRevision, false, fmt.Errorf("ZedToken specified references an older datastore and SpiceDB is configured to raise an error in this scenario") + log.Warn().Str("zedtoken", requested.Token).Msg("ZedToken specified references a different datastore instance and SpiceDB is configured to raise an error in this scenario") + return datastore.NoRevision, false, fmt.Errorf("ZedToken specified references a different datastore instance and SpiceDB is configured to raise an error in this scenario") default: return datastore.NoRevision, false, spiceerrors.MustBugf("unknown mismatching token option: %v", option) diff --git a/internal/middleware/consistency/consistency_test.go b/internal/middleware/consistency/consistency_test.go index e28a816805..bbc61a5c37 100644 --- a/internal/middleware/consistency/consistency_test.go +++ b/internal/middleware/consistency/consistency_test.go @@ -220,7 +220,7 @@ func TestAtExactSnapshotWithMismatchedToken(t *testing.T) { updated := ContextWithHandle(context.Background()) updated = datastoremw.ContextWithDatastore(updated, ds) - // mint a token with a different datastore ID. + // mint a token with a different datastore instance ID. ds.CurrentUniqueID = "foo" zedToken, err := zedtoken.NewFromRevision(context.Background(), optimized, ds) require.NoError(err) @@ -234,7 +234,7 @@ func TestAtExactSnapshotWithMismatchedToken(t *testing.T) { }, }, ds, TreatMismatchingTokensAsError) require.Error(err) - require.ErrorContains(err, "ZedToken specified references an older datastore but at-exact-snapshot") + require.ErrorContains(err, "ZedToken specified references a different datastore instance but at-exact-snapshot") } func TestAtLeastAsFreshWithMismatchedTokenExpectError(t *testing.T) { @@ -248,7 +248,7 @@ func TestAtLeastAsFreshWithMismatchedTokenExpectError(t *testing.T) { updated := ContextWithHandle(context.Background()) updated = datastoremw.ContextWithDatastore(updated, ds) - // mint a token with a different datastore ID. + // mint a token with a different datastore instance ID. ds.CurrentUniqueID = "foo" zedToken, err := zedtoken.NewFromRevision(context.Background(), optimized, ds) require.NoError(err) @@ -262,7 +262,7 @@ func TestAtLeastAsFreshWithMismatchedTokenExpectError(t *testing.T) { }, }, ds, TreatMismatchingTokensAsError) require.Error(err) - require.ErrorContains(err, "ZedToken specified references an older datastore and SpiceDB is configured to raise an error in this scenario") + require.ErrorContains(err, "ZedToken specified references a different datastore instance and SpiceDB is configured to raise an error in this scenario") } func TestAtLeastAsFreshWithMismatchedTokenExpectMinLatency(t *testing.T) { @@ -276,7 +276,7 @@ func TestAtLeastAsFreshWithMismatchedTokenExpectMinLatency(t *testing.T) { updated := ContextWithHandle(context.Background()) updated = datastoremw.ContextWithDatastore(updated, ds) - // mint a token with a different datastore ID. + // mint a token with a different datastore instance ID. ds.CurrentUniqueID = "foo" zedToken, err := zedtoken.NewFromRevision(context.Background(), optimized, ds) require.NoError(err) @@ -310,7 +310,7 @@ func TestAtLeastAsFreshWithMismatchedTokenExpectFullConsistency(t *testing.T) { updated := ContextWithHandle(context.Background()) updated = datastoremw.ContextWithDatastore(updated, ds) - // mint a token with a different datastore ID. + // mint a token with a different datastore instance ID. ds.CurrentUniqueID = "foo" zedToken, err := zedtoken.NewFromRevision(context.Background(), optimized, ds) require.NoError(err) diff --git a/internal/services/v1/watch.go b/internal/services/v1/watch.go index 8c8bbc7d74..5165235b24 100644 --- a/internal/services/v1/watch.go +++ b/internal/services/v1/watch.go @@ -57,8 +57,13 @@ func (ws *watchServer) Watch(req *v1.WatchRequest, stream v1.WatchService_WatchS return status.Errorf(codes.InvalidArgument, "failed to decode start revision: %s", err) } + // NOTE: if the token given is for a different datastore, we return an error and immediately fail the watch. + // This is necessary because asking for a resumed watch on a *different* datastore instance makes little semantic + // sense and, if we allowed it here, would likely result in missing or wrong events being emitted. This is the + // safest option and should only cause an issue if a client is connecting between instances of SpiceDBs which are, + // themselves, connecting to different datastore instances, which should itself be an invalid configuration. if tokenStatus == zedtoken.StatusMismatchedDatastoreID { - return status.Errorf(codes.InvalidArgument, "start revision was generated by a different datastore") + return status.Errorf(codes.InvalidArgument, "start revision was generated by a different datastore instance") } afterRevision = decodedRevision diff --git a/pkg/cmd/server/zz_generated.options.go b/pkg/cmd/server/zz_generated.options.go index d0aab33461..a1a2811058 100644 --- a/pkg/cmd/server/zz_generated.options.go +++ b/pkg/cmd/server/zz_generated.options.go @@ -82,12 +82,12 @@ func (c *Config) ToOption() ConfigOption { to.MaxDatastoreReadPageSize = c.MaxDatastoreReadPageSize to.StreamingAPITimeout = c.StreamingAPITimeout to.WatchHeartbeat = c.WatchHeartbeat - to.MismatchZedTokenBehavior = c.MismatchZedTokenBehavior to.MaxReadRelationshipsLimit = c.MaxReadRelationshipsLimit to.MaxDeleteRelationshipsLimit = c.MaxDeleteRelationshipsLimit to.MaxLookupResourcesLimit = c.MaxLookupResourcesLimit to.MaxBulkExportRelationshipsLimit = c.MaxBulkExportRelationshipsLimit to.EnableExperimentalLookupResources = c.EnableExperimentalLookupResources + to.MismatchZedTokenBehavior = c.MismatchZedTokenBehavior to.MetricsAPI = c.MetricsAPI to.UnaryMiddlewareModification = c.UnaryMiddlewareModification to.StreamingMiddlewareModification = c.StreamingMiddlewareModification @@ -150,12 +150,12 @@ func (c Config) DebugMap() map[string]any { debugMap["MaxDatastoreReadPageSize"] = helpers.DebugValue(c.MaxDatastoreReadPageSize, false) debugMap["StreamingAPITimeout"] = helpers.DebugValue(c.StreamingAPITimeout, false) debugMap["WatchHeartbeat"] = helpers.DebugValue(c.WatchHeartbeat, false) - debugMap["MismatchZedTokenBehavior"] = helpers.DebugValue(c.MismatchZedTokenBehavior, false) debugMap["MaxReadRelationshipsLimit"] = helpers.DebugValue(c.MaxReadRelationshipsLimit, false) debugMap["MaxDeleteRelationshipsLimit"] = helpers.DebugValue(c.MaxDeleteRelationshipsLimit, false) debugMap["MaxLookupResourcesLimit"] = helpers.DebugValue(c.MaxLookupResourcesLimit, false) debugMap["MaxBulkExportRelationshipsLimit"] = helpers.DebugValue(c.MaxBulkExportRelationshipsLimit, false) debugMap["EnableExperimentalLookupResources"] = helpers.DebugValue(c.EnableExperimentalLookupResources, false) + debugMap["MismatchZedTokenBehavior"] = helpers.DebugValue(c.MismatchZedTokenBehavior, false) debugMap["MetricsAPI"] = helpers.DebugValue(c.MetricsAPI, false) debugMap["SilentlyDisableTelemetry"] = helpers.DebugValue(c.SilentlyDisableTelemetry, false) debugMap["TelemetryCAOverridePath"] = helpers.DebugValue(c.TelemetryCAOverridePath, false) @@ -519,13 +519,6 @@ func WithWatchHeartbeat(watchHeartbeat time.Duration) ConfigOption { } } -// WithMismatchZedTokenBehavior returns an option that can set MismatchZedTokenBehavior on a Config -func WithMismatchZedTokenBehavior(mismatchZedTokenBehavior string) ConfigOption { - return func(c *Config) { - c.MismatchZedTokenBehavior = mismatchZedTokenBehavior - } -} - // WithMaxReadRelationshipsLimit returns an option that can set MaxReadRelationshipsLimit on a Config func WithMaxReadRelationshipsLimit(maxReadRelationshipsLimit uint32) ConfigOption { return func(c *Config) { @@ -561,6 +554,13 @@ func WithEnableExperimentalLookupResources(enableExperimentalLookupResources boo } } +// WithMismatchZedTokenBehavior returns an option that can set MismatchZedTokenBehavior on a Config +func WithMismatchZedTokenBehavior(mismatchZedTokenBehavior string) ConfigOption { + return func(c *Config) { + c.MismatchZedTokenBehavior = mismatchZedTokenBehavior + } +} + // WithMetricsAPI returns an option that can set MetricsAPI on a Config func WithMetricsAPI(metricsAPI util.HTTPServerConfig) ConfigOption { return func(c *Config) { diff --git a/pkg/proto/impl/v1/impl.pb.go b/pkg/proto/impl/v1/impl.pb.go index 2a08e7ce5b..4c96a27b48 100644 --- a/pkg/proto/impl/v1/impl.pb.go +++ b/pkg/proto/impl/v1/impl.pb.go @@ -815,9 +815,9 @@ type DecodedZedToken_V1ZedToken struct { unknownFields protoimpl.UnknownFields Revision string `protobuf:"bytes,1,opt,name=revision,proto3" json:"revision,omitempty"` - // datastore_unique_id is the unique ID for the datastore. Will be empty for legacy - // tokens. - DatastoreUniqueId string `protobuf:"bytes,2,opt,name=datastore_unique_id,json=datastoreUniqueId,proto3" json:"datastore_unique_id,omitempty"` + // datastore_unique_id_prefix is a prefix of the unique ID for the datastore that created + // this token. Will be empty for legacy tokens. + DatastoreUniqueIdPrefix string `protobuf:"bytes,2,opt,name=datastore_unique_id_prefix,json=datastoreUniqueIdPrefix,proto3" json:"datastore_unique_id_prefix,omitempty"` } func (x *DecodedZedToken_V1ZedToken) Reset() { @@ -859,9 +859,9 @@ func (x *DecodedZedToken_V1ZedToken) GetRevision() string { return "" } -func (x *DecodedZedToken_V1ZedToken) GetDatastoreUniqueId() string { +func (x *DecodedZedToken_V1ZedToken) GetDatastoreUniqueIdPrefix() string { if x != nil { - return x.DatastoreUniqueId + return x.DatastoreUniqueIdPrefix } return "" } @@ -895,7 +895,7 @@ var file_impl_v1_impl_proto_rawDesc = []byte{ 0x08, 0x56, 0x32, 0x5a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x0f, 0x0a, 0x0d, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x5f, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x22, 0xb2, 0x02, 0x0a, 0x0f, 0x44, 0x65, 0x63, 0x6f, 0x64, + 0x5f, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x22, 0xbf, 0x02, 0x0a, 0x0f, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x5a, 0x65, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x55, 0x0a, 0x14, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x76, 0x31, 0x5f, 0x7a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x69, 0x6d, 0x70, 0x6c, 0x2e, @@ -908,63 +908,64 @@ var file_impl_v1_impl_proto_rawDesc = []byte{ 0x65, 0x6e, 0x48, 0x00, 0x52, 0x02, 0x76, 0x31, 0x1a, 0x26, 0x0a, 0x08, 0x56, 0x31, 0x5a, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x1a, 0x58, 0x0a, 0x0a, 0x56, 0x31, 0x5a, 0x65, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, + 0x1a, 0x65, 0x0a, 0x0a, 0x56, 0x31, 0x5a, 0x65, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x13, 0x64, 0x61, + 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x1a, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x5f, 0x69, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, - 0x72, 0x65, 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x64, 0x42, 0x0f, 0x0a, 0x0d, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x22, 0x45, 0x0a, 0x0d, 0x44, - 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x12, 0x23, 0x0a, 0x02, - 0x76, 0x31, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x69, 0x6d, 0x70, 0x6c, 0x2e, - 0x76, 0x31, 0x2e, 0x56, 0x31, 0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x48, 0x00, 0x52, 0x02, 0x76, - 0x31, 0x42, 0x0f, 0x0a, 0x0d, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x6e, 0x65, - 0x6f, 0x66, 0x22, 0xd6, 0x01, 0x0a, 0x08, 0x56, 0x31, 0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x12, - 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x73, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x37, 0x0a, 0x18, 0x63, 0x61, 0x6c, 0x6c, 0x5f, - 0x61, 0x6e, 0x64, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x5f, 0x68, - 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x63, 0x61, 0x6c, 0x6c, 0x41, - 0x6e, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x48, 0x61, 0x73, 0x68, - 0x12, 0x29, 0x0a, 0x10, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x64, 0x69, 0x73, 0x70, - 0x61, 0x74, 0x63, 0x68, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x13, 0x64, - 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x5f, - 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, - 0x6f, 0x72, 0x65, 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x64, 0x22, 0x26, 0x0a, 0x0a, 0x44, - 0x6f, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, - 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, - 0x65, 0x6e, 0x74, 0x22, 0x8e, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x3a, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x69, 0x6d, 0x70, 0x6c, 0x2e, 0x76, 0x31, - 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, - 0x6b, 0x69, 0x6e, 0x64, 0x22, 0x3e, 0x0a, 0x0c, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, - 0x4b, 0x49, 0x4e, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x45, 0x4c, 0x41, 0x54, 0x49, - 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, - 0x4f, 0x4e, 0x10, 0x02, 0x22, 0x59, 0x0a, 0x14, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x41, 0x6e, 0x64, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, - 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x22, - 0x54, 0x0a, 0x10, 0x56, 0x31, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x52, 0x65, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x0c, 0x6e, 0x73, 0x5f, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x69, 0x6d, 0x70, 0x6c, - 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x41, 0x6e, 0x64, - 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x6e, 0x73, 0x52, 0x65, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x8a, 0x01, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x2e, 0x69, 0x6d, - 0x70, 0x6c, 0x2e, 0x76, 0x31, 0x42, 0x09, 0x49, 0x6d, 0x70, 0x6c, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x50, 0x01, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, - 0x75, 0x74, 0x68, 0x7a, 0x65, 0x64, 0x2f, 0x73, 0x70, 0x69, 0x63, 0x65, 0x64, 0x62, 0x2f, 0x70, - 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x69, 0x6d, 0x70, 0x6c, 0x2f, 0x76, 0x31, - 0x3b, 0x69, 0x6d, 0x70, 0x6c, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x49, 0x58, 0x58, 0xaa, 0x02, 0x07, - 0x49, 0x6d, 0x70, 0x6c, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x07, 0x49, 0x6d, 0x70, 0x6c, 0x5c, 0x56, - 0x31, 0xe2, 0x02, 0x13, 0x49, 0x6d, 0x70, 0x6c, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x08, 0x49, 0x6d, 0x70, 0x6c, 0x3a, 0x3a, - 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x64, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, + 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, + 0x64, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x42, 0x0f, 0x0a, 0x0d, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x5f, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x22, 0x45, 0x0a, 0x0d, 0x44, 0x65, 0x63, 0x6f, + 0x64, 0x65, 0x64, 0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x12, 0x23, 0x0a, 0x02, 0x76, 0x31, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x69, 0x6d, 0x70, 0x6c, 0x2e, 0x76, 0x31, 0x2e, + 0x56, 0x31, 0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x48, 0x00, 0x52, 0x02, 0x76, 0x31, 0x42, 0x0f, + 0x0a, 0x0d, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x22, + 0xd6, 0x01, 0x0a, 0x08, 0x56, 0x31, 0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, + 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x37, 0x0a, 0x18, 0x63, 0x61, 0x6c, 0x6c, 0x5f, 0x61, 0x6e, 0x64, + 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x5f, 0x68, 0x61, 0x73, 0x68, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x63, 0x61, 0x6c, 0x6c, 0x41, 0x6e, 0x64, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x48, 0x61, 0x73, 0x68, 0x12, 0x29, 0x0a, + 0x10, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, + 0x68, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x13, 0x64, 0x61, 0x74, 0x61, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, + 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x64, 0x22, 0x26, 0x0a, 0x0a, 0x44, 0x6f, 0x63, 0x43, + 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, + 0x22, 0x8e, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x3a, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x69, 0x6d, 0x70, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, + 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x52, + 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, 0x6b, 0x69, 0x6e, + 0x64, 0x22, 0x3e, 0x0a, 0x0c, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x69, 0x6e, + 0x64, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x4b, 0x49, 0x4e, + 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x45, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, + 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x10, + 0x02, 0x22, 0x59, 0x0a, 0x14, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x41, 0x6e, + 0x64, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x6e, 0x61, 0x6d, + 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0d, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x54, 0x0a, 0x10, + 0x56, 0x31, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x40, 0x0a, 0x0c, 0x6e, 0x73, 0x5f, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x69, 0x6d, 0x70, 0x6c, 0x2e, 0x76, 0x31, + 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x41, 0x6e, 0x64, 0x52, 0x65, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x6e, 0x73, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x42, 0x8a, 0x01, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x2e, 0x69, 0x6d, 0x70, 0x6c, 0x2e, + 0x76, 0x31, 0x42, 0x09, 0x49, 0x6d, 0x70, 0x6c, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, + 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74, 0x68, + 0x7a, 0x65, 0x64, 0x2f, 0x73, 0x70, 0x69, 0x63, 0x65, 0x64, 0x62, 0x2f, 0x70, 0x6b, 0x67, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x69, 0x6d, 0x70, 0x6c, 0x2f, 0x76, 0x31, 0x3b, 0x69, 0x6d, + 0x70, 0x6c, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x49, 0x58, 0x58, 0xaa, 0x02, 0x07, 0x49, 0x6d, 0x70, + 0x6c, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x07, 0x49, 0x6d, 0x70, 0x6c, 0x5c, 0x56, 0x31, 0xe2, 0x02, + 0x13, 0x49, 0x6d, 0x70, 0x6c, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x08, 0x49, 0x6d, 0x70, 0x6c, 0x3a, 0x3a, 0x56, 0x31, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/pkg/proto/impl/v1/impl.pb.validate.go b/pkg/proto/impl/v1/impl.pb.validate.go index d46c680943..afe61ac194 100644 --- a/pkg/proto/impl/v1/impl.pb.validate.go +++ b/pkg/proto/impl/v1/impl.pb.validate.go @@ -1591,7 +1591,7 @@ func (m *DecodedZedToken_V1ZedToken) validate(all bool) error { // no validation rules for Revision - // no validation rules for DatastoreUniqueId + // no validation rules for DatastoreUniqueIdPrefix if len(errors) > 0 { return DecodedZedToken_V1ZedTokenMultiError(errors) diff --git a/pkg/proto/impl/v1/impl_vtproto.pb.go b/pkg/proto/impl/v1/impl_vtproto.pb.go index e39a6cddaa..abd647dcc7 100644 --- a/pkg/proto/impl/v1/impl_vtproto.pb.go +++ b/pkg/proto/impl/v1/impl_vtproto.pb.go @@ -154,7 +154,7 @@ func (m *DecodedZedToken_V1ZedToken) CloneVT() *DecodedZedToken_V1ZedToken { } r := new(DecodedZedToken_V1ZedToken) r.Revision = m.Revision - r.DatastoreUniqueId = m.DatastoreUniqueId + r.DatastoreUniqueIdPrefix = m.DatastoreUniqueIdPrefix if len(m.unknownFields) > 0 { r.unknownFields = make([]byte, len(m.unknownFields)) copy(r.unknownFields, m.unknownFields) @@ -544,7 +544,7 @@ func (this *DecodedZedToken_V1ZedToken) EqualVT(that *DecodedZedToken_V1ZedToken if this.Revision != that.Revision { return false } - if this.DatastoreUniqueId != that.DatastoreUniqueId { + if this.DatastoreUniqueIdPrefix != that.DatastoreUniqueIdPrefix { return false } return string(this.unknownFields) == string(that.unknownFields) @@ -1129,10 +1129,10 @@ func (m *DecodedZedToken_V1ZedToken) MarshalToSizedBufferVT(dAtA []byte) (int, e i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } - if len(m.DatastoreUniqueId) > 0 { - i -= len(m.DatastoreUniqueId) - copy(dAtA[i:], m.DatastoreUniqueId) - i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DatastoreUniqueId))) + if len(m.DatastoreUniqueIdPrefix) > 0 { + i -= len(m.DatastoreUniqueIdPrefix) + copy(dAtA[i:], m.DatastoreUniqueIdPrefix) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DatastoreUniqueIdPrefix))) i-- dAtA[i] = 0x12 } @@ -1650,7 +1650,7 @@ func (m *DecodedZedToken_V1ZedToken) SizeVT() (n int) { if l > 0 { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } - l = len(m.DatastoreUniqueId) + l = len(m.DatastoreUniqueIdPrefix) if l > 0 { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } @@ -2390,7 +2390,7 @@ func (m *DecodedZedToken_V1ZedToken) UnmarshalVT(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DatastoreUniqueId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field DatastoreUniqueIdPrefix", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2418,7 +2418,7 @@ func (m *DecodedZedToken_V1ZedToken) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.DatastoreUniqueId = string(dAtA[iNdEx:postIndex]) + m.DatastoreUniqueIdPrefix = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex diff --git a/pkg/zedtoken/zedtoken.go b/pkg/zedtoken/zedtoken.go index f655b74565..9eb1927e5a 100644 --- a/pkg/zedtoken/zedtoken.go +++ b/pkg/zedtoken/zedtoken.go @@ -42,10 +42,12 @@ const ( // StatusMismatchedDatastoreID indicates that the zedtoken is valid, but the // datastore ID does not match the current datastore, indicating that the - // token was generated by a different datastore. + // token was generated by a different datastore instance. StatusMismatchedDatastoreID ) +const uniqueIDPrefixLength = 8 + // MustNewFromRevisionForTesting generates an encoded zedtoken from an integral revision. func MustNewFromRevisionForTesting(revision datastore.Revision) *v1.ZedToken { encoded, err := newFromRevision(revision, legacyEmptyDatastoreID) @@ -66,11 +68,16 @@ func NewFromRevision(ctx context.Context, revision datastore.Revision, ds datast } func newFromRevision(revision datastore.Revision, datastoreUniqueID string) (*v1.ZedToken, error) { + datastoreUniqueIDPrefix := datastoreUniqueID + if len(datastoreUniqueIDPrefix) > uniqueIDPrefixLength { + datastoreUniqueIDPrefix = datastoreUniqueIDPrefix[0:uniqueIDPrefixLength] + } + toEncode := &zedtoken.DecodedZedToken{ VersionOneof: &zedtoken.DecodedZedToken_V1{ V1: &zedtoken.DecodedZedToken_V1ZedToken{ - Revision: revision.String(), - DatastoreUniqueId: datastoreUniqueID, + Revision: revision.String(), + DatastoreUniqueIdPrefix: datastoreUniqueIDPrefix, }, }, } @@ -132,7 +139,7 @@ func DecodeRevision(encoded *v1.ZedToken, ds revisionDecoder) (datastore.Revisio return datastore.NoRevision, StatusUnknown, fmt.Errorf(errDecodeError, err) } - if ver.V1.DatastoreUniqueId == legacyEmptyDatastoreID { + if ver.V1.DatastoreUniqueIdPrefix == legacyEmptyDatastoreID { return parsed, StatusLegacyEmptyDatastoreID, nil } @@ -141,7 +148,12 @@ func DecodeRevision(encoded *v1.ZedToken, ds revisionDecoder) (datastore.Revisio return datastore.NoRevision, StatusUnknown, fmt.Errorf(errDecodeError, err) } - if ver.V1.DatastoreUniqueId != datastoreUniqueID { + datastoreUniqueIDPrefix := datastoreUniqueID + if len(datastoreUniqueIDPrefix) > uniqueIDPrefixLength { + datastoreUniqueIDPrefix = datastoreUniqueIDPrefix[0:uniqueIDPrefixLength] + } + + if ver.V1.DatastoreUniqueIdPrefix != datastoreUniqueIDPrefix { return parsed, StatusMismatchedDatastoreID, nil } diff --git a/pkg/zedtoken/zedtoken_test.go b/pkg/zedtoken/zedtoken_test.go index 85df77aa4d..fc32e079f3 100644 --- a/pkg/zedtoken/zedtoken_test.go +++ b/pkg/zedtoken/zedtoken_test.go @@ -141,7 +141,7 @@ var decodeTests = []struct { }, { format: "V1 ZedToken with matching datastore unique ID", - token: "GhIKAjQyEgxzb21ldW5pcXVlaWQ=", + token: "Gg4KAjQyEghzb21ldW5pcQ==", datastoreUniqueID: "someuniqueid", expectedRevision: revisions.NewForTransactionID(42), expectedStatus: StatusValid, @@ -149,7 +149,7 @@ var decodeTests = []struct { }, { format: "V1 ZedToken with mismatched datastore unique ID", - token: "GhIKAjQyEgxzb21ldW5pcXVlaWQ=", + token: "Gg4KAjQyEghzb21ldW5pcQ==", datastoreUniqueID: "anotheruniqueid", expectedRevision: revisions.NewForTransactionID(42), expectedStatus: StatusMismatchedDatastoreID, @@ -225,7 +225,7 @@ var hlcDecodeTests = []struct { }, { format: "V1 ZedToken with matching datastore unique ID", - token: "GkYKHjE2OTM1NDA5NDAzNzMwNDU3MjcuMDAwMDAwMDAwMRIkNjM0OWFhZjItMzdjZC00N2I5LTg0ZTgtZmU1ZmE2ZTJkZWFk", + token: "GioKHjE2OTM1NDA5NDAzNzMwNDU3MjcuMDAwMDAwMDAwMRIINjM0OWFhZjI=", datastoreUniqueID: "6349aaf2-37cd-47b9-84e8-fe5fa6e2dead", expectedStatus: StatusValid, expectedRevision: (func() datastore.Revision { @@ -243,7 +243,7 @@ var hlcDecodeTests = []struct { }, { format: "V1 ZedToken with mismatched datastore unique ID", - token: "GkYKHjE2OTM1NDA5NDAzNzMwNDU3MjcuMDAwMDAwMDAwMRIkNjM0OWFhZjItMzdjZC00N2I5LTg0ZTgtZmU1ZmE2ZTJkZWFk", + token: "GioKHjE2OTM1NDA5NDAzNzMwNDU3MjcuMDAwMDAwMDAwMRIINjM0OWFhZjI=", datastoreUniqueID: "arrrg-6349aaf2-37cd-47b9-84e8-fe5fa6e2dead", expectedStatus: StatusMismatchedDatastoreID, expectedRevision: (func() datastore.Revision { diff --git a/proto/internal/impl/v1/impl.proto b/proto/internal/impl/v1/impl.proto index 0e3f1356e6..77f45ed4d4 100644 --- a/proto/internal/impl/v1/impl.proto +++ b/proto/internal/impl/v1/impl.proto @@ -34,9 +34,9 @@ message DecodedZedToken { message V1ZedToken { string revision = 1; - // datastore_unique_id is the unique ID for the datastore. Will be empty for legacy - // tokens. - string datastore_unique_id = 2; + // datastore_unique_id_prefix is a prefix of the unique ID for the datastore that created + // this token. Will be empty for legacy tokens. + string datastore_unique_id_prefix = 2; } oneof version_oneof { V1Zookie deprecated_v1_zookie = 2;