satellite/satellitedb: unexport satellitedb.DB

Backstory: I needed a better way to pass around information about the
underlying driver and implementation to all the various db-using things
in satellitedb (at least until some new "cockroach driver" support makes
it to DBX). After hitting a few dead ends, I decided I wanted to have a
type that could act like a *dbx.DB but which would also carry
information about the implementation, etc. Then I could pass around that
type to all the things in satellitedb that previously wanted *dbx.DB.

But then I realized that *satellitedb.DB was, essentially, exactly that
already.

One thing that might have kept *satellitedb.DB from being directly
usable was that embedding a *dbx.DB inside it would make a lot of dbx
methods publicly available on a *satellitedb.DB instance that previously
were nicely encapsulated and hidden. But after a quick look, I realized
that _nothing_ outside of satellite/satellitedb even needs to use
satellitedb.DB at all. It didn't even need to be exported, except for
some trivially-replaceable code in migrate_postgres_test.go. And once
I made it unexported, any concerns about exposing new methods on it were
entirely moot.

So I have here changed the exported *satellitedb.DB type into the
unexported *satellitedb.satelliteDB type, and I have changed all the
places here that wanted raw dbx.DB handles to use this new type instead.
Now they can just take a gander at the implementation member on it and
know all they need to know about the underlying database.

This will make it possible for some other pending code here to
differentiate between postgres and cockroach backends.

Change-Id: I27af99f8ae23b50782333da5277b553b34634edc
This commit is contained in:
paul cannon 2019-12-13 20:29:54 -06:00 committed by paul cannon
parent 6fb9b4b231
commit b5ddfc6fa5
24 changed files with 97 additions and 87 deletions

View File

@ -21,7 +21,7 @@ var _ console.APIKeys = (*apikeys)(nil)
// apikeys is an implementation of satellite.APIKeys
type apikeys struct {
methods dbx.Methods
db *dbx.DB
db *satelliteDB
}
func (keys *apikeys) GetPagedByProjectID(ctx context.Context, projectID uuid.UUID, cursor console.APIKeyCursor) (akp *console.APIKeyPage, err error) {

View File

@ -110,7 +110,7 @@ const (
)
type attributionDB struct {
db *dbx.DB
db *satelliteDB
}
// Get reads the partner info

View File

@ -18,12 +18,12 @@ import (
)
type bucketsDB struct {
db dbx.Methods
db *satelliteDB
}
// Buckets returns database for interacting with buckets
func (db *DB) Buckets() metainfo.BucketsDB {
return &bucketsDB{db: db.db}
func (db *satelliteDB) Buckets() metainfo.BucketsDB {
return &bucketsDB{db: db}
}
// CreateBucket creates a new bucket

View File

@ -39,7 +39,7 @@ func (intent applyBalanceIntentState) Int() int {
//
// architecture: Database
type coinPaymentsTransactions struct {
db *dbx.DB
db *satelliteDB
}
// Insert inserts new coinpayments transaction into DB.

View File

@ -17,7 +17,7 @@ var _ console.DB = (*ConsoleDB)(nil)
// ConsoleDB contains access to different satellite databases.
type ConsoleDB struct {
db *dbx.DB
db *satelliteDB
tx *dbx.Tx
methods dbx.Methods

View File

@ -17,7 +17,7 @@ import (
)
type containment struct {
db *dbx.DB
db *satelliteDB
}
// Get gets the pending audit by node id

View File

@ -25,7 +25,7 @@ var _ stripecoinpayments.CouponsDB = (*coupons)(nil)
//
// architecture: Database
type coupons struct {
db *dbx.DB
db *satelliteDB
}
// Insert inserts a coupon into the database.

View File

@ -22,7 +22,7 @@ var _ stripecoinpayments.CustomersDB = (*customers)(nil)
//
// architecture: Database
type customers struct {
db *dbx.DB
db *satelliteDB
}
// Insert inserts a stripe customer into the database.

View File

@ -29,15 +29,18 @@ var (
Error = errs.Class("satellitedb")
)
// DB contains access to different database tables
type DB struct {
// satelliteDB combines access to different database tables with a record
// of the db driver, db implementation, and db source URL.
type satelliteDB struct {
*dbx.DB
log *zap.Logger
db *dbx.DB
driver string
implementation dbutil.Implementation
source string
}
var _ dbx.DBMethods = &satelliteDB{}
// New creates instance of database supports postgres
func New(log *zap.Logger, databaseURL string) (satellite.DB, error) {
driver, source, implementation, err := dbutil.SplitConnStr(databaseURL)
@ -50,92 +53,93 @@ func New(log *zap.Logger, databaseURL string) (satellite.DB, error) {
source = pgutil.CheckApplicationName(source)
db, err := dbx.Open(driver, source)
dbxDB, err := dbx.Open("postgres", source)
if err != nil {
return nil, Error.New("failed opening database %q, %q: %v",
driver, source, err)
return nil, Error.New("failed opening database via DBX at %q: %v",
source, err)
}
log.Debug("Connected to:", zap.String("db source", source))
dbutil.Configure(db.DB, mon)
dbutil.Configure(dbxDB.DB, mon)
core := &DB{log: log, db: db, driver: driver, source: source, implementation: implementation}
core := &satelliteDB{
DB: dbxDB,
log: log,
driver: driver,
source: source,
implementation: implementation,
}
return core, nil
}
// Close is used to close db connection
func (db *DB) Close() error {
return db.db.Close()
}
// TestDBAccess for raw database access,
// should not be used outside of migration tests.
func (db *DB) TestDBAccess() *dbx.DB { return db.db }
func (db *satelliteDB) TestDBAccess() *dbx.DB { return db.DB }
// PeerIdentities returns a storage for peer identities
func (db *DB) PeerIdentities() overlay.PeerIdentities {
return &peerIdentities{db: db.db}
func (db *satelliteDB) PeerIdentities() overlay.PeerIdentities {
return &peerIdentities{db: db}
}
// Attribution is a getter for value attribution repository
func (db *DB) Attribution() attribution.DB {
return &attributionDB{db: db.db}
func (db *satelliteDB) Attribution() attribution.DB {
return &attributionDB{db: db}
}
// OverlayCache is a getter for overlay cache repository
func (db *DB) OverlayCache() overlay.DB {
return &overlaycache{db: db.db}
func (db *satelliteDB) OverlayCache() overlay.DB {
return &overlaycache{db: db}
}
// RepairQueue is a getter for RepairQueue repository
func (db *DB) RepairQueue() queue.RepairQueue {
return &repairQueue{db: db.db, dbType: db.implementation}
func (db *satelliteDB) RepairQueue() queue.RepairQueue {
return &repairQueue{db: db}
}
// StoragenodeAccounting returns database for tracking storagenode usage
func (db *DB) StoragenodeAccounting() accounting.StoragenodeAccounting {
return &StoragenodeAccounting{db: db.db}
func (db *satelliteDB) StoragenodeAccounting() accounting.StoragenodeAccounting {
return &StoragenodeAccounting{db: db}
}
// ProjectAccounting returns database for tracking project data use
func (db *DB) ProjectAccounting() accounting.ProjectAccounting {
return &ProjectAccounting{db: db.db}
func (db *satelliteDB) ProjectAccounting() accounting.ProjectAccounting {
return &ProjectAccounting{db: db}
}
// Irreparable returns database for storing segments that failed repair
func (db *DB) Irreparable() irreparable.DB {
return &irreparableDB{db: db.db}
func (db *satelliteDB) Irreparable() irreparable.DB {
return &irreparableDB{db: db}
}
// Console returns database for storing users, projects and api keys
func (db *DB) Console() console.DB {
func (db *satelliteDB) Console() console.DB {
return &ConsoleDB{
db: db.db,
methods: db.db,
db: db,
methods: db,
}
}
// Rewards returns database for storing offers
func (db *DB) Rewards() rewards.DB {
return &offersDB{db: db.db}
func (db *satelliteDB) Rewards() rewards.DB {
return &offersDB{db: db}
}
// Orders returns database for storing orders
func (db *DB) Orders() orders.DB {
return &ordersDB{db: db.db}
func (db *satelliteDB) Orders() orders.DB {
return &ordersDB{db: db}
}
// Containment returns database for storing pending audit info
func (db *DB) Containment() audit.Containment {
return &containment{db: db.db}
func (db *satelliteDB) Containment() audit.Containment {
return &containment{db: db}
}
// GracefulExit returns database for graceful exit
func (db *DB) GracefulExit() gracefulexit.DB {
return &gracefulexitDB{db: db.db}
func (db *satelliteDB) GracefulExit() gracefulexit.DB {
return &gracefulexitDB{db: db}
}
// StripeCoinPayments returns database for stripecoinpayments.
func (db *DB) StripeCoinPayments() stripecoinpayments.DB {
return &stripeCoinPaymentsDB{db: db.db}
func (db *satelliteDB) StripeCoinPayments() stripecoinpayments.DB {
return &stripeCoinPaymentsDB{db: db}
}

View File

@ -19,7 +19,7 @@ import (
)
type gracefulexitDB struct {
db *dbx.DB
db *satelliteDB
}
// IncrementProgress increments transfer stats for a node.

View File

@ -38,7 +38,7 @@ func (intent invoiceProjectRecordState) Int() int {
//
// architecture: Database
type invoiceProjectRecords struct {
db *dbx.DB
db *satelliteDB
}
// Create creates new invoice project record in the DB.

View File

@ -14,7 +14,7 @@ import (
)
type irreparableDB struct {
db *dbx.DB
db *satelliteDB
}
// IncrementRepairAttempts a db entry for to increment the repair attempts field

View File

@ -22,7 +22,7 @@ var (
)
// CreateTables is a method for creating all tables for database
func (db *DB) CreateTables() error {
func (db *satelliteDB) CreateTables() error {
// First handle the idiosyncrasies of postgres and cockroach migrations. Postgres
// will need to create any schemas specified in the search path, and cockroach
// will need to create the database it was told to connect to. These things should
@ -36,7 +36,7 @@ func (db *DB) CreateTables() error {
}
if schema != "" {
err = pgutil.CreateSchema(db.db, schema)
err = pgutil.CreateSchema(db, schema)
if err != nil {
return errs.New("error creating schema: %+v", err)
}
@ -44,11 +44,11 @@ func (db *DB) CreateTables() error {
case dbutil.Cockroach:
var dbName string
if err := db.db.QueryRow(`SELECT current_database();`).Scan(&dbName); err != nil {
if err := db.QueryRow(`SELECT current_database();`).Scan(&dbName); err != nil {
return errs.New("error querying current database: %+v", err)
}
_, err := db.db.Exec(fmt.Sprintf(`CREATE DATABASE IF NOT EXISTS %s;`,
_, err := db.Exec(fmt.Sprintf(`CREATE DATABASE IF NOT EXISTS %s;`,
pq.QuoteIdentifier(dbName)))
if err != nil {
return errs.Wrap(err)
@ -61,7 +61,7 @@ func (db *DB) CreateTables() error {
// since we merged migration steps 0-69, the current db version should never be
// less than 69 unless the migration hasn't run yet
const minDBVersion = 69
dbVersion, err := migration.CurrentVersion(db.log, db.db)
dbVersion, err := migration.CurrentVersion(db.log, db.DB)
if err != nil {
return errs.New("error current version: %+v", err)
}
@ -73,12 +73,12 @@ func (db *DB) CreateTables() error {
return migration.Run(db.log.Named("migrate"))
default:
return migrate.Create("database", db.db)
return migrate.Create("database", db.DB)
}
}
// CheckVersion confirms the database is at the desired version
func (db *DB) CheckVersion() error {
func (db *satelliteDB) CheckVersion() error {
switch db.implementation {
case dbutil.Postgres, dbutil.Cockroach:
migration := db.PostgresMigration()
@ -90,12 +90,12 @@ func (db *DB) CheckVersion() error {
}
// PostgresMigration returns steps needed for migrating postgres database.
func (db *DB) PostgresMigration() *migrate.Migration {
func (db *satelliteDB) PostgresMigration() *migrate.Migration {
return &migrate.Migration{
Table: "versions",
Steps: []*migrate.Step{
{
DB: db.db,
DB: db.DB,
Description: "Initial setup",
Version: 69,
Action: migrate.SQL{
@ -495,7 +495,7 @@ func (db *DB) PostgresMigration() *migrate.Migration {
},
},
{
DB: db.db,
DB: db.DB,
Description: "Add coupons and coupon_usage tables",
Version: 70,
Action: migrate.SQL{
@ -521,7 +521,7 @@ func (db *DB) PostgresMigration() *migrate.Migration {
},
},
{
DB: db.db,
DB: db.DB,
Description: "Reset node reputations to re-enable disqualification",
Version: 71,
Action: migrate.SQL{
@ -529,7 +529,7 @@ func (db *DB) PostgresMigration() *migrate.Migration {
},
},
{
DB: db.db,
DB: db.DB,
Description: "Add unique to user_credits to match dbx schema",
Version: 72,
Action: migrate.SQL{

View File

@ -21,7 +21,9 @@ import (
"storj.io/storj/private/dbutil/pgutil"
"storj.io/storj/private/dbutil/pgutil/pgtest"
"storj.io/storj/private/dbutil/tempdb"
"storj.io/storj/private/migrate"
"storj.io/storj/satellite/satellitedb"
dbx "storj.io/storj/satellite/satellitedb/dbx"
)
// loadSnapshots loads all the dbschemas from testdata/postgres.* caching the result
@ -136,6 +138,13 @@ func TestMigratePostgres(t *testing.T) {
pgMigrateTest(t, *pgtest.ConnStr)
}
// satelliteDB provides access to certain methods on a *satellitedb.satelliteDB
// instance, since that type is not exported.
type satelliteDB interface {
TestDBAccess() *dbx.DB
PostgresMigration() *migrate.Migration
}
func pgMigrateTest(t *testing.T, connStr string) {
log := zaptest.NewLogger(t)
@ -153,12 +162,12 @@ func pgMigrateTest(t *testing.T, connStr string) {
defer func() { require.NoError(t, db.Close()) }()
// we need raw database access unfortunately
rawdb := db.(*satellitedb.DB).TestDBAccess()
rawdb := db.(satelliteDB).TestDBAccess()
var finalSchema *dbschema.Schema
// get migration for this database
migrations := db.(*satellitedb.DB).PostgresMigration()
migrations := db.(satelliteDB).PostgresMigration()
for i, step := range migrations.Steps {
tag := fmt.Sprintf("#%d - v%d", i, step.Version)

View File

@ -22,7 +22,7 @@ var (
)
type offersDB struct {
db *dbx.DB
db *satelliteDB
}
// ListAll returns all offersDB from the db
@ -108,7 +108,7 @@ func (db *offersDB) Create(ctx context.Context, o *rewards.NewOffer) (*rewards.O
var id int64
err := crdb.ExecuteTx(ctx, db.db.DB, nil, func(tx *sql.Tx) error {
err := crdb.ExecuteTx(ctx, db.db.DB.DB, nil, func(tx *sql.Tx) error {
// If there's an existing current offer, update its status to Done and set its expires_at to be NOW()
switch o.Type {
case rewards.Partner:

View File

@ -28,7 +28,7 @@ var (
)
type ordersDB struct {
db *dbx.DB
db *satelliteDB
}
// CreateSerialInfo creates serial number entry in database

View File

@ -31,7 +31,7 @@ var (
var _ overlay.DB = (*overlaycache)(nil)
type overlaycache struct {
db *dbx.DB
db *satelliteDB
}
func (cache *overlaycache) SelectStorageNodes(ctx context.Context, count int, criteria *overlay.NodeCriteria) (nodes []*pb.Node, err error) {
@ -586,7 +586,7 @@ func (cache *overlaycache) BatchUpdateStats(ctx context.Context, updateRequests
}
updateNodeStats := populateUpdateNodeStats(dbNode, updateReq)
sql := buildUpdateStatement(cache.db, updateNodeStats)
sql := buildUpdateStatement(updateNodeStats)
allSQL += sql
}
@ -1120,7 +1120,7 @@ func updateReputation(isSuccess bool, alpha, beta, lambda, w float64, totalCount
return newAlpha, newBeta, totalCount + 1
}
func buildUpdateStatement(db *dbx.DB, update updateNodeStats) string {
func buildUpdateStatement(update updateNodeStats) string {
if update.NodeID.IsZero() {
return ""
}

View File

@ -17,7 +17,7 @@ import (
)
type peerIdentities struct {
db *dbx.DB
db *satelliteDB
}
// Set adds a peer identity entry

View File

@ -24,7 +24,7 @@ var _ accounting.ProjectAccounting = (*ProjectAccounting)(nil)
// ProjectAccounting implements the accounting/db ProjectAccounting interface
type ProjectAccounting struct {
db *dbx.DB
db *satelliteDB
}
// SaveTallies saves the latest bucket info

View File

@ -21,7 +21,7 @@ var _ console.ProjectMembers = (*projectMembers)(nil)
// ProjectMembers exposes methods to manage ProjectMembers table in database.
type projectMembers struct {
methods dbx.Methods
db *dbx.DB
db *satelliteDB
}
// GetByMemberID is a method for querying project member from the database by memberID.

View File

@ -13,13 +13,11 @@ import (
"storj.io/storj/pkg/pb"
"storj.io/storj/private/dbutil"
"storj.io/storj/private/dbutil/pgutil"
dbx "storj.io/storj/satellite/satellitedb/dbx"
"storj.io/storj/storage"
)
type repairQueue struct {
db *dbx.DB
dbType dbutil.Implementation
db *satelliteDB
}
func (r *repairQueue) Insert(ctx context.Context, seg *pb.InjuredSegment) (err error) {
@ -36,9 +34,9 @@ func (r *repairQueue) Insert(ctx context.Context, seg *pb.InjuredSegment) (err e
func (r *repairQueue) Select(ctx context.Context) (seg *pb.InjuredSegment, err error) {
defer mon.Task()(&ctx)(&err)
switch r.dbType {
switch r.db.implementation {
case dbutil.Cockroach:
err = crdb.ExecuteTx(ctx, r.db.DB, nil, func(tx *sql.Tx) error {
err = crdb.ExecuteTx(ctx, r.db.DB.DB, nil, func(tx *sql.Tx) error {
return tx.QueryRowContext(ctx, `
UPDATE injuredsegments SET attempted = now() AT TIME ZONE 'UTC' WHERE path = (
SELECT path FROM injuredsegments
@ -54,7 +52,7 @@ func (r *repairQueue) Select(ctx context.Context) (seg *pb.InjuredSegment, err e
ORDER BY attempted NULLS FIRST FOR UPDATE SKIP LOCKED LIMIT 1
) RETURNING data`).Scan(&seg)
default:
return seg, errs.New("invalid dbType: %v", r.dbType)
return seg, errs.New("invalid dbType: %v", r.db.implementation)
}
if err == sql.ErrNoRows {
err = storage.ErrEmptyQueue.New("")

View File

@ -18,7 +18,7 @@ import (
// StoragenodeAccounting implements the accounting/db StoragenodeAccounting interface
type StoragenodeAccounting struct {
db *dbx.DB
db *satelliteDB
}
// SaveTallies records raw tallies of at rest data to the database

View File

@ -5,7 +5,6 @@ package satellitedb
import (
"storj.io/storj/satellite/payments/stripecoinpayments"
dbx "storj.io/storj/satellite/satellitedb/dbx"
)
// ensures that *stripeCoinPaymentsDB implements stripecoinpayments.DB.
@ -15,7 +14,7 @@ var _ stripecoinpayments.DB = (*stripeCoinPaymentsDB)(nil)
//
// architecture: Database
type stripeCoinPaymentsDB struct {
db *dbx.DB
db *satelliteDB
}
// Customers is getter for customers db.

View File

@ -22,7 +22,7 @@ import (
var _ console.UserCredits = (*usercredits)(nil)
type usercredits struct {
db *dbx.DB
db *satelliteDB
tx *dbx.Tx
}