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