Skip to content

Commit

Permalink
Move column elision behind an experimental flag
Browse files Browse the repository at this point in the history
  • Loading branch information
josephschorr committed Nov 22, 2024
1 parent 75efa5a commit d98d7d2
Show file tree
Hide file tree
Showing 15 changed files with 147 additions and 36 deletions.
10 changes: 8 additions & 2 deletions internal/datastore/common/relationships.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -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)
Expand Down
36 changes: 27 additions & 9 deletions internal/datastore/common/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -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
Expand All @@ -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.
Expand All @@ -94,6 +106,7 @@ func NewSchemaInformation(
colCaveatContext string,
paginationFilterType PaginationFilterType,
placeholderFormat sq.PlaceholderFormat,
columnOptionizationOption ColumnOptimizationOption,
extraFields ...string,
) SchemaInformation {
return SchemaInformation{
Expand All @@ -108,6 +121,7 @@ func NewSchemaInformation(
colCaveatContext,
paginationFilterType,
placeholderFormat,
columnOptionizationOption,
extraFields,
}
}
Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -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)
}
Expand Down
2 changes: 2 additions & 0 deletions internal/datastore/common/sql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,7 @@ func TestSchemaQueryFilterer(t *testing.T) {
"caveat_context",
TupleComparison,
sq.Question,
ColumnOptimizationOptionStaticValues,
)
filterer := NewSchemaQueryFiltererForRelationshipsSelect(schema, 100)

Expand Down Expand Up @@ -829,6 +830,7 @@ func TestExecuteQuery(t *testing.T) {
"caveat_context",
TupleComparison,
sq.Question,
ColumnOptimizationOptionStaticValues,
)
filterer := NewSchemaQueryFiltererForRelationshipsSelect(schema, 100)
ran := tc.run(filterer)
Expand Down
1 change: 1 addition & 0 deletions internal/datastore/crdb/crdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ func newCRDBDatastore(ctx context.Context, url string, options ...Option) (datas
colCaveatContext,
common.ExpandedLogicComparison,
sq.Dollar,
config.columnOptimizationOption,
extraFields...,
)

Expand Down
15 changes: 15 additions & 0 deletions internal/datastore/crdb/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand All @@ -28,6 +29,7 @@ type crdbOptions struct {
enablePrometheusStats bool
withIntegrity bool
allowedMigrations []string
columnOptimizationOption common.ColumnOptimizationOption
}

const (
Expand Down Expand Up @@ -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
Expand All @@ -78,6 +81,7 @@ func generateConfig(options []Option) (crdbOptions, error) {
connectRate: defaultConnectRate,
filterMaximumIDCount: defaultFilterMaximumIDCount,
withIntegrity: defaultWithIntegrity,
columnOptimizationOption: defaultColumnOptimizationOption,
}

for _, option := range options {
Expand Down Expand Up @@ -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
}
}
}
1 change: 1 addition & 0 deletions internal/datastore/dsfortesting/dsfortesting.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ func (vr validatingReader) QueryRelationships(
"caveat_context",
common.TupleComparison,
sq.Question,
common.ColumnOptimizationOptionStaticValues,
)

qBuilder, err := common.NewSchemaQueryFiltererForRelationshipsSelect(schema, 100).
Expand Down
1 change: 1 addition & 0 deletions internal/datastore/mysql/datastore.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ func newMySQLDatastore(ctx context.Context, uri string, replicaIndex int, option
colCaveatContext,
common.ExpandedLogicComparison,
sq.Question,
config.columnOptimizationOption,
)

store := &Datastore{
Expand Down
15 changes: 15 additions & 0 deletions internal/datastore/mysql/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"time"

"github.com/authzed/spicedb/internal/datastore/common"
log "github.com/authzed/spicedb/internal/logging"
)

Expand All @@ -25,6 +26,7 @@ const (
defaultGCEnabled = true
defaultCredentialsProviderName = ""
defaultFilterMaximumIDCount = 100
defaultColumnOptimizationOption = common.ColumnOptimizationOptionNone
)

type mysqlOptions struct {
Expand All @@ -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
Expand All @@ -70,6 +73,7 @@ func generateConfig(options []Option) (mysqlOptions, error) {
gcEnabled: defaultGCEnabled,
credentialsProviderName: defaultCredentialsProviderName,
filterMaximumIDCount: defaultFilterMaximumIDCount,
columnOptimizationOption: defaultColumnOptimizationOption,
}

for _, option := range options {
Expand Down Expand Up @@ -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
}
}
}
23 changes: 19 additions & 4 deletions internal/datastore/postgres/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand All @@ -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
Expand Down Expand Up @@ -67,6 +69,7 @@ const (
defaultCredentialsProviderName = ""
defaultReadStrictMode = false
defaultFilterMaximumIDCount = 100
defaultColumnOptimizationOption = common.ColumnOptimizationOptionNone
)

// Option provides the facility to configure how clients within the
Expand All @@ -89,6 +92,7 @@ func generateConfig(options []Option) (postgresOptions, error) {
readStrictMode: defaultReadStrictMode,
queryInterceptor: nil,
filterMaximumIDCount: defaultFilterMaximumIDCount,
columnOptimizationOption: defaultColumnOptimizationOption,
}

for _, option := range options {
Expand Down Expand Up @@ -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
}
}
}
1 change: 1 addition & 0 deletions internal/datastore/postgres/postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ func newPostgresDatastore(
colCaveatContext,
common.TupleComparison,
sq.Dollar,
config.columnOptimizationOption,
)

datastore := &pgDatastore{
Expand Down
16 changes: 16 additions & 0 deletions internal/datastore/spanner/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"runtime"
"time"

"github.com/authzed/spicedb/internal/datastore/common"
log "github.com/authzed/spicedb/internal/logging"
)

Expand All @@ -26,6 +27,7 @@ type spannerOptions struct {
migrationPhase string
allowedMigrations []string
filterMaximumIDCount uint16
columnOptimizationOption common.ColumnOptimizationOption
}

type migrationPhase uint8
Expand All @@ -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
Expand All @@ -72,6 +75,7 @@ func generateConfig(options []Option) (spannerOptions, error) {
maxSessions: 400,
migrationPhase: "", // no migration
filterMaximumIDCount: defaultFilterMaximumIDCount,
columnOptimizationOption: defaultColumnOptimizationOption,
}

for _, option := range options {
Expand Down Expand Up @@ -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
}
}
}
Loading

0 comments on commit d98d7d2

Please sign in to comment.