Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stats: use leased types in the stats cache #53078

Merged
merged 1 commit into from
Aug 20, 2020
Merged
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
2 changes: 2 additions & 0 deletions pkg/server/server_sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,8 @@ func newSQLServer(ctx context.Context, cfg sqlServerArgs) (*sqlServer, error) {
cfg.db,
cfg.circularInternalExecutor,
codec,
leaseMgr,
cfg.Settings,
),

// Note: don't forget to add the secondary loggers as closers
Expand Down
50 changes: 0 additions & 50 deletions pkg/sql/catalog/resolver/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"github.com/cockroachdb/cockroach/pkg/keys"
"github.com/cockroachdb/cockroach/pkg/kv"
"github.com/cockroachdb/cockroach/pkg/sql/catalog"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/catalogkv"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/catconstants"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb"
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
Expand Down Expand Up @@ -274,55 +273,6 @@ func ResolveSchemaNameByID(
return "", errors.Newf("unable to resolve schema id %d for db %d", schemaID, dbID)
}

// ResolveTypeDescByID resolves a TypeDescriptor and fully qualified name
// from an ID.
// TODO (rohany): Once we start to cache type descriptors, this needs to
// look into the set of leased copies.
// TODO (rohany): Once we lease types, this should be pushed down into the
// leased object collection.
func ResolveTypeDescByID(
ctx context.Context,
txn *kv.Txn,
codec keys.SQLCodec,
id descpb.ID,
lookupFlags tree.ObjectLookupFlags,
) (tree.TypeName, sqlbase.TypeDescriptor, error) {
desc, err := catalogkv.GetDescriptorByID(ctx, txn, codec, id, catalogkv.Immutable,
catalogkv.TypeDescriptorKind, lookupFlags.Required)
if err != nil {
if pgerror.GetPGCode(err) == pgcode.WrongObjectType {
err = errors.HandleAsAssertionFailure(err)
}
return tree.TypeName{}, nil, err
}
// Get the parent database and schema names to create a fully qualified
// name for the type.
// TODO (SQLSchema): As we add leasing for all descriptors, these calls
// should look into those leased copies, rather than do raw reads.
typDesc := desc.(*sqlbase.ImmutableTypeDescriptor)
db, err := catalogkv.MustGetDatabaseDescByID(ctx, txn, codec, typDesc.ParentID)
if err != nil {
return tree.TypeName{}, nil, err
}
schemaName, err := ResolveSchemaNameByID(ctx, txn, codec, typDesc.ParentID, typDesc.ParentSchemaID)
if err != nil {
return tree.TypeName{}, nil, err
}
name := tree.MakeNewQualifiedTypeName(db.GetName(), schemaName, typDesc.GetName())
var ret sqlbase.TypeDescriptor
if lookupFlags.RequireMutable {
// TODO(ajwerner): Figure this out later when we construct this inside of
// the name resolution. This really shouldn't be happening here. Instead we
// should be taking a SchemaResolver and resolving through it which should
// be able to hit a descs.Collection and determine whether this is a new
// type or not.
desc = sqlbase.NewMutableExistingTypeDescriptor(*typDesc.TypeDesc())
} else {
ret = typDesc
}
return name, ret, nil
}

// GetForDatabase looks up and returns all available
// schema ids to names for a given database.
func GetForDatabase(
Expand Down
9 changes: 9 additions & 0 deletions pkg/sql/stats/automatic_stats_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/cockroachdb/cockroach/pkg/settings/cluster"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/catalogkv"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/lease"
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
"github.com/cockroachdb/cockroach/pkg/sql/sqlutil"
"github.com/cockroachdb/cockroach/pkg/sql/types"
Expand Down Expand Up @@ -65,6 +66,8 @@ func TestMaybeRefreshStats(t *testing.T) {
kvDB,
executor,
keys.SystemSQLCodec,
s.LeaseManager().(*lease.Manager),
s.ClusterSettings(),
)
refresher := MakeRefresher(st, executor, cache, time.Microsecond /* asOfTime */)

Expand Down Expand Up @@ -142,6 +145,8 @@ func TestAverageRefreshTime(t *testing.T) {
kvDB,
executor,
keys.SystemSQLCodec,
s.LeaseManager().(*lease.Manager),
s.ClusterSettings(),
)
refresher := MakeRefresher(st, executor, cache, time.Microsecond /* asOfTime */)

Expand Down Expand Up @@ -378,6 +383,8 @@ func TestAutoStatsReadOnlyTables(t *testing.T) {
kvDB,
executor,
keys.SystemSQLCodec,
s.LeaseManager().(*lease.Manager),
s.ClusterSettings(),
)
refresher := MakeRefresher(st, executor, cache, time.Microsecond /* asOfTime */)

Expand Down Expand Up @@ -416,6 +423,8 @@ func TestNoRetryOnFailure(t *testing.T) {
kvDB,
executor,
keys.SystemSQLCodec,
s.LeaseManager().(*lease.Manager),
s.ClusterSettings(),
)
r := MakeRefresher(st, executor, cache, time.Microsecond /* asOfTime */)

Expand Down
3 changes: 3 additions & 0 deletions pkg/sql/stats/delete_stats_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/cockroachdb/cockroach/pkg/keys"
"github.com/cockroachdb/cockroach/pkg/kv"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/lease"
"github.com/cockroachdb/cockroach/pkg/sql/sqlutil"
"github.com/cockroachdb/cockroach/pkg/testutils"
"github.com/cockroachdb/cockroach/pkg/testutils/serverutils"
Expand All @@ -44,6 +45,8 @@ func TestDeleteOldStatsForColumns(t *testing.T) {
db,
ex,
keys.SystemSQLCodec,
s.LeaseManager().(*lease.Manager),
s.ClusterSettings(),
)

// The test data must be ordered by CreatedAt DESC so the calculated set of
Expand Down
10 changes: 7 additions & 3 deletions pkg/sql/stats/gossip_invalidation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/cockroachdb/cockroach/pkg/gossip"
"github.com/cockroachdb/cockroach/pkg/keys"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/catalogkv"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/lease"
"github.com/cockroachdb/cockroach/pkg/sql/sqlutil"
"github.com/cockroachdb/cockroach/pkg/sql/stats"
"github.com/cockroachdb/cockroach/pkg/testutils"
Expand All @@ -38,12 +39,15 @@ func TestGossipInvalidation(t *testing.T) {
tc := testcluster.StartTestCluster(t, 3, base.TestClusterArgs{})
defer tc.Stopper().Stop(ctx)

s := tc.Server(0)
sc := stats.NewTableStatisticsCache(
10, /* cacheSize */
gossip.MakeOptionalGossip(tc.Server(0).GossipI().(*gossip.Gossip)),
tc.Server(0).DB(),
tc.Server(0).InternalExecutor().(sqlutil.InternalExecutor),
gossip.MakeOptionalGossip(s.GossipI().(*gossip.Gossip)),
s.DB(),
s.InternalExecutor().(sqlutil.InternalExecutor),
keys.SystemSQLCodec,
s.LeaseManager().(*lease.Manager),
s.ClusterSettings(),
)

sr0 := sqlutils.MakeSQLRunner(tc.ServerConn(0))
Expand Down
50 changes: 28 additions & 22 deletions pkg/sql/stats/stats_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ import (
"github.com/cockroachdb/cockroach/pkg/keys"
"github.com/cockroachdb/cockroach/pkg/kv"
"github.com/cockroachdb/cockroach/pkg/roachpb"
"github.com/cockroachdb/cockroach/pkg/settings/cluster"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/resolver"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descs"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/lease"
"github.com/cockroachdb/cockroach/pkg/sql/opt/cat"
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
Expand Down Expand Up @@ -61,6 +63,9 @@ type TableStatisticsCache struct {
ClientDB *kv.DB
SQLExecutor sqlutil.InternalExecutor
Codec keys.SQLCodec

LeaseMgr *lease.Manager
Settings *cluster.Settings
}

// The cache stores *cacheEntry objects. The fields are protected by the
Expand Down Expand Up @@ -99,11 +104,15 @@ func NewTableStatisticsCache(
db *kv.DB,
sqlExecutor sqlutil.InternalExecutor,
codec keys.SQLCodec,
leaseManager *lease.Manager,
settings *cluster.Settings,
) *TableStatisticsCache {
tableStatsCache := &TableStatisticsCache{
ClientDB: db,
SQLExecutor: sqlExecutor,
Codec: codec,
LeaseMgr: leaseManager,
Settings: settings,
}
tableStatsCache.mu.cache = cache.NewUnorderedCache(cache.Config{
Policy: cache.CacheLRU,
Expand Down Expand Up @@ -334,8 +343,8 @@ const (

// parseStats converts the given datums to a TableStatistic object. It might
// need to run a query to get user defined type metadata.
func parseStats(
ctx context.Context, db *kv.DB, codec keys.SQLCodec, datums tree.Datums,
func (sc *TableStatisticsCache) parseStats(
ctx context.Context, datums tree.Datums,
) (*TableStatistic, error) {
if datums == nil || datums.Len() == 0 {
return nil, nil
Expand Down Expand Up @@ -401,28 +410,25 @@ func parseStats(

// Decode the histogram data so that it's usable by the opt catalog.
res.Histogram = make([]cat.HistogramBucket, len(res.HistogramData.Buckets))
typ := res.HistogramData.ColumnType
// Hydrate the type in case any user defined types are present.
// There are cases where typ is nil, so don't do anything if so.
if typ != nil && typ.UserDefined() {
// TODO (rohany): This should instead query a leased copy of the type.
// TODO (rohany): If we are caching data about types here, then this
// cache needs to be invalidated as well when type metadata changes.
// TODO (rohany): It might be better to store the type metadata used when
// collecting the stats in the HistogramData object itself, and avoid
// this query and caching/leasing problem.
if typ := res.HistogramData.ColumnType; typ != nil && typ.UserDefined() {
// The metadata accessed here is never older than the metadata used when
// collecting the stats. Changes to types are backwards compatible across
// versions, so using a newer version of the type metadata here is safe.
err := db.Txn(ctx, func(ctx context.Context, txn *kv.Txn) error {
typeLookup := func(ctx context.Context, id descpb.ID) (tree.TypeName, sqlbase.TypeDescriptor, error) {
return resolver.ResolveTypeDescByID(ctx, txn, codec, id, tree.ObjectLookupFlags{})
}
name, typeDesc, err := typeLookup(ctx, sqlbase.GetTypeDescID(typ))
if err != nil {
return err
}
return typeDesc.HydrateTypeInfoWithName(ctx, typ, &name, sqlbase.TypeLookupFunc(typeLookup))
// Given that we never delete members from enum types, a descriptor we
// get from the lease manager will be able to be used to decode these stats,
// even if it wasn't the descriptor that was used to collect the stats.
// If have types that are not backwards compatible in this way, then we
// will need to start writing a timestamp on the stats objects and request
// TypeDescriptor's with the timestamp that the stats were recorded with.
err := sc.ClientDB.Txn(ctx, func(ctx context.Context, txn *kv.Txn) error {
collection := descs.NewCollection(ctx, sc.Settings, sc.LeaseMgr)
defer collection.ReleaseAll(ctx)
resolver := descs.NewDistSQLTypeResolver(collection, txn)
var err error
res.HistogramData.ColumnType, err = resolver.ResolveTypeByOID(ctx, typ.Oid())
return err
})
if err != nil {
return nil, err
Expand All @@ -431,7 +437,7 @@ func parseStats(
var a sqlbase.DatumAlloc
for i := range res.Histogram {
bucket := &res.HistogramData.Buckets[i]
datum, _, err := sqlbase.DecodeTableKey(&a, typ, bucket.UpperBound, encoding.Ascending)
datum, _, err := sqlbase.DecodeTableKey(&a, res.HistogramData.ColumnType, bucket.UpperBound, encoding.Ascending)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -476,7 +482,7 @@ ORDER BY "createdAt" DESC

var statsList []*TableStatistic
for _, row := range rows {
stats, err := parseStats(ctx, sc.ClientDB, sc.Codec, row)
stats, err := sc.parseStats(ctx, row)
if err != nil {
return nil, err
}
Expand Down
7 changes: 7 additions & 0 deletions pkg/sql/stats/stats_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/cockroachdb/cockroach/pkg/kv"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/catalogkv"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/lease"
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
"github.com/cockroachdb/cockroach/pkg/sql/sqlutil"
"github.com/cockroachdb/cockroach/pkg/sql/types"
Expand Down Expand Up @@ -233,6 +234,8 @@ func TestCacheBasic(t *testing.T) {
db,
ex,
keys.SystemSQLCodec,
s.LeaseManager().(*lease.Manager),
s.ClusterSettings(),
)
for _, tableID := range tableIDs {
if err := checkStatsForTable(ctx, sc, expectedStats[tableID], tableID); err != nil {
Expand Down Expand Up @@ -325,6 +328,8 @@ CREATE STATISTICS s FROM tt;
kvDB,
s.InternalExecutor().(sqlutil.InternalExecutor),
keys.SystemSQLCodec,
s.LeaseManager().(*lease.Manager),
s.ClusterSettings(),
)
tbl := catalogkv.TestingGetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", "tt")
// Get stats for our table. We are ensuring here that the access to the stats
Expand Down Expand Up @@ -364,6 +369,8 @@ func TestCacheWait(t *testing.T) {
db,
ex,
keys.SystemSQLCodec,
s.LeaseManager().(*lease.Manager),
s.ClusterSettings(),
)
for _, tableID := range tableIDs {
if err := checkStatsForTable(ctx, sc, expectedStats[tableID], tableID); err != nil {
Expand Down