Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Schema: reads inside write transactions now use a cheap hash-only lookup (`schema_revision`) to check the cache before loading the full schema blob, reducing DB round-trips on cache hits (https://github.com/authzed/spicedb/pull/3160)
- Updated the Prometheus buckets for `grpc_server_handling_seconds` and `spicedb_datastore_query_latency` to be able to correlate them (https://github.com/authzed/spicedb/pull/3188)
- Use `testcontainers` instead of `ory/dockertest` for running containers in integration tests (https://github.com/authzed/spicedb/pull/2782)
- The unified schema storage migration is now driven by the standard `--datastore-migration-phase` flag instead of the bespoke `--experimental-schema-mode` flag, which has been removed. The phase values are unchanged (`read-legacy-write-legacy` (default when unset), `read-legacy-write-both`, `read-new-write-both`, `read-new-write-new`).

### Fixed
- Fixed a nil pointer dereference panic in `CheckBulkPermissions` that could occur under concurrent load when a tracing-enabled check shared a singleflight dispatch with a non-tracing bulk check. Debug-enabled checks are no longer singleflighted together with non-debug checks. (https://github.com/authzed/spicedb/pull/3174)
Expand Down
7 changes: 3 additions & 4 deletions docs/spicedb.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 12 additions & 12 deletions internal/datastore/postgres/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,18 @@ type postgresOptions struct {
queryInterceptor pgxcommon.QueryInterceptor
}

type migrationPhase uint8

const (
writeBothReadOld migrationPhase = iota
writeBothReadNew
complete
)

var migrationPhases = map[string]migrationPhase{
"write-both-read-old": writeBothReadOld,
"write-both-read-new": writeBothReadNew,
"": complete,
// migrationPhases enumerates the values accepted by the
// --datastore-migration-phase flag. They mirror the unified schema storage
// migration phases parsed by datalayer.ParseSchemaMode (the canonical source
// of these strings). The datastore driver itself takes no action on the phase
// beyond logging it; the active read/write behavior lives in the data layer.
// An empty phase is the steady-state (legacy) default.
var migrationPhases = map[string]struct{}{
"": {},
"read-legacy-write-legacy": {},
"read-legacy-write-both": {},
"read-new-write-both": {},
"read-new-write-new": {},
}

const (
Expand Down
20 changes: 12 additions & 8 deletions internal/datastore/spanner/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,18 @@ type spannerOptions struct {
datastoreMetricsOption DatastoreMetricsOption
}

type migrationPhase uint8

const (
complete migrationPhase = iota
)

var migrationPhases = map[string]migrationPhase{
"": complete,
// migrationPhases enumerates the values accepted by the
// --datastore-migration-phase flag. They mirror the unified schema storage
// migration phases parsed by datalayer.ParseSchemaMode (the canonical source
// of these strings). The datastore driver itself takes no action on the phase
// beyond logging it; the active read/write behavior lives in the data layer.
// An empty phase is the steady-state (legacy) default.
var migrationPhases = map[string]struct{}{
"": {},
"read-legacy-write-legacy": {},
"read-legacy-write-both": {},
"read-new-write-both": {},
"read-new-write-new": {},
}

const (
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/datastore/datastore.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ func RegisterDatastoreFlagsWithPrefix(flagSet *pflag.FlagSet, prefix string, opt
}
flagSet.StringVar(&opts.SpannerDatastoreMetricsOption, flagName("datastore-spanner-metrics"), "otel", `configure the metrics that are emitted by the Spanner datastore ("none", "native", "otel")`)
flagSet.StringVar(&opts.TablePrefix, flagName("datastore-mysql-table-prefix"), "", "prefix to add to the name of all SpiceDB database tables")
flagSet.StringVar(&opts.MigrationPhase, flagName("datastore-migration-phase"), "", "datastore-specific flag that should be used to signal to a datastore which phase of a multi-step migration it is in")
flagSet.StringVar(&opts.MigrationPhase, flagName("datastore-migration-phase"), "", "datastore-specific flag that should be used to signal to a datastore which phase of a multi-step migration it is in. For the unified schema storage migration, the supported phases are: read-legacy-write-legacy (default), read-legacy-write-both, read-new-write-both, read-new-write-new")
flagSet.StringArrayVar(&opts.AllowedMigrations, flagName("datastore-allowed-migrations"), []string{}, "migration levels that will not fail the health check (in addition to the current head migration)")
flagSet.Uint16Var(&opts.WatchBufferLength, flagName("datastore-watch-buffer-length"), 1024, "how large the watch buffer should be before blocking")
flagSet.StringVar(&opts.WatchChangeBufferMaximumSize, flagName("datastore-watch-change-buffer-maximum-size"), "15%", "how much memory to reserve for the watch change buffer, either as a quantity of bytes (e.g. 5Gi) or a percentage of available memory (e.g. 50%). if this value is exceeded, the watch will error and must be restarted.")
Expand Down
1 change: 0 additions & 1 deletion pkg/cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,6 @@ func RegisterServeFlags(cmd *cobra.Command, config *server.Config) error {
return fmt.Errorf("failed to mark flag as deprecated: %w", err)
}
experimentalFlags.BoolVar(&config.EnableExperimentalWatchableSchemaCache, "enable-experimental-watchable-schema-cache", false, "enables the experimental schema cache, which uses the Watch API to keep the schema up to date")
experimentalFlags.StringVar(&config.ExperimentalSchemaMode, "experimental-schema-mode", "read-legacy-write-legacy", "schema storage mode for migration to unified schema: read-legacy-write-legacy, read-legacy-write-both, read-new-write-both, read-new-write-new")
// TODO: these two could reasonably be put in either the Dispatch group or the Experimental group. Is there a preference?
experimentalFlags.StringToStringVar(&config.DispatchSecondaryUpstreamAddrs, "experimental-dispatch-secondary-upstream-addrs", nil, "secondary upstream addresses for dispatches, each with a name")
experimentalFlags.StringToStringVar(&config.DispatchSecondaryUpstreamExprs, "experimental-dispatch-secondary-upstream-exprs", nil, "map from request type to its associated CEL expression, which returns the secondary upstream(s) to be used for the request")
Expand Down
11 changes: 6 additions & 5 deletions pkg/cmd/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,7 @@
StoredSchemaCacheConfig CacheConfig `debugmap:"visible"`

// Schema options
SchemaPrefixesRequired bool `debugmap:"visible"`
ExperimentalSchemaMode string `debugmap:"visible" default:"read-legacy-write-legacy"`
SchemaPrefixesRequired bool `debugmap:"visible"`

// Dispatch options
DispatchServer util.GRPCServerConfig `debugmap:"visible"`
Expand Down Expand Up @@ -266,12 +265,14 @@
log.Ctx(ctx).Info().EmbedObject(storedSchemaCache).Msg("configured stored schema cache")
closeables.AddWithoutError(storedSchemaCache.Close)

// Parse schema mode early so proxy setup can depend on it.
// Parse schema mode early so proxy setup can depend on it. The phase of the
// unified-schema migration is driven by the standard --datastore-migration-phase
// flag; an empty phase keeps the backward-compatible legacy read/write behavior.
var dlOpts []datalayer.DataLayerOption
dlOpts = append(dlOpts, datalayer.WithSchemaCache(storedSchemaCache))
schemaMode := datalayer.SchemaModeReadLegacyWriteLegacy
if c.ExperimentalSchemaMode != "" {
schemaMode, err = datalayer.ParseSchemaMode(c.ExperimentalSchemaMode)
if c.DatastoreConfig.MigrationPhase != "" {
schemaMode, err = datalayer.ParseSchemaMode(c.DatastoreConfig.MigrationPhase)

Check warning on line 275 in pkg/cmd/server/server.go

View check run for this annotation

Codecov / codecov/patch

pkg/cmd/server/server.go#L275

Added line #L275 was not covered by tests
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/server/server_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package server

import (
Expand Down Expand Up @@ -85,7 +85,7 @@
require.Equal(t, 4096, cfg.MaxCaveatContextSize)
require.Equal(t, 25_000, cfg.MaxRelationshipContextSize)
require.Equal(t, time.Second, cfg.SchemaWatchHeartbeat)
require.Equal(t, "read-legacy-write-legacy", cfg.ExperimentalSchemaMode)
require.Equal(t, "", cfg.DatastoreConfig.MigrationPhase)

require.Equal(t, uint32(50), cfg.DispatchMaxDepth)
require.Equal(t, uint16(50), cfg.GlobalDispatchConcurrencyLimit)
Expand Down
13 changes: 0 additions & 13 deletions pkg/cmd/server/zz_generated.options.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading