From d98d7d296bd4100be0956fd610fcbca1b96a9fd9 Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Fri, 22 Nov 2024 18:21:08 +0000 Subject: [PATCH] Move column elision behind an experimental flag --- internal/datastore/common/relationships.go | 10 ++++-- internal/datastore/common/sql.go | 36 ++++++++++++++----- internal/datastore/common/sql_test.go | 2 ++ internal/datastore/crdb/crdb.go | 1 + internal/datastore/crdb/options.go | 15 ++++++++ .../datastore/dsfortesting/dsfortesting.go | 1 + internal/datastore/mysql/datastore.go | 1 + internal/datastore/mysql/options.go | 15 ++++++++ internal/datastore/postgres/options.go | 23 +++++++++--- internal/datastore/postgres/postgres.go | 1 + internal/datastore/spanner/options.go | 16 +++++++++ internal/datastore/spanner/reader.go | 24 +++---------- internal/datastore/spanner/spanner.go | 19 ++++++++-- pkg/cmd/datastore/datastore.go | 10 ++++++ pkg/cmd/datastore/zz_generated.options.go | 9 +++++ 15 files changed, 147 insertions(+), 36 deletions(-) diff --git a/internal/datastore/common/relationships.go b/internal/datastore/common/relationships.go index 603b86ea9d..56370aa8ef 100644 --- a/internal/datastore/common/relationships.go +++ b/internal/datastore/common/relationships.go @@ -20,6 +20,12 @@ const errUnableToQueryRels = "unable to query relationships: %w" // StaticValueOrAddColumnForSelect adds a column to the list of columns to select if the value // is not static, otherwise it sets the value to the static value. func StaticValueOrAddColumnForSelect(colsToSelect []any, queryInfo QueryInfo, colName string, field *string) []any { + if queryInfo.Schema.ColumnOptimization == ColumnOptimizationOptionNone { + // If column optimization is disabled, always add the column to the list of columns to select. + colsToSelect = append(colsToSelect, field) + return colsToSelect + } + // If the value is static, set the field to it and return. if found, ok := queryInfo.FilteringValues[colName]; ok && found.SingleValue != nil { *field = *found.SingleValue @@ -78,7 +84,7 @@ func QueryRelationships[R Rows, C ~map[string]any](ctx context.Context, queryInf colsToSelect = StaticValueOrAddColumnForSelect(colsToSelect, queryInfo, queryInfo.Schema.ColUsersetObjectID, &subjectObjectID) colsToSelect = StaticValueOrAddColumnForSelect(colsToSelect, queryInfo, queryInfo.Schema.ColUsersetRelation, &subjectRelation) - if !queryInfo.SkipCaveats { + if !queryInfo.SkipCaveats || queryInfo.Schema.ColumnOptimization == ColumnOptimizationOptionNone { colsToSelect = append(colsToSelect, &caveatName, &caveatCtx) } @@ -108,7 +114,7 @@ func QueryRelationships[R Rows, C ~map[string]any](ctx context.Context, queryInf } var caveat *corev1.ContextualizedCaveat - if !queryInfo.SkipCaveats { + if !queryInfo.SkipCaveats || queryInfo.Schema.ColumnOptimization == ColumnOptimizationOptionNone { if caveatName.Valid { var err error caveat, err = ContextualizedCaveatFrom(caveatName.String, caveatCtx) diff --git a/internal/datastore/common/sql.go b/internal/datastore/common/sql.go index e1fb34e167..0c6b83ad22 100644 --- a/internal/datastore/common/sql.go +++ b/internal/datastore/common/sql.go @@ -47,7 +47,7 @@ var ( tracer = otel.Tracer("spicedb/internal/datastore/common") ) -// PaginationFilterType is an enumerator +// PaginationFilterType is an enumerator for pagination filter types. type PaginationFilterType uint8 const ( @@ -62,6 +62,17 @@ const ( ExpandedLogicComparison ) +// ColumnOptimizationOption is an enumerator for column optimization options. +type ColumnOptimizationOption int + +const ( + // ColumnOptimizationOptionNone is the default option, which does not optimize the static columns. + ColumnOptimizationOptionNone ColumnOptimizationOption = iota + + // ColumnOptimizationOptionStaticValue is an option that optimizes the column for a static value. + ColumnOptimizationOptionStaticValues +) + // SchemaInformation holds the schema information from the SQL datastore implementation. type SchemaInformation struct { RelationshipTableName string @@ -75,6 +86,7 @@ type SchemaInformation struct { ColCaveatContext string PaginationFilterType PaginationFilterType PlaceholderFormat sq.PlaceholderFormat + ColumnOptimization ColumnOptimizationOption // ExtaFields are additional fields that are not part of the core schema, but are // requested by the caller for this query. @@ -94,6 +106,7 @@ func NewSchemaInformation( colCaveatContext string, paginationFilterType PaginationFilterType, placeholderFormat sq.PlaceholderFormat, + columnOptionizationOption ColumnOptimizationOption, extraFields ...string, ) SchemaInformation { return SchemaInformation{ @@ -108,6 +121,7 @@ func NewSchemaInformation( colCaveatContext, paginationFilterType, placeholderFormat, + columnOptionizationOption, extraFields, } } @@ -663,14 +677,14 @@ func (tqs QueryExecutor) ExecuteQuery( // Set the column names to select. columnNamesToSelect := make([]string, 0, 8+len(query.extraFields)) - columnNamesToSelect = checkColumn(columnNamesToSelect, query.filteringColumnTracker, query.schema.ColNamespace) - columnNamesToSelect = checkColumn(columnNamesToSelect, query.filteringColumnTracker, query.schema.ColObjectID) - columnNamesToSelect = checkColumn(columnNamesToSelect, query.filteringColumnTracker, query.schema.ColRelation) - columnNamesToSelect = checkColumn(columnNamesToSelect, query.filteringColumnTracker, query.schema.ColUsersetNamespace) - columnNamesToSelect = checkColumn(columnNamesToSelect, query.filteringColumnTracker, query.schema.ColUsersetObjectID) - columnNamesToSelect = checkColumn(columnNamesToSelect, query.filteringColumnTracker, query.schema.ColUsersetRelation) + columnNamesToSelect = checkColumn(columnNamesToSelect, query.schema.ColumnOptimization, query.filteringColumnTracker, query.schema.ColNamespace) + columnNamesToSelect = checkColumn(columnNamesToSelect, query.schema.ColumnOptimization, query.filteringColumnTracker, query.schema.ColObjectID) + columnNamesToSelect = checkColumn(columnNamesToSelect, query.schema.ColumnOptimization, query.filteringColumnTracker, query.schema.ColRelation) + columnNamesToSelect = checkColumn(columnNamesToSelect, query.schema.ColumnOptimization, query.filteringColumnTracker, query.schema.ColUsersetNamespace) + columnNamesToSelect = checkColumn(columnNamesToSelect, query.schema.ColumnOptimization, query.filteringColumnTracker, query.schema.ColUsersetObjectID) + columnNamesToSelect = checkColumn(columnNamesToSelect, query.schema.ColumnOptimization, query.filteringColumnTracker, query.schema.ColUsersetRelation) - if !queryOpts.SkipCaveats { + if !queryOpts.SkipCaveats || query.schema.ColumnOptimization == ColumnOptimizationOptionNone { columnNamesToSelect = append(columnNamesToSelect, query.schema.ColCaveatName, query.schema.ColCaveatContext) } @@ -698,7 +712,11 @@ func (tqs QueryExecutor) ExecuteQuery( return tqs.Executor(ctx, QueryInfo{query.schema, query.filteringColumnTracker, queryOpts.SkipCaveats, selectingNoColumns}, sql, args) } -func checkColumn(columns []string, tracker map[string]ColumnTracker, colName string) []string { +func checkColumn(columns []string, option ColumnOptimizationOption, tracker map[string]ColumnTracker, colName string) []string { + if option == ColumnOptimizationOptionNone { + return append(columns, colName) + } + if r, ok := tracker[colName]; !ok || r.SingleValue == nil { return append(columns, colName) } diff --git a/internal/datastore/common/sql_test.go b/internal/datastore/common/sql_test.go index 747178da6d..b09c164b7c 100644 --- a/internal/datastore/common/sql_test.go +++ b/internal/datastore/common/sql_test.go @@ -570,6 +570,7 @@ func TestSchemaQueryFilterer(t *testing.T) { "caveat_context", TupleComparison, sq.Question, + ColumnOptimizationOptionStaticValues, ) filterer := NewSchemaQueryFiltererForRelationshipsSelect(schema, 100) @@ -829,6 +830,7 @@ func TestExecuteQuery(t *testing.T) { "caveat_context", TupleComparison, sq.Question, + ColumnOptimizationOptionStaticValues, ) filterer := NewSchemaQueryFiltererForRelationshipsSelect(schema, 100) ran := tc.run(filterer) diff --git a/internal/datastore/crdb/crdb.go b/internal/datastore/crdb/crdb.go index 65c576a5b6..e9b36cb12d 100644 --- a/internal/datastore/crdb/crdb.go +++ b/internal/datastore/crdb/crdb.go @@ -219,6 +219,7 @@ func newCRDBDatastore(ctx context.Context, url string, options ...Option) (datas colCaveatContext, common.ExpandedLogicComparison, sq.Dollar, + config.columnOptimizationOption, extraFields..., ) diff --git a/internal/datastore/crdb/options.go b/internal/datastore/crdb/options.go index db0fab7f7a..7424463246 100644 --- a/internal/datastore/crdb/options.go +++ b/internal/datastore/crdb/options.go @@ -4,6 +4,7 @@ import ( "fmt" "time" + "github.com/authzed/spicedb/internal/datastore/common" pgxcommon "github.com/authzed/spicedb/internal/datastore/postgres/common" log "github.com/authzed/spicedb/internal/logging" ) @@ -28,6 +29,7 @@ type crdbOptions struct { enablePrometheusStats bool withIntegrity bool allowedMigrations []string + columnOptimizationOption common.ColumnOptimizationOption } const ( @@ -55,6 +57,7 @@ const ( defaultConnectRate = 100 * time.Millisecond defaultFilterMaximumIDCount = 100 defaultWithIntegrity = false + defaultColumnOptimizationOption = common.ColumnOptimizationOptionNone ) // Option provides the facility to configure how clients within the CRDB @@ -78,6 +81,7 @@ func generateConfig(options []Option) (crdbOptions, error) { connectRate: defaultConnectRate, filterMaximumIDCount: defaultFilterMaximumIDCount, withIntegrity: defaultWithIntegrity, + columnOptimizationOption: defaultColumnOptimizationOption, } for _, option := range options { @@ -345,3 +349,14 @@ func WithIntegrity(withIntegrity bool) Option { func AllowedMigrations(allowedMigrations []string) Option { return func(po *crdbOptions) { po.allowedMigrations = allowedMigrations } } + +// WithColumnOptimization configures the column optimization option for the datastore. +func WithColumnOptimization(isEnabled bool) Option { + return func(po *crdbOptions) { + if isEnabled { + po.columnOptimizationOption = common.ColumnOptimizationOptionStaticValues + } else { + po.columnOptimizationOption = common.ColumnOptimizationOptionNone + } + } +} diff --git a/internal/datastore/dsfortesting/dsfortesting.go b/internal/datastore/dsfortesting/dsfortesting.go index 42fad1209a..aac31b2700 100644 --- a/internal/datastore/dsfortesting/dsfortesting.go +++ b/internal/datastore/dsfortesting/dsfortesting.go @@ -61,6 +61,7 @@ func (vr validatingReader) QueryRelationships( "caveat_context", common.TupleComparison, sq.Question, + common.ColumnOptimizationOptionStaticValues, ) qBuilder, err := common.NewSchemaQueryFiltererForRelationshipsSelect(schema, 100). diff --git a/internal/datastore/mysql/datastore.go b/internal/datastore/mysql/datastore.go index b11ef6fcb7..d1494c95fc 100644 --- a/internal/datastore/mysql/datastore.go +++ b/internal/datastore/mysql/datastore.go @@ -255,6 +255,7 @@ func newMySQLDatastore(ctx context.Context, uri string, replicaIndex int, option colCaveatContext, common.ExpandedLogicComparison, sq.Question, + config.columnOptimizationOption, ) store := &Datastore{ diff --git a/internal/datastore/mysql/options.go b/internal/datastore/mysql/options.go index 4a48e44fad..713e97e671 100644 --- a/internal/datastore/mysql/options.go +++ b/internal/datastore/mysql/options.go @@ -4,6 +4,7 @@ import ( "fmt" "time" + "github.com/authzed/spicedb/internal/datastore/common" log "github.com/authzed/spicedb/internal/logging" ) @@ -25,6 +26,7 @@ const ( defaultGCEnabled = true defaultCredentialsProviderName = "" defaultFilterMaximumIDCount = 100 + defaultColumnOptimizationOption = common.ColumnOptimizationOptionNone ) type mysqlOptions struct { @@ -47,6 +49,7 @@ type mysqlOptions struct { credentialsProviderName string filterMaximumIDCount uint16 allowedMigrations []string + columnOptimizationOption common.ColumnOptimizationOption } // Option provides the facility to configure how clients within the @@ -70,6 +73,7 @@ func generateConfig(options []Option) (mysqlOptions, error) { gcEnabled: defaultGCEnabled, credentialsProviderName: defaultCredentialsProviderName, filterMaximumIDCount: defaultFilterMaximumIDCount, + columnOptimizationOption: defaultColumnOptimizationOption, } for _, option := range options { @@ -269,3 +273,14 @@ func FilterMaximumIDCount(filterMaximumIDCount uint16) Option { func AllowedMigrations(allowedMigrations []string) Option { return func(mo *mysqlOptions) { mo.allowedMigrations = allowedMigrations } } + +// WithColumnOptimization configures the column optimization strategy for the MySQL datastore. +func WithColumnOptimization(isEnabled bool) Option { + return func(mo *mysqlOptions) { + if isEnabled { + mo.columnOptimizationOption = common.ColumnOptimizationOptionStaticValues + } else { + mo.columnOptimizationOption = common.ColumnOptimizationOptionNone + } + } +} diff --git a/internal/datastore/postgres/options.go b/internal/datastore/postgres/options.go index d3a9b1f8de..f0cef1bd0f 100644 --- a/internal/datastore/postgres/options.go +++ b/internal/datastore/postgres/options.go @@ -4,6 +4,7 @@ import ( "fmt" "time" + "github.com/authzed/spicedb/internal/datastore/common" pgxcommon "github.com/authzed/spicedb/internal/datastore/postgres/common" log "github.com/authzed/spicedb/internal/logging" ) @@ -24,10 +25,11 @@ type postgresOptions struct { maxRetries uint8 filterMaximumIDCount uint16 - enablePrometheusStats bool - analyzeBeforeStatistics bool - gcEnabled bool - readStrictMode bool + enablePrometheusStats bool + analyzeBeforeStatistics bool + gcEnabled bool + readStrictMode bool + columnOptimizationOption common.ColumnOptimizationOption migrationPhase string allowedMigrations []string @@ -67,6 +69,7 @@ const ( defaultCredentialsProviderName = "" defaultReadStrictMode = false defaultFilterMaximumIDCount = 100 + defaultColumnOptimizationOption = common.ColumnOptimizationOptionNone ) // Option provides the facility to configure how clients within the @@ -89,6 +92,7 @@ func generateConfig(options []Option) (postgresOptions, error) { readStrictMode: defaultReadStrictMode, queryInterceptor: nil, filterMaximumIDCount: defaultFilterMaximumIDCount, + columnOptimizationOption: defaultColumnOptimizationOption, } for _, option := range options { @@ -377,3 +381,14 @@ func CredentialsProviderName(credentialsProviderName string) Option { func FilterMaximumIDCount(filterMaximumIDCount uint16) Option { return func(po *postgresOptions) { po.filterMaximumIDCount = filterMaximumIDCount } } + +// WithColumnOptimization sets the column optimization option for the datastore. +func WithColumnOptimization(isEnabled bool) Option { + return func(po *postgresOptions) { + if isEnabled { + po.columnOptimizationOption = common.ColumnOptimizationOptionStaticValues + } else { + po.columnOptimizationOption = common.ColumnOptimizationOptionNone + } + } +} diff --git a/internal/datastore/postgres/postgres.go b/internal/datastore/postgres/postgres.go index 0f5a7d02d5..ea07890720 100644 --- a/internal/datastore/postgres/postgres.go +++ b/internal/datastore/postgres/postgres.go @@ -326,6 +326,7 @@ func newPostgresDatastore( colCaveatContext, common.TupleComparison, sq.Dollar, + config.columnOptimizationOption, ) datastore := &pgDatastore{ diff --git a/internal/datastore/spanner/options.go b/internal/datastore/spanner/options.go index 29d9617428..a0ae438a23 100644 --- a/internal/datastore/spanner/options.go +++ b/internal/datastore/spanner/options.go @@ -6,6 +6,7 @@ import ( "runtime" "time" + "github.com/authzed/spicedb/internal/datastore/common" log "github.com/authzed/spicedb/internal/logging" ) @@ -26,6 +27,7 @@ type spannerOptions struct { migrationPhase string allowedMigrations []string filterMaximumIDCount uint16 + columnOptimizationOption common.ColumnOptimizationOption } type migrationPhase uint8 @@ -49,6 +51,7 @@ const ( defaultDisableStats = false maxRevisionQuantization = 24 * time.Hour defaultFilterMaximumIDCount = 100 + defaultColumnOptimizationOption = common.ColumnOptimizationOptionNone ) // Option provides the facility to configure how clients within the Spanner @@ -72,6 +75,7 @@ func generateConfig(options []Option) (spannerOptions, error) { maxSessions: 400, migrationPhase: "", // no migration filterMaximumIDCount: defaultFilterMaximumIDCount, + columnOptimizationOption: defaultColumnOptimizationOption, } for _, option := range options { @@ -224,3 +228,15 @@ func AllowedMigrations(allowedMigrations []string) Option { func FilterMaximumIDCount(filterMaximumIDCount uint16) Option { return func(po *spannerOptions) { po.filterMaximumIDCount = filterMaximumIDCount } } + +// WithColumnOptimization configures the Spanner driver to optimize the columns +// in the underlying tables. +func WithColumnOptimization(isEnabled bool) Option { + return func(po *spannerOptions) { + if isEnabled { + po.columnOptimizationOption = common.ColumnOptimizationOptionStaticValues + } else { + po.columnOptimizationOption = common.ColumnOptimizationOptionNone + } + } +} diff --git a/internal/datastore/spanner/reader.go b/internal/datastore/spanner/reader.go index fd67a099e4..69ba242b24 100644 --- a/internal/datastore/spanner/reader.go +++ b/internal/datastore/spanner/reader.go @@ -7,7 +7,6 @@ import ( "time" "cloud.google.com/go/spanner" - sq "github.com/Masterminds/squirrel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" "google.golang.org/grpc/codes" @@ -35,6 +34,7 @@ type spannerReader struct { executor common.QueryExecutor txSource txFactory filterMaximumIDCount uint16 + schema common.SchemaInformation } func (sr spannerReader) CountRelationships(ctx context.Context, name string) (int, error) { @@ -55,7 +55,7 @@ func (sr spannerReader) CountRelationships(ctx context.Context, name string) (in return 0, err } - builder, err := common.NewSchemaQueryFiltererWithStartingQuery(schema, countRels, sr.filterMaximumIDCount).FilterWithRelationshipsFilter(relFilter) + builder, err := common.NewSchemaQueryFiltererWithStartingQuery(sr.schema, countRels, sr.filterMaximumIDCount).FilterWithRelationshipsFilter(relFilter) if err != nil { return 0, err } @@ -135,7 +135,7 @@ func (sr spannerReader) QueryRelationships( filter datastore.RelationshipsFilter, opts ...options.QueryOptionsOption, ) (iter datastore.RelationshipIterator, err error) { - qBuilder, err := common.NewSchemaQueryFiltererForRelationshipsSelect(schema, sr.filterMaximumIDCount).FilterWithRelationshipsFilter(filter) + qBuilder, err := common.NewSchemaQueryFiltererForRelationshipsSelect(sr.schema, sr.filterMaximumIDCount).FilterWithRelationshipsFilter(filter) if err != nil { return nil, err } @@ -148,7 +148,7 @@ func (sr spannerReader) ReverseQueryRelationships( subjectsFilter datastore.SubjectsFilter, opts ...options.ReverseQueryOptionsOption, ) (iter datastore.RelationshipIterator, err error) { - qBuilder, err := common.NewSchemaQueryFiltererForRelationshipsSelect(schema, sr.filterMaximumIDCount). + qBuilder, err := common.NewSchemaQueryFiltererForRelationshipsSelect(sr.schema, sr.filterMaximumIDCount). FilterWithSubjectsSelectors(subjectsFilter.AsSelector()) if err != nil { return nil, err @@ -204,7 +204,7 @@ func queryExecutor(txSource txFactory) common.ExecuteReadRelsQueryFunc { colsToSelect = common.StaticValueOrAddColumnForSelect(colsToSelect, queryInfo, queryInfo.Schema.ColUsersetObjectID, &subjectObjectID) colsToSelect = common.StaticValueOrAddColumnForSelect(colsToSelect, queryInfo, queryInfo.Schema.ColUsersetRelation, &subjectRelation) - if !queryInfo.SkipCaveats { + if !queryInfo.SkipCaveats || queryInfo.Schema.ColumnOptimization == common.ColumnOptimizationOptionNone { colsToSelect = append(colsToSelect, &caveatName, &caveatCtx) } @@ -368,18 +368,4 @@ var queryTuplesForDelete = sql.Select( colUsersetRelation, ).From(tableRelationship) -var schema = common.NewSchemaInformation( - tableRelationship, - colNamespace, - colObjectID, - colRelation, - colUsersetNamespace, - colUsersetObjectID, - colUsersetRelation, - colCaveatName, - colCaveatContext, - common.ExpandedLogicComparison, - sq.AtP, -) - var _ datastore.Reader = spannerReader{} diff --git a/internal/datastore/spanner/spanner.go b/internal/datastore/spanner/spanner.go index 6565b3dc6c..04e5f2734d 100644 --- a/internal/datastore/spanner/spanner.go +++ b/internal/datastore/spanner/spanner.go @@ -88,6 +88,7 @@ type spannerDatastore struct { client *spanner.Client config spannerOptions database string + schema common.SchemaInformation cachedEstimatedBytesPerRelationshipLock sync.RWMutex cachedEstimatedBytesPerRelationship uint64 @@ -196,6 +197,20 @@ func NewSpannerDatastore(ctx context.Context, database string, opts ...Option) ( cachedEstimatedBytesPerRelationshipLock: sync.RWMutex{}, tableSizesStatsTable: tableSizesStatsTable, filterMaximumIDCount: config.filterMaximumIDCount, + schema: common.NewSchemaInformation( + tableRelationship, + colNamespace, + colObjectID, + colRelation, + colUsersetNamespace, + colUsersetObjectID, + colUsersetRelation, + colCaveatName, + colCaveatContext, + common.ExpandedLogicComparison, + sq.AtP, + config.columnOptimizationOption, + ), } // Optimized revision and revision checking use a stale read for the // current timestamp. @@ -244,7 +259,7 @@ func (sd *spannerDatastore) SnapshotReader(revisionRaw datastore.Revision) datas return &traceableRTX{delegate: sd.client.Single().WithTimestampBound(spanner.ReadTimestamp(r.Time()))} } executor := common.QueryExecutor{Executor: queryExecutor(txSource)} - return spannerReader{executor, txSource, sd.filterMaximumIDCount} + return spannerReader{executor, txSource, sd.filterMaximumIDCount, sd.schema} } func (sd *spannerDatastore) readTransactionMetadata(ctx context.Context, transactionTag string) (map[string]any, error) { @@ -293,7 +308,7 @@ func (sd *spannerDatastore) ReadWriteTx(ctx context.Context, fn datastore.TxUser executor := common.QueryExecutor{Executor: queryExecutor(txSource)} rwt := spannerReadWriteTXN{ - spannerReader{executor, txSource, sd.filterMaximumIDCount}, + spannerReader{executor, txSource, sd.filterMaximumIDCount, sd.schema}, spannerRWT, } err := func() error { diff --git a/pkg/cmd/datastore/datastore.go b/pkg/cmd/datastore/datastore.go index e0c23733d1..fb9ec248a6 100644 --- a/pkg/cmd/datastore/datastore.go +++ b/pkg/cmd/datastore/datastore.go @@ -165,6 +165,9 @@ type Config struct { // Migrations MigrationPhase string `debugmap:"visible"` AllowedMigrations []string `debugmap:"visible"` + + // Expermimental + ExperimentalColumnOptimization bool `debugmap:"visible"` } //go:generate go run github.com/ecordell/optgen -sensitive-field-name-matches uri,secure -output zz_generated.relintegritykey.options.go . RelIntegrityKey @@ -269,6 +272,8 @@ func RegisterDatastoreFlagsWithPrefix(flagSet *pflag.FlagSet, prefix string, opt return fmt.Errorf("failed to mark flag as hidden: %w", err) } + flagSet.BoolVar(&opts.ExperimentalColumnOptimization, flagName("datastore-experimental-column-optimization"), false, "enable experimental column optimization") + return nil } @@ -315,6 +320,7 @@ func DefaultDatastoreConfig() *Config { RelationshipIntegrityCurrentKey: RelIntegrityKey{}, RelationshipIntegrityExpiredKeys: []string{}, AllowedMigrations: []string{}, + ExperimentalColumnOptimization: false, } } @@ -509,6 +515,7 @@ func newCRDBDatastore(ctx context.Context, opts Config) (datastore.Datastore, er crdb.FilterMaximumIDCount(opts.FilterMaximumIDCount), crdb.WithIntegrity(opts.RelationshipIntegrityEnabled), crdb.AllowedMigrations(opts.AllowedMigrations), + crdb.WithColumnOptimization(opts.ExperimentalColumnOptimization), ) } @@ -549,6 +556,7 @@ func commonPostgresDatastoreOptions(opts Config) ([]postgres.Option, error) { postgres.WithEnablePrometheusStats(opts.EnableDatastoreMetrics), postgres.MaxRetries(maxRetries), postgres.FilterMaximumIDCount(opts.FilterMaximumIDCount), + postgres.WithColumnOptimization(opts.ExperimentalColumnOptimization), }, nil } @@ -631,6 +639,7 @@ func newSpannerDatastore(ctx context.Context, opts Config) (datastore.Datastore, spanner.MigrationPhase(opts.MigrationPhase), spanner.AllowedMigrations(opts.AllowedMigrations), spanner.FilterMaximumIDCount(opts.FilterMaximumIDCount), + spanner.WithColumnOptimization(opts.ExperimentalColumnOptimization), ) } @@ -675,6 +684,7 @@ func commonMySQLDatastoreOptions(opts Config) ([]mysql.Option, error) { mysql.RevisionQuantization(opts.RevisionQuantization), mysql.FilterMaximumIDCount(opts.FilterMaximumIDCount), mysql.AllowedMigrations(opts.AllowedMigrations), + mysql.WithColumnOptimization(opts.ExperimentalColumnOptimization), }, nil } diff --git a/pkg/cmd/datastore/zz_generated.options.go b/pkg/cmd/datastore/zz_generated.options.go index 7d0774838c..0e41eee6d5 100644 --- a/pkg/cmd/datastore/zz_generated.options.go +++ b/pkg/cmd/datastore/zz_generated.options.go @@ -77,6 +77,7 @@ func (c *Config) ToOption() ConfigOption { to.WatchConnectTimeout = c.WatchConnectTimeout to.MigrationPhase = c.MigrationPhase to.AllowedMigrations = c.AllowedMigrations + to.ExperimentalColumnOptimization = c.ExperimentalColumnOptimization } } @@ -128,6 +129,7 @@ func (c Config) DebugMap() map[string]any { debugMap["WatchConnectTimeout"] = helpers.DebugValue(c.WatchConnectTimeout, false) debugMap["MigrationPhase"] = helpers.DebugValue(c.MigrationPhase, false) debugMap["AllowedMigrations"] = helpers.DebugValue(c.AllowedMigrations, false) + debugMap["ExperimentalColumnOptimization"] = helpers.DebugValue(c.ExperimentalColumnOptimization, false) return debugMap } @@ -510,3 +512,10 @@ func SetAllowedMigrations(allowedMigrations []string) ConfigOption { c.AllowedMigrations = allowedMigrations } } + +// WithExperimentalColumnOptimization returns an option that can set ExperimentalColumnOptimization on a Config +func WithExperimentalColumnOptimization(experimentalColumnOptimization bool) ConfigOption { + return func(c *Config) { + c.ExperimentalColumnOptimization = experimentalColumnOptimization + } +}