From 580e511b4ca1cc6c7d45b67cb800ecfcb4eeb49b Mon Sep 17 00:00:00 2001 From: Isaac Hess Date: Mon, 23 Sep 2019 12:36:46 -0700 Subject: [PATCH] storagenode/storagenodedb: Migrate to separate dbs (#3081) * storagenode/storagenodedb: Migrate to separate dbs * storagenode/storagenodedb: Add migration to drop versions tables * Put drop table statements into a transaction. * Fix CI errors. * Fix CI errors. * Changes requested from PR feedback. * storagenode/storagenodedb: fix tx commit --- cmd/storagenode/main.go | 2 +- internal/dbutil/sqliteutil/migrator.go | 43 +- internal/testplanet/storagenode.go | 3 +- storagenode/bandwidth/db_test.go | 2 +- storagenode/peer.go | 2 +- storagenode/storagenodedb/database.go | 301 +++++++++---- storagenode/storagenodedb/migratableDB.go | 16 +- storagenode/storagenodedb/migrations_test.go | 12 +- .../storagenodedb/storagenodedbtest/run.go | 2 +- .../storagenodedbtest/run_test.go | 2 +- .../storagenodedb/testdata/multidbsnapshot.go | 2 + storagenode/storagenodedb/testdata/v21.go | 4 +- storagenode/storagenodedb/testdata/v22.go | 425 ++++++++++++++++++ storagenode/storagenodedb/testdata/v23.go | 221 +++++++++ 14 files changed, 930 insertions(+), 107 deletions(-) create mode 100644 storagenode/storagenodedb/testdata/v22.go create mode 100644 storagenode/storagenodedb/testdata/v23.go diff --git a/cmd/storagenode/main.go b/cmd/storagenode/main.go index 3ccd73dab..8d05d040e 100644 --- a/cmd/storagenode/main.go +++ b/cmd/storagenode/main.go @@ -163,7 +163,7 @@ func cmdRun(cmd *cobra.Command, args []string) (err error) { zap.S().Warn("Failed to initialize telemetry batcher: ", err) } - err = db.CreateTables() + err = db.CreateTables(ctx) if err != nil { return errs.New("Error creating tables for master database on storagenode: %+v", err) } diff --git a/internal/dbutil/sqliteutil/migrator.go b/internal/dbutil/sqliteutil/migrator.go index edf59363e..b4a47de06 100644 --- a/internal/dbutil/sqliteutil/migrator.go +++ b/internal/dbutil/sqliteutil/migrator.go @@ -138,9 +138,40 @@ func backupConns(ctx context.Context, sourceDB *sqlite3.SQLiteConn, destDB *sqli } // KeepTables drops all the tables except the specified tables to keep. -func KeepTables(ctx context.Context, db *sql.DB, tablesToKeep ...string) error { +func KeepTables(ctx context.Context, db *sql.DB, tablesToKeep ...string) (err error) { + err = dropTables(ctx, db, tablesToKeep...) + if err != nil { + return ErrKeepTables.Wrap(err) + } + + // VACUUM the database to reclaim the space used by the dropped tables. The + // data will not actually be reclaimed until the db has been closed. + // We don't include this in the above transaction because + // you can't VACUUM within a transaction with SQLite3. + _, err = db.Exec("VACUUM;") + if err != nil { + return ErrKeepTables.Wrap(err) + } + return err +} + +// dropTables performs the table drops in a single transaction +func dropTables(ctx context.Context, db *sql.DB, tablesToKeep ...string) (err error) { + tx, err := db.BeginTx(ctx, nil) + if err != nil { + return ErrKeepTables.Wrap(err) + } + + defer func() { + if err != nil { + err = ErrKeepTables.Wrap(errs.Combine(err, tx.Rollback())) + } else { + err = ErrKeepTables.Wrap(errs.Combine(err, tx.Commit())) + } + }() + // Get a list of tables excluding sqlite3 system tables. - rows, err := db.Query("SELECT name FROM sqlite_master WHERE type ='table' AND name NOT LIKE 'sqlite_%';") + rows, err := tx.QueryContext(ctx, "SELECT name FROM sqlite_master WHERE type ='table' AND name NOT LIKE 'sqlite_%';") if err != nil { return ErrKeepTables.Wrap(err) } @@ -165,19 +196,13 @@ func KeepTables(ctx context.Context, db *sql.DB, tablesToKeep ...string) error { for _, tableName := range tables { if !tableToKeep(tableName, tablesToKeep) { // Drop tables we aren't told to keep in the destination database. - _, err = db.Exec(fmt.Sprintf("DROP TABLE %s;", tableName)) + _, err = tx.ExecContext(ctx, fmt.Sprintf("DROP TABLE %s;", tableName)) if err != nil { return ErrKeepTables.Wrap(err) } } } - // VACUUM the database to reclaim the space used by the dropped tables. The - // data will not actually be reclaimed until the db has been closed. - _, err = db.Exec("VACUUM;") - if err != nil { - return ErrKeepTables.Wrap(err) - } return nil } diff --git a/internal/testplanet/storagenode.go b/internal/testplanet/storagenode.go index 3f5b6a2dd..2478021a0 100644 --- a/internal/testplanet/storagenode.go +++ b/internal/testplanet/storagenode.go @@ -4,6 +4,7 @@ package testplanet import ( + "context" "fmt" "os" "path/filepath" @@ -171,7 +172,7 @@ func (planet *Planet) newStorageNodes(count int, whitelistedSatellites storj.Nod return xs, err } - err = db.CreateTables() + err = db.CreateTables(context.TODO()) if err != nil { return nil, err } diff --git a/storagenode/bandwidth/db_test.go b/storagenode/bandwidth/db_test.go index 56e8e2431..ef331777b 100644 --- a/storagenode/bandwidth/db_test.go +++ b/storagenode/bandwidth/db_test.go @@ -334,7 +334,7 @@ func TestBandwidthRollup(t *testing.T) { ctx := testcontext.New(t) defer ctx.Cleanup() - err := db.CreateTables() + err := db.CreateTables(ctx) if err != nil { t.Fatal(err) } diff --git a/storagenode/peer.go b/storagenode/peer.go index 3f26a3166..100a7bfdf 100644 --- a/storagenode/peer.go +++ b/storagenode/peer.go @@ -51,7 +51,7 @@ var ( // architecture: Master Database type DB interface { // CreateTables initializes the database - CreateTables() error + CreateTables(ctx context.Context) error // Close closes the database Close() error diff --git a/storagenode/storagenodedb/database.go b/storagenode/storagenodedb/database.go index 30697baa0..bbd42c47a 100644 --- a/storagenode/storagenodedb/database.go +++ b/storagenode/storagenodedb/database.go @@ -6,11 +6,9 @@ package storagenodedb import ( "context" "database/sql" - "database/sql/driver" "fmt" "os" "path/filepath" - "time" _ "github.com/mattn/go-sqlite3" // used indirectly. "github.com/zeebo/errs" @@ -18,6 +16,7 @@ import ( "gopkg.in/spacemonkeygo/monkit.v2" "storj.io/storj/internal/dbutil" + "storj.io/storj/internal/dbutil/sqliteutil" "storj.io/storj/internal/migrate" "storj.io/storj/storage" "storj.io/storj/storage/filestore" @@ -30,6 +29,9 @@ import ( "storj.io/storj/storagenode/storageusage" ) +// VersionTable is the table that stores the version info in each db +const VersionTable = "versions" + var ( mon = monkit.Package() @@ -39,29 +41,10 @@ var ( var _ storagenode.DB = (*DB)(nil) -// SQLDB defines interface that matches *sql.DB -// this is such that we can use utccheck.DB for the backend -// -// TODO: wrap the connector instead of *sql.DB +// SQLDB defines an interface to allow accessing and setting an sql.DB type SQLDB interface { - Begin() (*sql.Tx, error) - BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error) - Close() error - Conn(ctx context.Context) (*sql.Conn, error) - Driver() driver.Driver - Exec(query string, args ...interface{}) (sql.Result, error) - ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) - Ping() error - PingContext(ctx context.Context) error - Prepare(query string) (*sql.Stmt, error) - PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) - Query(query string, args ...interface{}) (*sql.Rows, error) - QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) - QueryRow(query string, args ...interface{}) *sql.Row - QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row - SetConnMaxLifetime(d time.Duration) - SetMaxIdleConns(n int) - SetMaxOpenConns(n int) + Configure(sqlDB *sql.DB) + GetDB() *sql.DB } // Config configures storage node database @@ -96,7 +79,7 @@ type DB struct { usedSerialsDB *usedSerialsDB satellitesDB *satellitesDB - sqlDatabases map[string]*sql.DB + sqlDatabases map[string]SQLDB } // New creates a new master database for storage node @@ -107,23 +90,46 @@ func New(log *zap.Logger, config Config) (*DB, error) { } pieces := filestore.New(log, piecesDir) + deprecatedInfoDB := &deprecatedInfoDB{} + v0PieceInfoDB := &v0PieceInfoDB{} + bandwidthDB := &bandwidthDB{} + ordersDB := &ordersDB{} + pieceExpirationDB := &pieceExpirationDB{} + pieceSpaceUsedDB := &pieceSpaceUsedDB{} + reputationDB := &reputationDB{} + storageUsageDB := &storageUsageDB{} + usedSerialsDB := &usedSerialsDB{} + satellitesDB := &satellitesDB{} + db := &DB{ log: log, pieces: pieces, dbDirectory: filepath.Dir(config.Info2), - sqlDatabases: make(map[string]*sql.DB), - deprecatedInfoDB: &deprecatedInfoDB{}, - v0PieceInfoDB: &v0PieceInfoDB{}, - bandwidthDB: &bandwidthDB{}, - ordersDB: &ordersDB{}, - pieceExpirationDB: &pieceExpirationDB{}, - pieceSpaceUsedDB: &pieceSpaceUsedDB{}, - reputationDB: &reputationDB{}, - storageUsageDB: &storageUsageDB{}, - usedSerialsDB: &usedSerialsDB{}, - satellitesDB: &satellitesDB{}, + deprecatedInfoDB: deprecatedInfoDB, + v0PieceInfoDB: v0PieceInfoDB, + bandwidthDB: bandwidthDB, + ordersDB: ordersDB, + pieceExpirationDB: pieceExpirationDB, + pieceSpaceUsedDB: pieceSpaceUsedDB, + reputationDB: reputationDB, + storageUsageDB: storageUsageDB, + usedSerialsDB: usedSerialsDB, + satellitesDB: satellitesDB, + + sqlDatabases: map[string]SQLDB{ + DeprecatedInfoDBName: deprecatedInfoDB, + PieceInfoDBName: v0PieceInfoDB, + BandwidthDBName: bandwidthDB, + OrdersDBName: ordersDB, + PieceExpirationDBName: pieceExpirationDB, + PieceSpaceUsedDBName: pieceSpaceUsedDB, + ReputationDBName: reputationDB, + StorageUsageDBName: storageUsageDB, + UsedSerialsDBName: usedSerialsDB, + SatellitesDBName: satellitesDB, + }, } err = db.openDatabases() @@ -139,54 +145,95 @@ func (db *DB) openDatabases() error { // that each uses internally to do data access to the SQLite3 databases. // The reason it was done this way was because there's some outside consumers that are // taking a reference to the business object. - deprecatedInfoDB, err := db.openDatabase(DeprecatedInfoDBName) + err := db.openDatabase(DeprecatedInfoDBName) if err != nil { return errs.Combine(err, db.closeDatabases()) } - db.deprecatedInfoDB.Configure(deprecatedInfoDB) - db.bandwidthDB.Configure(deprecatedInfoDB) - db.ordersDB.Configure(deprecatedInfoDB) - db.pieceExpirationDB.Configure(deprecatedInfoDB) - db.v0PieceInfoDB.Configure(deprecatedInfoDB) - db.pieceSpaceUsedDB.Configure(deprecatedInfoDB) - db.reputationDB.Configure(deprecatedInfoDB) - db.storageUsageDB.Configure(deprecatedInfoDB) - db.usedSerialsDB.Configure(deprecatedInfoDB) - db.satellitesDB.Configure(deprecatedInfoDB) + err = db.openDatabase(BandwidthDBName) + if err != nil { + return errs.Combine(err, db.closeDatabases()) + } + + err = db.openDatabase(OrdersDBName) + if err != nil { + return errs.Combine(err, db.closeDatabases()) + } + + err = db.openDatabase(PieceExpirationDBName) + if err != nil { + return errs.Combine(err, db.closeDatabases()) + } + + err = db.openDatabase(PieceInfoDBName) + if err != nil { + return errs.Combine(err, db.closeDatabases()) + } + + err = db.openDatabase(PieceSpaceUsedDBName) + if err != nil { + return errs.Combine(err, db.closeDatabases()) + } + + err = db.openDatabase(ReputationDBName) + if err != nil { + return errs.Combine(err, db.closeDatabases()) + } + + err = db.openDatabase(StorageUsageDBName) + if err != nil { + return errs.Combine(err, db.closeDatabases()) + } + + err = db.openDatabase(UsedSerialsDBName) + if err != nil { + return errs.Combine(err, db.closeDatabases()) + } + + err = db.openDatabase(SatellitesDBName) + if err != nil { + return errs.Combine(err, db.closeDatabases()) + } return nil } +func (db *DB) rawDatabaseFromName(dbName string) *sql.DB { + return db.sqlDatabases[dbName].GetDB() +} + // openDatabase opens or creates a database at the specified path. -func (db *DB) openDatabase(dbName string) (*sql.DB, error) { - path := filepath.Join(db.dbDirectory, db.FilenameFromDBName(dbName)) +func (db *DB) openDatabase(dbName string) error { + path := db.filepathFromDBName(dbName) if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil { - return nil, err + return ErrDatabase.Wrap(err) } sqlDB, err := sql.Open("sqlite3", "file:"+path+"?_journal=WAL&_busy_timeout=10000") if err != nil { - return nil, ErrDatabase.Wrap(err) + return ErrDatabase.Wrap(err) } - // This isn't safe for concurrent access but we don't currently access this map concurrently. - // If we do in the future it needs some protection. - db.sqlDatabases[dbName] = sqlDB + mDB := db.sqlDatabases[dbName] + mDB.Configure(sqlDB) dbutil.Configure(sqlDB, mon) db.log.Debug(fmt.Sprintf("opened database %s", dbName)) - return sqlDB, nil + return nil } -// FilenameFromDBName returns a constructed filename for the specified database name. -func (db *DB) FilenameFromDBName(dbName string) string { +// filenameFromDBName returns a constructed filename for the specified database name. +func (db *DB) filenameFromDBName(dbName string) string { return dbName + ".db" } +func (db *DB) filepathFromDBName(dbName string) string { + return filepath.Join(db.dbDirectory, db.filenameFromDBName(dbName)) +} + // CreateTables creates any necessary tables. -func (db *DB) CreateTables() error { - migration := db.Migration() +func (db *DB) CreateTables(ctx context.Context) error { + migration := db.Migration(ctx) return migration.Run(db.log.Named("migration")) } @@ -207,17 +254,11 @@ func (db *DB) closeDatabases() error { // closeDatabase closes the specified SQLite database connections and removes them from the associated maps. func (db *DB) closeDatabase(dbName string) (err error) { - conn, ok := db.sqlDatabases[dbName] + mdb, ok := db.sqlDatabases[dbName] if !ok { - return ErrDatabase.New("double close on database %s", dbName) + return ErrDatabase.New("no database with name %s found. database was never opened or already closed.", dbName) } - delete(db.sqlDatabases, dbName) - return ErrDatabase.Wrap(conn.Close()) -} - -// DeprecatedInfoDB returns the instance of the versions database. -func (db *DB) DeprecatedInfoDB() SQLDB { - return db.deprecatedInfoDB + return ErrDatabase.Wrap(mdb.GetDB().Close()) } // V0PieceInfo returns the instance of the V0PieceInfoDB database. @@ -267,24 +308,57 @@ func (db *DB) UsedSerials() piecestore.UsedSerials { // RawDatabases are required for testing purposes func (db *DB) RawDatabases() map[string]SQLDB { - return map[string]SQLDB{ - BandwidthDBName: db.bandwidthDB, - OrdersDBName: db.ordersDB, - PieceExpirationDBName: db.pieceExpirationDB, - PieceSpaceUsedDBName: db.pieceSpaceUsedDB, - ReputationDBName: db.reputationDB, - StorageUsageDBName: db.storageUsageDB, - UsedSerialsDBName: db.usedSerialsDB, - PieceInfoDBName: db.v0PieceInfoDB, - DeprecatedInfoDBName: db.deprecatedInfoDB, - SatellitesDBName: db.satellitesDB, + return db.sqlDatabases +} + +// migrateToDB is a helper method that performs the migration from the +// deprecatedInfoDB to the specified new db. It first closes and deletes any +// existing database to guarantee idempotence. After migration it also closes +// and re-opens the new database to allow the system to recover used disk space. +func (db *DB) migrateToDB(ctx context.Context, dbName string, tablesToKeep ...string) error { + err := db.closeDatabase(dbName) + if err != nil { + return ErrDatabase.Wrap(err) } + + path := db.filepathFromDBName(dbName) + + if _, err := os.Stat(path); err == nil { + err = os.Remove(path) + if err != nil { + return ErrDatabase.Wrap(err) + } + } + + err = db.openDatabase(dbName) + if err != nil { + return ErrDatabase.Wrap(err) + } + + err = sqliteutil.MigrateTablesToDatabase(ctx, db.rawDatabaseFromName(DeprecatedInfoDBName), db.rawDatabaseFromName(dbName), tablesToKeep...) + if err != nil { + return ErrDatabase.Wrap(err) + } + + // We need to close and re-open the database we have just migrated *to* in + // order to recover any excess disk usage that was freed in the VACUUM call + err = db.closeDatabase(dbName) + if err != nil { + return ErrDatabase.Wrap(err) + } + + err = db.openDatabase(dbName) + if err != nil { + return ErrDatabase.Wrap(err) + } + + return nil } // Migration returns table migrations. -func (db *DB) Migration() *migrate.Migration { +func (db *DB) Migration(ctx context.Context) *migrate.Migration { return &migrate.Migration{ - Table: "versions", + Table: VersionTable, Steps: []*migrate.Step{ { DB: db.deprecatedInfoDB, @@ -690,6 +764,71 @@ func (db *DB) Migration() *migrate.Migration { )`, }, }, + { + DB: db.deprecatedInfoDB, + Description: "Split into multiple sqlite databases", + Version: 22, + Action: migrate.Func(func(log *zap.Logger, _ migrate.DB, tx *sql.Tx) error { + // Migrate all the tables to new database files. + if err := db.migrateToDB(ctx, BandwidthDBName, "bandwidth_usage", "bandwidth_usage_rollups"); err != nil { + return ErrDatabase.Wrap(err) + } + if err := db.migrateToDB(ctx, OrdersDBName, "unsent_order", "order_archive_"); err != nil { + return ErrDatabase.Wrap(err) + } + if err := db.migrateToDB(ctx, PieceExpirationDBName, "piece_expirations"); err != nil { + return ErrDatabase.Wrap(err) + } + if err := db.migrateToDB(ctx, PieceInfoDBName, "pieceinfo_"); err != nil { + return ErrDatabase.Wrap(err) + } + if err := db.migrateToDB(ctx, PieceSpaceUsedDBName, "piece_space_used"); err != nil { + return ErrDatabase.Wrap(err) + } + if err := db.migrateToDB(ctx, ReputationDBName, "reputation"); err != nil { + return ErrDatabase.Wrap(err) + } + if err := db.migrateToDB(ctx, StorageUsageDBName, "storage_usage"); err != nil { + return ErrDatabase.Wrap(err) + } + if err := db.migrateToDB(ctx, UsedSerialsDBName, "used_serial_"); err != nil { + return ErrDatabase.Wrap(err) + } + if err := db.migrateToDB(ctx, SatellitesDBName, "satellites", "satellite_exit_progress"); err != nil { + return ErrDatabase.Wrap(err) + } + + return nil + }), + }, + { + DB: db.deprecatedInfoDB, + Description: "Drop unneeded tables in deprecatedInfoDB", + Version: 23, + Action: migrate.Func(func(log *zap.Logger, _ migrate.DB, tx *sql.Tx) error { + // We drop the migrated tables from the deprecated database and VACUUM SQLite3 + // in migration step 23 because if we were to keep that as part of step 22 + // and an error occurred it would replay the entire migration but some tables + // may have successfully dropped and we would experience unrecoverable data loss. + // This way if step 22 completes it never gets replayed even if a drop table or + // VACUUM call fails. + if err := sqliteutil.KeepTables(ctx, db.rawDatabaseFromName(DeprecatedInfoDBName), VersionTable); err != nil { + return ErrDatabase.Wrap(err) + } + + // Close the deprecated db in order to free up unused + // disk space + if err := db.closeDatabase(DeprecatedInfoDBName); err != nil { + return ErrDatabase.Wrap(err) + } + + if err := db.openDatabase(DeprecatedInfoDBName); err != nil { + return ErrDatabase.Wrap(err) + } + + return nil + }), + }, }, } } diff --git a/storagenode/storagenodedb/migratableDB.go b/storagenode/storagenodedb/migratableDB.go index 2897b9407..a54932f7c 100644 --- a/storagenode/storagenodedb/migratableDB.go +++ b/storagenode/storagenodedb/migratableDB.go @@ -3,8 +3,13 @@ package storagenodedb +import ( + "database/sql" +) + +// migratableDB fulfills the migrate.DB interface and the SQLDB interface type migratableDB struct { - SQLDB + *sql.DB } // Schema returns schema @@ -22,6 +27,11 @@ func (db *migratableDB) Rebind(s string) string { } // Configure sets the underlining SQLDB connection. -func (db *migratableDB) Configure(sqlDB SQLDB) { - db.SQLDB = sqlDB +func (db *migratableDB) Configure(sqlDB *sql.DB) { + db.DB = sqlDB +} + +// GetDB returns the raw *sql.DB underlying this migratableDB +func (db *migratableDB) GetDB() *sql.DB { + return db.DB } diff --git a/storagenode/storagenodedb/migrations_test.go b/storagenode/storagenodedb/migrations_test.go index bc07a8474..ea1033fc0 100644 --- a/storagenode/storagenodedb/migrations_test.go +++ b/storagenode/storagenodedb/migrations_test.go @@ -32,7 +32,7 @@ func insertNewData(mdbs *testdata.MultiDBState, rawDBs map[string]storagenodedb. if !ok { return errs.New("Failed to find DB %s", dbName) } - _, err := rawDB.Exec(dbState.NewData) + _, err := rawDB.GetDB().Exec(dbState.NewData) if err != nil { return err } @@ -45,7 +45,7 @@ func insertNewData(mdbs *testdata.MultiDBState, rawDBs map[string]storagenodedb. func getSchemas(rawDBs map[string]storagenodedb.SQLDB) (map[string]*dbschema.Schema, error) { schemas := make(map[string]*dbschema.Schema) for dbName, rawDB := range rawDBs { - schema, err := sqliteutil.QuerySchema(rawDB) + schema, err := sqliteutil.QuerySchema(rawDB.GetDB()) if err != nil { return nil, err } @@ -63,7 +63,7 @@ func getSchemas(rawDBs map[string]storagenodedb.SQLDB) (map[string]*dbschema.Sch func getData(rawDBs map[string]storagenodedb.SQLDB, schemas map[string]*dbschema.Schema) (map[string]*dbschema.Data, error) { data := make(map[string]*dbschema.Data) for dbName, rawDB := range rawDBs { - datum, err := sqliteutil.QueryData(rawDB, schemas[dbName]) + datum, err := sqliteutil.QueryData(rawDB.GetDB(), schemas[dbName]) if err != nil { return nil, err } @@ -91,10 +91,8 @@ func TestMigrate(t *testing.T) { require.NoError(t, err) defer func() { require.NoError(t, db.Close()) }() - rawDBs := db.RawDatabases() - // get migration for this database - migrations := db.Migration() + migrations := db.Migration(ctx) for i, step := range migrations.Steps { // the schema is different when migration step is before the step, cannot test the layout tag := fmt.Sprintf("#%d - v%d", i, step.Version) @@ -107,6 +105,8 @@ func TestMigrate(t *testing.T) { expected, ok := testdata.States.FindVersion(step.Version) require.True(t, ok) + rawDBs := db.RawDatabases() + // insert data for new tables err = insertNewData(expected, rawDBs) require.NoError(t, err, tag) diff --git a/storagenode/storagenodedb/storagenodedbtest/run.go b/storagenode/storagenodedb/storagenodedbtest/run.go index 8558f06ce..c0e2faefa 100644 --- a/storagenode/storagenodedb/storagenodedbtest/run.go +++ b/storagenode/storagenodedb/storagenodedbtest/run.go @@ -40,7 +40,7 @@ func Run(t *testing.T, test func(t *testing.T, db storagenode.DB)) { } defer ctx.Check(db.Close) - err = db.CreateTables() + err = db.CreateTables(ctx) if err != nil { t.Fatal(err) } diff --git a/storagenode/storagenodedb/storagenodedbtest/run_test.go b/storagenode/storagenodedb/storagenodedbtest/run_test.go index cf5fae156..a34a36e0d 100644 --- a/storagenode/storagenodedb/storagenodedbtest/run_test.go +++ b/storagenode/storagenodedb/storagenodedbtest/run_test.go @@ -76,7 +76,7 @@ func testConcurrency(t *testing.T, ctx *testcontext.Context, db *storagenodedb.D t.Run("Sqlite", func(t *testing.T) { runtime.GOMAXPROCS(2) - err := db.CreateTables() + err := db.CreateTables(ctx) if err != nil { t.Fatal(err) } diff --git a/storagenode/storagenodedb/testdata/multidbsnapshot.go b/storagenode/storagenodedb/testdata/multidbsnapshot.go index 030e667d9..48f46c3c4 100644 --- a/storagenode/storagenodedb/testdata/multidbsnapshot.go +++ b/storagenode/storagenodedb/testdata/multidbsnapshot.go @@ -35,6 +35,8 @@ var States = MultiDBStates{ &v19, &v20, &v21, + &v22, + &v23, }, } diff --git a/storagenode/storagenodedb/testdata/v21.go b/storagenode/storagenodedb/testdata/v21.go index b9e398cea..605cb681d 100644 --- a/storagenode/storagenodedb/testdata/v21.go +++ b/storagenode/storagenodedb/testdata/v21.go @@ -212,8 +212,8 @@ var v21 = MultiDBState{ INSERT INTO storage_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',5.0,'2019-07-19 20:00:00+00:00'); `, NewData: ` - INSERT INTO satellites VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000','127.0.0.1:55516','2019-09-10 20:00:00+00:00', 0); - INSERT INTO satellite_exit_progress VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000','2019-09-10 20:00:00+00:00', null, 100, 0, null); + INSERT INTO satellites VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000','127.0.0.1:55516','2019-09-10 20:00:00+00:00', 0); + INSERT INTO satellite_exit_progress VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000','2019-09-10 20:00:00+00:00', null, 100, 0, null); `, }, }, diff --git a/storagenode/storagenodedb/testdata/v22.go b/storagenode/storagenodedb/testdata/v22.go new file mode 100644 index 000000000..24af96e37 --- /dev/null +++ b/storagenode/storagenodedb/testdata/v22.go @@ -0,0 +1,425 @@ +// Copyright (C) 2019 Storj Labs, Inc. +// See LICENSE for copying information. + +package testdata + +import "storj.io/storj/storagenode/storagenodedb" + +var v22 = MultiDBState{ + Version: 22, + DBStates: DBStates{ + storagenodedb.UsedSerialsDBName: &DBState{ + SQL: ` + -- table for keeping serials that need to be verified against + CREATE TABLE used_serial_ ( + satellite_id BLOB NOT NULL, + serial_number BLOB NOT NULL, + expiration TIMESTAMP NOT NULL + ); + -- primary key on satellite id and serial number + CREATE UNIQUE INDEX pk_used_serial_ ON used_serial_(satellite_id, serial_number); + -- expiration index to allow fast deletion + CREATE INDEX idx_used_serial_ ON used_serial_(expiration); + `, + }, + storagenodedb.StorageUsageDBName: &DBState{ + SQL: ` + CREATE TABLE storage_usage ( + satellite_id BLOB NOT NULL, + at_rest_total REAL NOT NUll, + interval_start TIMESTAMP NOT NULL, + PRIMARY KEY (satellite_id, interval_start) + ); + INSERT INTO storage_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',5.0,'2019-07-19 20:00:00+00:00'); + `, + }, + storagenodedb.ReputationDBName: &DBState{ + SQL: ` + -- tables to store nodestats cache + CREATE TABLE reputation ( + satellite_id BLOB NOT NULL, + uptime_success_count INTEGER NOT NULL, + uptime_total_count INTEGER NOT NULL, + uptime_reputation_alpha REAL NOT NULL, + uptime_reputation_beta REAL NOT NULL, + uptime_reputation_score REAL NOT NULL, + audit_success_count INTEGER NOT NULL, + audit_total_count INTEGER NOT NULL, + audit_reputation_alpha REAL NOT NULL, + audit_reputation_beta REAL NOT NULL, + audit_reputation_score REAL NOT NULL, + disqualified TIMESTAMP, + updated_at TIMESTAMP NOT NULL, + PRIMARY KEY (satellite_id) + ); + INSERT INTO reputation VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',1,1,1.0,1.0,1.0,1,1,1.0,1.0,1.0,'2019-07-19 20:00:00+00:00','2019-08-23 20:00:00+00:00'); + `, + }, + storagenodedb.PieceSpaceUsedDBName: &DBState{ + SQL: ` + CREATE TABLE piece_space_used ( + total INTEGER NOT NULL, + satellite_id BLOB + ); + CREATE UNIQUE INDEX idx_piece_space_used_satellite_id ON piece_space_used(satellite_id); + INSERT INTO piece_space_used (total) VALUES (1337); + INSERT INTO piece_space_used (total, satellite_id) VALUES (1337, X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000'); + `, + }, + storagenodedb.PieceInfoDBName: &DBState{ + SQL: ` + -- table for storing piece meta info + CREATE TABLE pieceinfo_ ( + satellite_id BLOB NOT NULL, + piece_id BLOB NOT NULL, + piece_size BIGINT NOT NULL, + piece_expiration TIMESTAMP, + order_limit BLOB NOT NULL, + uplink_piece_hash BLOB NOT NULL, + uplink_cert_id INTEGER NOT NULL, + deletion_failed_at TIMESTAMP, + piece_creation TIMESTAMP NOT NULL, + FOREIGN KEY(uplink_cert_id) REFERENCES certificate(cert_id) + ); + -- primary key by satellite id and piece id + CREATE UNIQUE INDEX pk_pieceinfo_ ON pieceinfo_(satellite_id, piece_id); + -- fast queries for expiration for pieces that have one + CREATE INDEX idx_pieceinfo__expiration ON pieceinfo_(piece_expiration) WHERE piece_expiration IS NOT NULL; + INSERT INTO pieceinfo_ VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',X'd5e757fd8d207d1c46583fb58330f803dc961b71147308ff75ff1e72a0df6b0b',1000,'2019-05-09 00:00:00.000000+00:00', X'', X'0a20d5e757fd8d207d1c46583fb58330f803dc961b71147308ff75ff1e72a0df6b0b120501020304051a47304502201c16d76ecd9b208f7ad9f1edf66ce73dce50da6bde6bbd7d278415099a727421022100ca730450e7f6506c2647516f6e20d0641e47c8270f58dde2bb07d1f5a3a45673',1,NULL,'epoch'); + INSERT INTO pieceinfo_ VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',X'd5e757fd8d207d1c46583fb58330f803dc961b71147308ff75ff1e72a0df6b0b',337,'2019-05-09 00:00:00.000000+00:00', X'', X'0a20d5e757fd8d207d1c46583fb58330f803dc961b71147308ff75ff1e72a0df6b0b120501020304051a483046022100e623cf4705046e2c04d5b42d5edbecb81f000459713ad460c691b3361817adbf022100993da2a5298bb88de6c35b2e54009d1bf306cda5d441c228aa9eaf981ceb0f3d',2,NULL,'epoch'); + `, + }, + storagenodedb.PieceExpirationDBName: &DBState{ + SQL: ` + -- table to hold expiration data (and only expirations. no other pieceinfo) + CREATE TABLE piece_expirations ( + satellite_id BLOB NOT NULL, + piece_id BLOB NOT NULL, + piece_expiration TIMESTAMP NOT NULL, -- date when it can be deleted + deletion_failed_at TIMESTAMP, + PRIMARY KEY ( satellite_id, piece_id ) + ); + CREATE INDEX idx_piece_expirations_piece_expiration ON piece_expirations(piece_expiration); + CREATE INDEX idx_piece_expirations_deletion_failed_at ON piece_expirations(deletion_failed_at); + `, + }, + storagenodedb.OrdersDBName: &DBState{ + SQL: ` + -- table for storing all unsent orders + CREATE TABLE unsent_order ( + satellite_id BLOB NOT NULL, + serial_number BLOB NOT NULL, + order_limit_serialized BLOB NOT NULL, + order_serialized BLOB NOT NULL, + order_limit_expiration TIMESTAMP NOT NULL, + uplink_cert_id INTEGER NOT NULL, + FOREIGN KEY(uplink_cert_id) REFERENCES certificate(cert_id) + ); + CREATE UNIQUE INDEX idx_orders ON unsent_order(satellite_id, serial_number); + -- table for storing all sent orders + CREATE TABLE order_archive_ ( + satellite_id BLOB NOT NULL, + serial_number BLOB NOT NULL, + order_limit_serialized BLOB NOT NULL, + order_serialized BLOB NOT NULL, + uplink_cert_id INTEGER NOT NULL, + status INTEGER NOT NULL, + archived_at TIMESTAMP NOT NULL, + FOREIGN KEY(uplink_cert_id) REFERENCES certificate(cert_id) + ); + INSERT INTO unsent_order VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',X'1eddef484b4c03f01332279032796972',X'0a101eddef484b4c03f0133227903279697212202b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf410001a201968996e7ef170a402fdfd88b6753df792c063c07c555905ffac9cd3cbd1c00022200ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac30002a20d00cf14f3c68b56321ace04902dec0484eb6f9098b22b31c6b3f82db249f191630643802420c08dfeb88e50510a8c1a5b9034a0c08dfeb88e50510a8c1a5b9035246304402204df59dc6f5d1bb7217105efbc9b3604d19189af37a81efbf16258e5d7db5549e02203bb4ead16e6e7f10f658558c22b59c3339911841e8dbaae6e2dea821f7326894',X'0a101eddef484b4c03f0133227903279697210321a47304502206d4c106ddec88140414bac5979c95bdea7de2e0ecc5be766e08f7d5ea36641a7022100e932ff858f15885ffa52d07e260c2c25d3861810ea6157956c1793ad0c906284','2019-04-01 16:01:35.9254586+00:00',1); + `, + }, + storagenodedb.BandwidthDBName: &DBState{ + SQL: ` + -- table for storing bandwidth usage + CREATE TABLE bandwidth_usage ( + satellite_id BLOB NOT NULL, + action INTEGER NOT NULL, + amount BIGINT NOT NULL, + created_at TIMESTAMP NOT NULL + ); + CREATE INDEX idx_bandwidth_usage_satellite ON bandwidth_usage(satellite_id); + CREATE INDEX idx_bandwidth_usage_created ON bandwidth_usage(created_at); + CREATE TABLE bandwidth_usage_rollups ( + interval_start TIMESTAMP NOT NULL, + satellite_id BLOB NOT NULL, + action INTEGER NOT NULL, + amount BIGINT NOT NULL, + PRIMARY KEY ( interval_start, satellite_id, action ) + ); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',0,0,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',0,0,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',1,1,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',1,1,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',2,2,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',2,2,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',3,3,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',3,3,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',4,4,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',4,4,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',5,5,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',5,5,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',6,6,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',6,6,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',1,1,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',1,1,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',2,2,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',2,2,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',3,3,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',3,3,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',4,4,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',4,4,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',5,5,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',5,5,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',6,6,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',6,6,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',0,0); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',0,0); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',1,1); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',1,1); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',2,2); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',2,2); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',3,3); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',3,3); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',4,4); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',4,4); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',5,5); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',5,5); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',6,6); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',6,6); + `, + }, + storagenodedb.SatellitesDBName: &DBState{ + SQL: ` + CREATE TABLE satellites ( + node_id BLOB NOT NULL, + address TEXT NOT NUll, + added_at TIMESTAMP NOT NULL, + status INTEGER NOT NULL, + PRIMARY KEY (node_id) + ); + + CREATE TABLE satellite_exit_progress ( + satellite_id BLOB NOT NULL, + initiated_at TIMESTAMP, + finished_at TIMESTAMP, + starting_disk_usage INTEGER NOT NULL, + bytes_deleted INTEGER NOT NULL, + completion_receipt BLOB, + PRIMARY KEY (satellite_id) + ); + + INSERT INTO satellites VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000','127.0.0.1:55516','2019-09-10 20:00:00+00:00', 0); + INSERT INTO satellite_exit_progress VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000','2019-09-10 20:00:00+00:00', null, 100, 0, null); + `, + }, + storagenodedb.DeprecatedInfoDBName: &DBState{ + SQL: ` + -- table for keeping serials that need to be verified against + CREATE TABLE used_serial_ ( + satellite_id BLOB NOT NULL, + serial_number BLOB NOT NULL, + expiration TIMESTAMP NOT NULL + ); + -- primary key on satellite id and serial number + CREATE UNIQUE INDEX pk_used_serial_ ON used_serial_(satellite_id, serial_number); + -- expiration index to allow fast deletion + CREATE INDEX idx_used_serial_ ON used_serial_(expiration); + + -- certificate table for storing uplink/satellite certificates + CREATE TABLE certificate ( + cert_id INTEGER + ); + + -- table for storing piece meta info + CREATE TABLE pieceinfo_ ( + satellite_id BLOB NOT NULL, + piece_id BLOB NOT NULL, + piece_size BIGINT NOT NULL, + piece_expiration TIMESTAMP, + + order_limit BLOB NOT NULL, + uplink_piece_hash BLOB NOT NULL, + uplink_cert_id INTEGER NOT NULL, + + deletion_failed_at TIMESTAMP, + piece_creation TIMESTAMP NOT NULL, + + FOREIGN KEY(uplink_cert_id) REFERENCES certificate(cert_id) + ); + -- primary key by satellite id and piece id + CREATE UNIQUE INDEX pk_pieceinfo_ ON pieceinfo_(satellite_id, piece_id); + -- fast queries for expiration for pieces that have one + CREATE INDEX idx_pieceinfo__expiration ON pieceinfo_(piece_expiration) WHERE piece_expiration IS NOT NULL; + + -- table for storing bandwidth usage + CREATE TABLE bandwidth_usage ( + satellite_id BLOB NOT NULL, + action INTEGER NOT NULL, + amount BIGINT NOT NULL, + created_at TIMESTAMP NOT NULL + ); + CREATE INDEX idx_bandwidth_usage_satellite ON bandwidth_usage(satellite_id); + CREATE INDEX idx_bandwidth_usage_created ON bandwidth_usage(created_at); + + -- table for storing all unsent orders + CREATE TABLE unsent_order ( + satellite_id BLOB NOT NULL, + serial_number BLOB NOT NULL, + + order_limit_serialized BLOB NOT NULL, + order_serialized BLOB NOT NULL, + order_limit_expiration TIMESTAMP NOT NULL, + + uplink_cert_id INTEGER NOT NULL, + + FOREIGN KEY(uplink_cert_id) REFERENCES certificate(cert_id) + ); + CREATE UNIQUE INDEX idx_orders ON unsent_order(satellite_id, serial_number); + + -- table for storing all sent orders + CREATE TABLE order_archive_ ( + satellite_id BLOB NOT NULL, + serial_number BLOB NOT NULL, + + order_limit_serialized BLOB NOT NULL, + order_serialized BLOB NOT NULL, + + uplink_cert_id INTEGER NOT NULL, + + status INTEGER NOT NULL, + archived_at TIMESTAMP NOT NULL, + + FOREIGN KEY(uplink_cert_id) REFERENCES certificate(cert_id) + ); + + CREATE TABLE bandwidth_usage_rollups ( + interval_start TIMESTAMP NOT NULL, + satellite_id BLOB NOT NULL, + action INTEGER NOT NULL, + amount BIGINT NOT NULL, + PRIMARY KEY ( interval_start, satellite_id, action ) + ); + + -- table to hold expiration data (and only expirations. no other pieceinfo) + CREATE TABLE piece_expirations ( + satellite_id BLOB NOT NULL, + piece_id BLOB NOT NULL, + piece_expiration TIMESTAMP NOT NULL, -- date when it can be deleted + deletion_failed_at TIMESTAMP, + PRIMARY KEY ( satellite_id, piece_id ) + ); + CREATE INDEX idx_piece_expirations_piece_expiration ON piece_expirations(piece_expiration); + CREATE INDEX idx_piece_expirations_deletion_failed_at ON piece_expirations(deletion_failed_at); + + -- tables to store nodestats cache + CREATE TABLE reputation ( + satellite_id BLOB NOT NULL, + uptime_success_count INTEGER NOT NULL, + uptime_total_count INTEGER NOT NULL, + uptime_reputation_alpha REAL NOT NULL, + uptime_reputation_beta REAL NOT NULL, + uptime_reputation_score REAL NOT NULL, + audit_success_count INTEGER NOT NULL, + audit_total_count INTEGER NOT NULL, + audit_reputation_alpha REAL NOT NULL, + audit_reputation_beta REAL NOT NULL, + audit_reputation_score REAL NOT NULL, + disqualified TIMESTAMP, + updated_at TIMESTAMP NOT NULL, + PRIMARY KEY (satellite_id) + ); + + CREATE TABLE storage_usage ( + satellite_id BLOB NOT NULL, + at_rest_total REAL NOT NUll, + interval_start TIMESTAMP NOT NULL, + PRIMARY KEY (satellite_id, interval_start) + ); + + CREATE TABLE piece_space_used ( + total INTEGER NOT NULL, + satellite_id BLOB + ); + + CREATE TABLE satellites ( + node_id BLOB NOT NULL, + address TEXT NOT NUll, + added_at TIMESTAMP NOT NULL, + status INTEGER NOT NULL, + PRIMARY KEY (node_id) + ); + + CREATE TABLE satellite_exit_progress ( + satellite_id BLOB NOT NULL, + initiated_at TIMESTAMP, + finished_at TIMESTAMP, + starting_disk_usage INTEGER NOT NULL, + bytes_deleted INTEGER NOT NULL, + completion_receipt BLOB, + PRIMARY KEY (satellite_id) + ); + CREATE UNIQUE INDEX idx_piece_space_used_satellite_id ON piece_space_used(satellite_id); + + INSERT INTO unsent_order VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',X'1eddef484b4c03f01332279032796972',X'0a101eddef484b4c03f0133227903279697212202b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf410001a201968996e7ef170a402fdfd88b6753df792c063c07c555905ffac9cd3cbd1c00022200ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac30002a20d00cf14f3c68b56321ace04902dec0484eb6f9098b22b31c6b3f82db249f191630643802420c08dfeb88e50510a8c1a5b9034a0c08dfeb88e50510a8c1a5b9035246304402204df59dc6f5d1bb7217105efbc9b3604d19189af37a81efbf16258e5d7db5549e02203bb4ead16e6e7f10f658558c22b59c3339911841e8dbaae6e2dea821f7326894',X'0a101eddef484b4c03f0133227903279697210321a47304502206d4c106ddec88140414bac5979c95bdea7de2e0ecc5be766e08f7d5ea36641a7022100e932ff858f15885ffa52d07e260c2c25d3861810ea6157956c1793ad0c906284','2019-04-01 16:01:35.9254586+00:00',1); + + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',0,0,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',0,0,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',1,1,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',1,1,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',2,2,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',2,2,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',3,3,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',3,3,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',4,4,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',4,4,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',5,5,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',5,5,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',6,6,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',6,6,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',1,1,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',1,1,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',2,2,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',2,2,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',3,3,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',3,3,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',4,4,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',4,4,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',5,5,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',5,5,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',6,6,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',6,6,'2019-04-01 20:51:24.1074772+00:00'); + + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',0,0); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',0,0); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',1,1); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',1,1); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',2,2); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',2,2); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',3,3); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',3,3); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',4,4); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',4,4); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',5,5); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',5,5); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',6,6); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',6,6); + + INSERT INTO pieceinfo_ VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',X'd5e757fd8d207d1c46583fb58330f803dc961b71147308ff75ff1e72a0df6b0b',1000,'2019-05-09 00:00:00.000000+00:00', X'', X'0a20d5e757fd8d207d1c46583fb58330f803dc961b71147308ff75ff1e72a0df6b0b120501020304051a47304502201c16d76ecd9b208f7ad9f1edf66ce73dce50da6bde6bbd7d278415099a727421022100ca730450e7f6506c2647516f6e20d0641e47c8270f58dde2bb07d1f5a3a45673',1,NULL,'epoch'); + INSERT INTO pieceinfo_ VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',X'd5e757fd8d207d1c46583fb58330f803dc961b71147308ff75ff1e72a0df6b0b',337,'2019-05-09 00:00:00.000000+00:00', X'', X'0a20d5e757fd8d207d1c46583fb58330f803dc961b71147308ff75ff1e72a0df6b0b120501020304051a483046022100e623cf4705046e2c04d5b42d5edbecb81f000459713ad460c691b3361817adbf022100993da2a5298bb88de6c35b2e54009d1bf306cda5d441c228aa9eaf981ceb0f3d',2,NULL,'epoch'); + + INSERT INTO piece_space_used (total) VALUES (1337); + + INSERT INTO piece_space_used (total, satellite_id) VALUES (1337, X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000'); + + INSERT INTO reputation VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',1,1,1.0,1.0,1.0,1,1,1.0,1.0,1.0,'2019-07-19 20:00:00+00:00','2019-08-23 20:00:00+00:00'); + + INSERT INTO storage_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',5.0,'2019-07-19 20:00:00+00:00'); + + INSERT INTO satellites VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000','127.0.0.1:55516','2019-09-10 20:00:00+00:00', 0); + INSERT INTO satellite_exit_progress VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000','2019-09-10 20:00:00+00:00', null, 100, 0, null); + `, + }, + }, +} diff --git a/storagenode/storagenodedb/testdata/v23.go b/storagenode/storagenodedb/testdata/v23.go new file mode 100644 index 000000000..4bdd6f23f --- /dev/null +++ b/storagenode/storagenodedb/testdata/v23.go @@ -0,0 +1,221 @@ +// Copyright (C) 2019 Storj Labs, Inc. +// See LICENSE for copying information. + +package testdata + +import "storj.io/storj/storagenode/storagenodedb" + +var v23 = MultiDBState{ + Version: 23, + DBStates: DBStates{ + storagenodedb.UsedSerialsDBName: &DBState{ + SQL: ` + -- table for keeping serials that need to be verified against + CREATE TABLE used_serial_ ( + satellite_id BLOB NOT NULL, + serial_number BLOB NOT NULL, + expiration TIMESTAMP NOT NULL + ); + -- primary key on satellite id and serial number + CREATE UNIQUE INDEX pk_used_serial_ ON used_serial_(satellite_id, serial_number); + -- expiration index to allow fast deletion + CREATE INDEX idx_used_serial_ ON used_serial_(expiration); + `, + }, + storagenodedb.StorageUsageDBName: &DBState{ + SQL: ` + CREATE TABLE storage_usage ( + satellite_id BLOB NOT NULL, + at_rest_total REAL NOT NUll, + interval_start TIMESTAMP NOT NULL, + PRIMARY KEY (satellite_id, interval_start) + ); + INSERT INTO storage_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',5.0,'2019-07-19 20:00:00+00:00'); + `, + }, + storagenodedb.ReputationDBName: &DBState{ + SQL: ` + -- tables to store nodestats cache + CREATE TABLE reputation ( + satellite_id BLOB NOT NULL, + uptime_success_count INTEGER NOT NULL, + uptime_total_count INTEGER NOT NULL, + uptime_reputation_alpha REAL NOT NULL, + uptime_reputation_beta REAL NOT NULL, + uptime_reputation_score REAL NOT NULL, + audit_success_count INTEGER NOT NULL, + audit_total_count INTEGER NOT NULL, + audit_reputation_alpha REAL NOT NULL, + audit_reputation_beta REAL NOT NULL, + audit_reputation_score REAL NOT NULL, + disqualified TIMESTAMP, + updated_at TIMESTAMP NOT NULL, + PRIMARY KEY (satellite_id) + ); + INSERT INTO reputation VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',1,1,1.0,1.0,1.0,1,1,1.0,1.0,1.0,'2019-07-19 20:00:00+00:00','2019-08-23 20:00:00+00:00'); + `, + }, + storagenodedb.PieceSpaceUsedDBName: &DBState{ + SQL: ` + CREATE TABLE piece_space_used ( + total INTEGER NOT NULL, + satellite_id BLOB + ); + CREATE UNIQUE INDEX idx_piece_space_used_satellite_id ON piece_space_used(satellite_id); + INSERT INTO piece_space_used (total) VALUES (1337); + INSERT INTO piece_space_used (total, satellite_id) VALUES (1337, X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000'); + `, + }, + storagenodedb.PieceInfoDBName: &DBState{ + SQL: ` + -- table for storing piece meta info + CREATE TABLE pieceinfo_ ( + satellite_id BLOB NOT NULL, + piece_id BLOB NOT NULL, + piece_size BIGINT NOT NULL, + piece_expiration TIMESTAMP, + order_limit BLOB NOT NULL, + uplink_piece_hash BLOB NOT NULL, + uplink_cert_id INTEGER NOT NULL, + deletion_failed_at TIMESTAMP, + piece_creation TIMESTAMP NOT NULL, + FOREIGN KEY(uplink_cert_id) REFERENCES certificate(cert_id) + ); + -- primary key by satellite id and piece id + CREATE UNIQUE INDEX pk_pieceinfo_ ON pieceinfo_(satellite_id, piece_id); + -- fast queries for expiration for pieces that have one + CREATE INDEX idx_pieceinfo__expiration ON pieceinfo_(piece_expiration) WHERE piece_expiration IS NOT NULL; + INSERT INTO pieceinfo_ VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',X'd5e757fd8d207d1c46583fb58330f803dc961b71147308ff75ff1e72a0df6b0b',1000,'2019-05-09 00:00:00.000000+00:00', X'', X'0a20d5e757fd8d207d1c46583fb58330f803dc961b71147308ff75ff1e72a0df6b0b120501020304051a47304502201c16d76ecd9b208f7ad9f1edf66ce73dce50da6bde6bbd7d278415099a727421022100ca730450e7f6506c2647516f6e20d0641e47c8270f58dde2bb07d1f5a3a45673',1,NULL,'epoch'); + INSERT INTO pieceinfo_ VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',X'd5e757fd8d207d1c46583fb58330f803dc961b71147308ff75ff1e72a0df6b0b',337,'2019-05-09 00:00:00.000000+00:00', X'', X'0a20d5e757fd8d207d1c46583fb58330f803dc961b71147308ff75ff1e72a0df6b0b120501020304051a483046022100e623cf4705046e2c04d5b42d5edbecb81f000459713ad460c691b3361817adbf022100993da2a5298bb88de6c35b2e54009d1bf306cda5d441c228aa9eaf981ceb0f3d',2,NULL,'epoch'); + `, + }, + storagenodedb.PieceExpirationDBName: &DBState{ + SQL: ` + -- table to hold expiration data (and only expirations. no other pieceinfo) + CREATE TABLE piece_expirations ( + satellite_id BLOB NOT NULL, + piece_id BLOB NOT NULL, + piece_expiration TIMESTAMP NOT NULL, -- date when it can be deleted + deletion_failed_at TIMESTAMP, + PRIMARY KEY ( satellite_id, piece_id ) + ); + CREATE INDEX idx_piece_expirations_piece_expiration ON piece_expirations(piece_expiration); + CREATE INDEX idx_piece_expirations_deletion_failed_at ON piece_expirations(deletion_failed_at); + `, + }, + storagenodedb.OrdersDBName: &DBState{ + SQL: ` + -- table for storing all unsent orders + CREATE TABLE unsent_order ( + satellite_id BLOB NOT NULL, + serial_number BLOB NOT NULL, + order_limit_serialized BLOB NOT NULL, + order_serialized BLOB NOT NULL, + order_limit_expiration TIMESTAMP NOT NULL, + uplink_cert_id INTEGER NOT NULL, + FOREIGN KEY(uplink_cert_id) REFERENCES certificate(cert_id) + ); + CREATE UNIQUE INDEX idx_orders ON unsent_order(satellite_id, serial_number); + -- table for storing all sent orders + CREATE TABLE order_archive_ ( + satellite_id BLOB NOT NULL, + serial_number BLOB NOT NULL, + order_limit_serialized BLOB NOT NULL, + order_serialized BLOB NOT NULL, + uplink_cert_id INTEGER NOT NULL, + status INTEGER NOT NULL, + archived_at TIMESTAMP NOT NULL, + FOREIGN KEY(uplink_cert_id) REFERENCES certificate(cert_id) + ); + INSERT INTO unsent_order VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',X'1eddef484b4c03f01332279032796972',X'0a101eddef484b4c03f0133227903279697212202b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf410001a201968996e7ef170a402fdfd88b6753df792c063c07c555905ffac9cd3cbd1c00022200ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac30002a20d00cf14f3c68b56321ace04902dec0484eb6f9098b22b31c6b3f82db249f191630643802420c08dfeb88e50510a8c1a5b9034a0c08dfeb88e50510a8c1a5b9035246304402204df59dc6f5d1bb7217105efbc9b3604d19189af37a81efbf16258e5d7db5549e02203bb4ead16e6e7f10f658558c22b59c3339911841e8dbaae6e2dea821f7326894',X'0a101eddef484b4c03f0133227903279697210321a47304502206d4c106ddec88140414bac5979c95bdea7de2e0ecc5be766e08f7d5ea36641a7022100e932ff858f15885ffa52d07e260c2c25d3861810ea6157956c1793ad0c906284','2019-04-01 16:01:35.9254586+00:00',1); + `, + }, + storagenodedb.BandwidthDBName: &DBState{ + SQL: ` + -- table for storing bandwidth usage + CREATE TABLE bandwidth_usage ( + satellite_id BLOB NOT NULL, + action INTEGER NOT NULL, + amount BIGINT NOT NULL, + created_at TIMESTAMP NOT NULL + ); + CREATE INDEX idx_bandwidth_usage_satellite ON bandwidth_usage(satellite_id); + CREATE INDEX idx_bandwidth_usage_created ON bandwidth_usage(created_at); + CREATE TABLE bandwidth_usage_rollups ( + interval_start TIMESTAMP NOT NULL, + satellite_id BLOB NOT NULL, + action INTEGER NOT NULL, + amount BIGINT NOT NULL, + PRIMARY KEY ( interval_start, satellite_id, action ) + ); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',0,0,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',0,0,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',1,1,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',1,1,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',2,2,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',2,2,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',3,3,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',3,3,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',4,4,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',4,4,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',5,5,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',5,5,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',6,6,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',6,6,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',1,1,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',1,1,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',2,2,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',2,2,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',3,3,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',3,3,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',4,4,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',4,4,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',5,5,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',5,5,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',6,6,'2019-04-01 18:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage VALUES(X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',6,6,'2019-04-01 20:51:24.1074772+00:00'); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',0,0); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',0,0); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',1,1); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',1,1); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',2,2); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',2,2); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',3,3); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',3,3); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',4,4); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',4,4); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',5,5); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',5,5); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 18:00:00+00:00',X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000',6,6); + INSERT INTO bandwidth_usage_rollups VALUES('2019-07-12 20:00:00+00:00',X'2b3a5863a41f25408a8f5348839d7a1361dbd886d75786bb139a8ca0bdf41000',6,6); + `, + }, + storagenodedb.SatellitesDBName: &DBState{ + SQL: ` + CREATE TABLE satellites ( + node_id BLOB NOT NULL, + address TEXT NOT NUll, + added_at TIMESTAMP NOT NULL, + status INTEGER NOT NULL, + PRIMARY KEY (node_id) + ); + + CREATE TABLE satellite_exit_progress ( + satellite_id BLOB NOT NULL, + initiated_at TIMESTAMP, + finished_at TIMESTAMP, + starting_disk_usage INTEGER NOT NULL, + bytes_deleted INTEGER NOT NULL, + completion_receipt BLOB, + PRIMARY KEY (satellite_id) + ); + + INSERT INTO satellites VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000','127.0.0.1:55516','2019-09-10 20:00:00+00:00', 0); + INSERT INTO satellite_exit_progress VALUES(X'0ed28abb2813e184a1e98b0f6605c4911ea468c7e8433eb583e0fca7ceac3000','2019-09-10 20:00:00+00:00', null, 100, 0, null); + `, + }, + storagenodedb.DeprecatedInfoDBName: &DBState{ + SQL: `-- This is intentionally left blank`, + }, + }, +}