github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/datastore/postgres/stats.go (about) 1 package postgres 2 3 import ( 4 "context" 5 "fmt" 6 7 sq "github.com/Masterminds/squirrel" 8 "github.com/jackc/pgx/v5" 9 10 pgxcommon "github.com/authzed/spicedb/internal/datastore/postgres/common" 11 "github.com/authzed/spicedb/pkg/datastore" 12 ) 13 14 const ( 15 tableMetadata = "metadata" 16 colUniqueID = "unique_id" 17 18 tablePGClass = "pg_class" 19 colReltuples = "reltuples" 20 colRelname = "relname" 21 ) 22 23 var ( 24 queryUniqueID = psql.Select(colUniqueID).From(tableMetadata) 25 queryEstimatedRowCount = psql. 26 Select(colReltuples). 27 From(tablePGClass). 28 Where(sq.Eq{colRelname: tableTuple}) 29 ) 30 31 func (pgd *pgDatastore) datastoreUniqueID(ctx context.Context) (string, error) { 32 idSQL, idArgs, err := queryUniqueID.ToSql() 33 if err != nil { 34 return "", fmt.Errorf("unable to generate query sql: %w", err) 35 } 36 37 var uniqueID string 38 return uniqueID, pgx.BeginTxFunc(ctx, pgd.readPool, pgd.readTxOptions, func(tx pgx.Tx) error { 39 return tx.QueryRow(ctx, idSQL, idArgs...).Scan(&uniqueID) 40 }) 41 } 42 43 func (pgd *pgDatastore) Statistics(ctx context.Context) (datastore.Stats, error) { 44 idSQL, idArgs, err := queryUniqueID.ToSql() 45 if err != nil { 46 return datastore.Stats{}, fmt.Errorf("unable to generate query sql: %w", err) 47 } 48 49 rowCountSQL, rowCountArgs, err := queryEstimatedRowCount.ToSql() 50 if err != nil { 51 return datastore.Stats{}, fmt.Errorf("unable to prepare row count sql: %w", err) 52 } 53 54 filterer := func(original sq.SelectBuilder) sq.SelectBuilder { 55 return original.Where(sq.Eq{colDeletedXid: liveDeletedTxnID}) 56 } 57 58 var uniqueID string 59 var nsDefs []datastore.RevisionedNamespace 60 var relCount int64 61 if err := pgx.BeginTxFunc(ctx, pgd.readPool, pgd.readTxOptions, func(tx pgx.Tx) error { 62 if pgd.analyzeBeforeStatistics { 63 if _, err := tx.Exec(ctx, "ANALYZE "+tableTuple); err != nil { 64 return fmt.Errorf("unable to analyze tuple table: %w", err) 65 } 66 } 67 68 if err := tx.QueryRow(ctx, idSQL, idArgs...).Scan(&uniqueID); err != nil { 69 return fmt.Errorf("unable to query unique ID: %w", err) 70 } 71 72 nsDefsWithRevisions, err := loadAllNamespaces(ctx, pgxcommon.QuerierFuncsFor(tx), filterer) 73 if err != nil { 74 return fmt.Errorf("unable to load namespaces: %w", err) 75 } 76 77 nsDefs = nsDefsWithRevisions 78 79 if err := tx.QueryRow(ctx, rowCountSQL, rowCountArgs...).Scan(&relCount); err != nil { 80 return fmt.Errorf("unable to read relationship count: %w", err) 81 } 82 83 return nil 84 }); err != nil { 85 return datastore.Stats{}, err 86 } 87 88 // Sometimes relCount can be negative on postgres, truncate to 0 89 var relCountUint uint64 90 if relCount > 0 { 91 relCountUint = uint64(relCount) 92 } 93 94 return datastore.Stats{ 95 UniqueID: uniqueID, 96 ObjectTypeStatistics: datastore.ComputeObjectTypeStats(nsDefs), 97 EstimatedRelationshipCount: relCountUint, 98 }, nil 99 }