2019-02-14 21:55:21 +00:00
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package satellitedb
import (
2020-01-13 13:18:48 +00:00
"context"
2019-12-05 20:42:12 +00:00
"fmt"
2020-01-17 20:56:56 +00:00
"strings"
2019-12-05 20:42:12 +00:00
2019-02-14 21:55:21 +00:00
"github.com/zeebo/errs"
2019-12-05 20:42:12 +00:00
"storj.io/storj/private/dbutil"
2019-11-14 19:46:15 +00:00
"storj.io/storj/private/dbutil/pgutil"
"storj.io/storj/private/migrate"
2020-01-30 19:38:25 +00:00
"storj.io/storj/private/tagsql"
2019-02-14 21:55:21 +00:00
)
2019-07-23 18:58:43 +01:00
var (
2020-08-11 15:50:01 +01:00
// ErrMigrate is for tracking migration errors.
2019-07-23 18:58:43 +01:00
ErrMigrate = errs . Class ( "migrate" )
2020-08-11 15:50:01 +01:00
// ErrMigrateMinVersion is for migration min version errors.
2019-11-19 20:52:57 +00:00
ErrMigrateMinVersion = errs . Class ( "migrate min version" )
2019-07-23 18:58:43 +01:00
)
2019-02-14 21:55:21 +00:00
2020-04-30 07:36:59 +01:00
// MigrateToLatest migrates the database to the latest version.
func ( db * satelliteDB ) MigrateToLatest ( ctx context . Context ) error {
2019-12-05 20:42:12 +00:00
// 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
// not really be here, and instead should be assumed to exist.
2020-04-24 19:01:47 +01:00
// This is tracked in jira ticket SM-200
2019-12-05 20:42:12 +00:00
switch db . implementation {
case dbutil . Postgres :
2019-05-14 16:13:18 +01:00
schema , err := pgutil . ParseSchemaFromConnstr ( db . source )
if err != nil {
return errs . New ( "error parsing schema: %+v" , err )
}
2019-11-22 19:59:46 +00:00
2019-05-14 16:13:18 +01:00
if schema != "" {
2020-01-13 13:18:48 +00:00
err = pgutil . CreateSchema ( ctx , db , schema )
2019-05-14 16:13:18 +01:00
if err != nil {
return errs . New ( "error creating schema: %+v" , err )
}
}
2019-12-05 20:42:12 +00:00
case dbutil . Cockroach :
var dbName string
2020-01-17 20:07:00 +00:00
if err := db . QueryRow ( ctx , ` SELECT current_database(); ` ) . Scan ( & dbName ) ; err != nil {
2019-12-05 20:42:12 +00:00
return errs . New ( "error querying current database: %+v" , err )
}
2020-01-17 20:07:00 +00:00
_ , err := db . Exec ( ctx , fmt . Sprintf ( ` CREATE DATABASE IF NOT EXISTS %s; ` ,
2020-06-28 04:56:29 +01:00
pgutil . QuoteIdentifier ( dbName ) ) )
2019-12-05 20:42:12 +00:00
if err != nil {
return errs . Wrap ( err )
}
}
switch db . implementation {
case dbutil . Postgres , dbutil . Cockroach :
2019-02-14 21:55:21 +00:00
migration := db . PostgresMigration ( )
2019-11-22 19:59:46 +00:00
// 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
2020-01-17 20:07:00 +00:00
dbVersion , err := migration . CurrentVersion ( ctx , db . log , db . DB )
2019-11-19 20:52:57 +00:00
if err != nil {
return errs . New ( "error current version: %+v" , err )
}
if dbVersion > - 1 && dbVersion < minDBVersion {
return ErrMigrateMinVersion . New ( "current database version is %d, it shouldn't be less than the min version %d" ,
dbVersion , minDBVersion ,
)
}
2020-01-13 13:44:55 +00:00
return migration . Run ( ctx , db . log . Named ( "migrate" ) )
2019-02-14 21:55:21 +00:00
default :
2020-01-17 20:07:00 +00:00
return migrate . Create ( ctx , "database" , db . DB )
2019-02-14 21:55:21 +00:00
}
}
2020-04-30 07:36:59 +01:00
// TestingMigrateToLatest is a method for creating all tables for database for testing.
func ( db * satelliteDB ) TestingMigrateToLatest ( ctx context . Context ) error {
2020-01-17 20:56:56 +00:00
switch db . implementation {
case dbutil . Postgres :
schema , err := pgutil . ParseSchemaFromConnstr ( db . source )
if err != nil {
return ErrMigrateMinVersion . New ( "error parsing schema: %+v" , err )
}
if schema != "" {
err = pgutil . CreateSchema ( ctx , db , schema )
if err != nil {
return ErrMigrateMinVersion . New ( "error creating schema: %+v" , err )
}
}
case dbutil . Cockroach :
var dbName string
if err := db . QueryRow ( ctx , ` SELECT current_database(); ` ) . Scan ( & dbName ) ; err != nil {
return ErrMigrateMinVersion . New ( "error querying current database: %+v" , err )
}
2020-06-28 04:56:29 +01:00
_ , err := db . Exec ( ctx , fmt . Sprintf ( ` CREATE DATABASE IF NOT EXISTS %s; ` , pgutil . QuoteIdentifier ( dbName ) ) )
2020-01-17 20:56:56 +00:00
if err != nil {
return ErrMigrateMinVersion . Wrap ( err )
}
}
switch db . implementation {
case dbutil . Postgres , dbutil . Cockroach :
migration := db . PostgresMigration ( )
dbVersion , err := migration . CurrentVersion ( ctx , db . log , db . DB )
if err != nil {
return ErrMigrateMinVersion . Wrap ( err )
}
if dbVersion > - 1 {
return ErrMigrateMinVersion . New ( "the database must be empty, got version %d" , dbVersion )
}
flattened , err := flattenMigration ( migration )
if err != nil {
return ErrMigrateMinVersion . Wrap ( err )
}
return flattened . Run ( ctx , db . log . Named ( "migrate" ) )
default :
return migrate . Create ( ctx , "database" , db . DB )
}
}
2020-07-16 15:18:02 +01:00
// CheckVersion confirms the database is at the desired version.
2020-01-13 13:44:55 +00:00
func ( db * satelliteDB ) CheckVersion ( ctx context . Context ) error {
2019-12-05 20:42:12 +00:00
switch db . implementation {
case dbutil . Postgres , dbutil . Cockroach :
2019-11-02 20:09:07 +00:00
migration := db . PostgresMigration ( )
2020-01-13 13:44:55 +00:00
return migration . ValidateVersions ( ctx , db . log )
2019-12-05 20:42:12 +00:00
2019-11-02 20:09:07 +00:00
default :
return nil
}
}
2020-06-25 12:23:39 +01:00
// flattenMigration joins the migration sql queries from
// each migration step to speed up the database setup.
//
// Steps with "SeparateTx" end up as separate migration transactions.
// Cockroach requires schema changes and updates to the values of that
// schema change to be in a different transaction.
2020-01-17 20:56:56 +00:00
func flattenMigration ( m * migrate . Migration ) ( * migrate . Migration , error ) {
2020-01-30 19:38:25 +00:00
var db tagsql . DB
2020-01-17 20:56:56 +00:00
var version int
var statements migrate . SQL
2020-06-30 22:49:29 +01:00
var steps [ ] * migrate . Step
2020-01-17 20:56:56 +00:00
2020-06-25 12:23:39 +01:00
pushMerged := func ( ) {
if len ( statements ) == 0 {
return
}
steps = append ( steps , & migrate . Step {
DB : db ,
Description : "Setup" ,
Version : version ,
Action : migrate . SQL { strings . Join ( statements , ";\n" ) } ,
} )
statements = nil
}
2020-01-17 20:56:56 +00:00
for _ , step := range m . Steps {
if db == nil {
db = step . DB
} else if db != step . DB {
return nil , errs . New ( "multiple databases not supported" )
}
2020-06-25 12:23:39 +01:00
if sql , ok := step . Action . ( migrate . SQL ) ; ok {
if step . SeparateTx {
pushMerged ( )
2020-03-18 20:00:13 +00:00
}
2020-06-25 12:23:39 +01:00
version = step . Version
statements = append ( statements , sql ... )
} else {
pushMerged ( )
2020-03-18 20:00:13 +00:00
steps = append ( steps , step )
2020-01-17 20:56:56 +00:00
}
}
2020-06-25 12:23:39 +01:00
pushMerged ( )
2020-01-17 20:56:56 +00:00
return & migrate . Migration {
Table : "versions" ,
2020-03-18 20:00:13 +00:00
Steps : steps ,
2020-01-17 20:56:56 +00:00
} , nil
}
2019-02-14 21:55:21 +00:00
// PostgresMigration returns steps needed for migrating postgres database.
2019-12-14 02:29:54 +00:00
func ( db * satelliteDB ) PostgresMigration ( ) * migrate . Migration {
2019-02-14 21:55:21 +00:00
return & migrate . Migration {
Table : "versions" ,
Steps : [ ] * migrate . Step {
{
2020-01-17 20:07:00 +00:00
DB : db . DB ,
2019-02-14 21:55:21 +00:00
Description : "Initial setup" ,
2020-08-26 16:06:44 +01:00
Version : 103 ,
2019-02-14 21:55:21 +00:00
Action : migrate . SQL {
2019-11-19 20:52:57 +00:00
` CREATE TABLE accounting_rollups (
2019-02-14 21:55:21 +00:00
id bigserial NOT NULL ,
node_id bytea NOT NULL ,
start_time timestamp with time zone NOT NULL ,
put_total bigint NOT NULL ,
get_total bigint NOT NULL ,
get_audit_total bigint NOT NULL ,
get_repair_total bigint NOT NULL ,
put_repair_total bigint NOT NULL ,
at_rest_total double precision NOT NULL ,
PRIMARY KEY ( id )
2019-11-19 20:52:57 +00:00
) ; ` ,
2020-08-26 16:06:44 +01:00
` CREATE INDEX accounting_rollups_start_time_index ON accounting_rollups ( start_time ); ` ,
2019-11-19 20:52:57 +00:00
` CREATE TABLE accounting_timestamps (
2019-02-14 21:55:21 +00:00
name text NOT NULL ,
value timestamp with time zone NOT NULL ,
PRIMARY KEY ( name )
2019-11-19 20:52:57 +00:00
) ; ` ,
` CREATE TABLE bucket_bandwidth_rollups (
bucket_name bytea NOT NULL ,
2020-08-26 16:06:44 +01:00
interval_start timestamp with time zone NOT NULL ,
2019-11-19 20:52:57 +00:00
interval_seconds integer NOT NULL ,
action integer NOT NULL ,
inline bigint NOT NULL ,
allocated bigint NOT NULL ,
settled bigint NOT NULL ,
project_id bytea NOT NULL ,
CONSTRAINT bucket_bandwidth_rollups_pk PRIMARY KEY ( bucket_name , project_id , interval_start , action )
) ; ` ,
2020-08-26 16:06:44 +01:00
` CREATE INDEX IF NOT EXISTS bucket_bandwidth_rollups_project_id_action_interval_index ON bucket_bandwidth_rollups ( project_id, action, interval_start ); ` ,
2019-11-19 20:52:57 +00:00
` CREATE TABLE bucket_storage_tallies (
bucket_name bytea NOT NULL ,
2020-08-26 16:06:44 +01:00
interval_start timestamp with time zone NOT NULL ,
2019-11-19 20:52:57 +00:00
inline bigint NOT NULL ,
remote bigint NOT NULL ,
remote_segments_count integer NOT NULL ,
inline_segments_count integer NOT NULL ,
object_count integer NOT NULL ,
metadata_size bigint NOT NULL ,
project_id bytea NOT NULL ,
CONSTRAINT bucket_storage_tallies_pk PRIMARY KEY ( bucket_name , project_id , interval_start )
) ; ` ,
` CREATE TABLE injuredsegments (
2019-02-14 21:55:21 +00:00
data bytea NOT NULL ,
2020-08-26 16:06:44 +01:00
attempted timestamp with time zone ,
2019-11-19 20:52:57 +00:00
path bytea NOT NULL ,
2020-08-26 16:06:44 +01:00
num_healthy_pieces integer DEFAULT 52 NOT NULL ,
2019-11-19 20:52:57 +00:00
CONSTRAINT injuredsegments_pk PRIMARY KEY ( path )
) ; ` ,
` CREATE INDEX injuredsegments_attempted_index ON injuredsegments ( attempted ); ` ,
2020-08-26 16:06:44 +01:00
` CREATE INDEX injuredsegments_num_healthy_pieces_index ON injuredsegments ( num_healthy_pieces ); ` ,
2019-11-19 20:52:57 +00:00
` CREATE TABLE irreparabledbs (
2019-02-14 21:55:21 +00:00
segmentpath bytea NOT NULL ,
segmentdetail bytea NOT NULL ,
pieces_lost_count bigint NOT NULL ,
seg_damaged_unix_sec bigint NOT NULL ,
repair_attempt_count bigint NOT NULL ,
PRIMARY KEY ( segmentpath )
2019-11-19 20:52:57 +00:00
) ; ` ,
` CREATE TABLE nodes (
2019-02-14 21:55:21 +00:00
id bytea NOT NULL ,
2019-11-19 20:52:57 +00:00
audit_success_count bigint NOT NULL DEFAULT 0 ,
total_audit_count bigint NOT NULL DEFAULT 0 ,
2019-02-14 21:55:21 +00:00
uptime_success_count bigint NOT NULL ,
total_uptime_count bigint NOT NULL ,
2019-11-19 20:52:57 +00:00
created_at timestamp with time zone NOT NULL DEFAULT current_timestamp ,
updated_at timestamp with time zone NOT NULL DEFAULT current_timestamp ,
wallet text NOT NULL ,
email text NOT NULL ,
address text NOT NULL DEFAULT ' ' ,
protocol INTEGER NOT NULL DEFAULT 0 ,
type INTEGER NOT NULL DEFAULT 0 ,
free_disk BIGINT NOT NULL DEFAULT - 1 ,
latency_90 BIGINT NOT NULL DEFAULT 0 ,
last_contact_success TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT ' epoch ' ,
last_contact_failure TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT ' epoch ' ,
major bigint NOT NULL DEFAULT 0 ,
minor bigint NOT NULL DEFAULT 0 ,
patch bigint NOT NULL DEFAULT 0 ,
hash TEXT NOT NULL DEFAULT ' ' ,
timestamp TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT ' 0001 - 01 - 01 00 : 00 : 00 + 00 ' ,
release bool NOT NULL DEFAULT FALSE ,
contained bool NOT NULL DEFAULT FALSE ,
last_net text NOT NULL ,
disqualified timestamp with time zone ,
audit_reputation_alpha double precision NOT NULL DEFAULT 1 ,
audit_reputation_beta double precision NOT NULL DEFAULT 0 ,
uptime_reputation_alpha double precision NOT NULL DEFAULT 1 ,
uptime_reputation_beta double precision NOT NULL DEFAULT 0 ,
piece_count bigint NOT NULL DEFAULT 0 ,
2020-08-26 16:06:44 +01:00
exit_loop_completed_at timestamp with time zone ,
exit_initiated_at timestamp with time zone ,
exit_finished_at timestamp with time zone ,
2019-11-19 20:52:57 +00:00
exit_success boolean NOT NULL DEFAULT FALSE ,
2020-08-26 16:06:44 +01:00
last_ip_port text ,
suspended timestamp with time zone ,
unknown_audit_reputation_alpha double precision NOT NULL DEFAULT 1 ,
unknown_audit_reputation_beta double precision NOT NULL DEFAULT 0 ,
vetted_at timestamp with time zone ,
2019-02-14 21:55:21 +00:00
PRIMARY KEY ( id )
2019-11-19 20:52:57 +00:00
) ; ` ,
` CREATE INDEX node_last_ip ON nodes ( last_net ); ` ,
` CREATE TABLE offers (
id serial NOT NULL ,
2019-02-14 21:55:21 +00:00
name text NOT NULL ,
description text NOT NULL ,
2019-11-19 20:52:57 +00:00
type integer NOT NULL ,
award_credit_duration_days integer ,
invitee_credit_duration_days integer ,
redeemable_cap integer ,
expires_at timestamp with time zone NOT NULL ,
2019-02-14 21:55:21 +00:00
created_at timestamp with time zone NOT NULL ,
status integer NOT NULL ,
2019-11-19 20:52:57 +00:00
award_credit_in_cents integer NOT NULL DEFAULT 0 ,
invitee_credit_in_cents integer NOT NULL DEFAULT 0 ,
2019-02-14 21:55:21 +00:00
PRIMARY KEY ( id )
2019-11-19 20:52:57 +00:00
) ; ` ,
2019-02-14 21:55:21 +00:00
2019-11-19 20:52:57 +00:00
` CREATE TABLE peer_identities (
node_id bytea NOT NULL ,
leaf_serial_number bytea NOT NULL ,
chain bytea NOT NULL ,
updated_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( node_id )
) ; ` ,
2019-02-14 21:55:21 +00:00
2019-11-19 20:52:57 +00:00
` CREATE TABLE pending_audits (
node_id bytea NOT NULL ,
piece_id bytea NOT NULL ,
stripe_index bigint NOT NULL ,
share_size bigint NOT NULL ,
expected_share_hash bytea NOT NULL ,
reverify_count bigint NOT NULL ,
path bytea NOT NULL ,
PRIMARY KEY ( node_id )
) ; ` ,
2019-02-14 21:55:21 +00:00
2019-11-19 20:52:57 +00:00
` CREATE TABLE projects (
2019-02-14 21:55:21 +00:00
id bytea NOT NULL ,
2019-11-19 20:52:57 +00:00
name text NOT NULL ,
description text NOT NULL ,
created_at timestamp with time zone NOT NULL ,
usage_limit bigint NOT NULL DEFAULT 0 ,
partner_id bytea ,
owner_id bytea NOT NULL ,
2020-08-26 16:06:44 +01:00
rate_limit integer ,
2019-02-14 21:55:21 +00:00
PRIMARY KEY ( id )
2019-11-19 20:52:57 +00:00
) ; ` ,
2019-02-14 21:55:21 +00:00
2019-11-19 20:52:57 +00:00
` CREATE TABLE registration_tokens (
secret bytea NOT NULL ,
owner_id bytea UNIQUE ,
project_limit integer NOT NULL ,
created_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( secret )
) ; ` ,
2019-02-14 21:55:21 +00:00
2019-11-19 20:52:57 +00:00
` CREATE TABLE reset_password_tokens (
secret bytea NOT NULL ,
owner_id bytea NOT NULL UNIQUE ,
created_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( secret )
) ; ` ,
2019-02-14 21:55:21 +00:00
2019-03-22 18:54:22 +00:00
` CREATE TABLE serial_numbers (
id serial NOT NULL ,
serial_number bytea NOT NULL ,
bucket_id bytea NOT NULL ,
2020-08-26 16:06:44 +01:00
expires_at timestamp with time zone NOT NULL ,
2019-03-26 10:34:30 +00:00
PRIMARY KEY ( id )
2019-11-19 20:52:57 +00:00
) ; ` ,
` CREATE INDEX serial_numbers_expires_at_index ON serial_numbers ( expires_at ); ` ,
2019-03-26 10:34:30 +00:00
` CREATE UNIQUE INDEX serial_number_index ON serial_numbers ( serial_number ) ` ,
2019-11-19 20:52:57 +00:00
2019-03-22 18:54:22 +00:00
` CREATE TABLE storagenode_bandwidth_rollups (
storagenode_id bytea NOT NULL ,
2020-08-26 16:06:44 +01:00
interval_start timestamp with time zone NOT NULL ,
2019-03-22 18:54:22 +00:00
interval_seconds integer NOT NULL ,
action integer NOT NULL ,
2020-08-26 16:06:44 +01:00
allocated bigint DEFAULT 0 ,
2019-03-22 18:54:22 +00:00
settled bigint NOT NULL ,
2019-03-26 10:34:30 +00:00
PRIMARY KEY ( storagenode_id , interval_start , action )
2019-05-13 16:53:52 +01:00
) ; ` ,
2019-05-16 15:11:15 +01:00
2020-08-26 16:06:44 +01:00
` CREATE TABLE storagenode_storage_tallies (
2019-05-16 15:11:15 +01:00
node_id bytea NOT NULL ,
2019-11-19 20:52:57 +00:00
interval_end_time timestamp with time zone NOT NULL ,
data_total double precision NOT NULL ,
2020-08-26 16:06:44 +01:00
CONSTRAINT storagenode_storage_tallies_pkey PRIMARY KEY ( interval_end_time , node_id )
) ; ` ,
` CREATE INDEX storagenode_storage_tallies_node_id_index ON storagenode_storage_tallies ( node_id ); ` ,
2019-11-19 20:52:57 +00:00
` CREATE TABLE users (
id bytea NOT NULL ,
full_name text NOT NULL ,
short_name text ,
email text NOT NULL ,
password_hash bytea NOT NULL ,
status integer NOT NULL ,
2019-06-13 14:52:33 +01:00
created_at timestamp with time zone NOT NULL ,
2019-11-19 20:52:57 +00:00
partner_id bytea ,
normalized_email text NOT NULL ,
2019-06-13 14:52:33 +01:00
PRIMARY KEY ( id )
) ; ` ,
2019-11-19 20:52:57 +00:00
` CREATE TABLE value_attributions (
bucket_name bytea NOT NULL ,
partner_id bytea NOT NULL ,
2020-08-26 16:06:44 +01:00
last_updated timestamp with time zone NOT NULL ,
2019-11-19 20:52:57 +00:00
project_id bytea NOT NULL ,
PRIMARY KEY ( project_id , bucket_name )
) ; ` ,
` CREATE TABLE api_keys (
id bytea NOT NULL ,
project_id bytea NOT NULL REFERENCES projects ( id ) ON DELETE CASCADE ,
head bytea NOT NULL UNIQUE ,
name text NOT NULL ,
secret bytea NOT NULL ,
created_at timestamp with time zone NOT NULL ,
partner_id bytea ,
PRIMARY KEY ( id ) ,
UNIQUE ( name , project_id )
) ; ` ,
2019-07-03 23:03:56 +01:00
` CREATE TABLE bucket_metainfos (
2019-07-01 21:45:21 +01:00
id bytea NOT NULL ,
project_id bytea NOT NULL REFERENCES projects ( id ) ,
name bytea NOT NULL ,
path_cipher integer NOT NULL ,
2019-07-03 23:03:56 +01:00
created_at timestamp with time zone NOT NULL ,
2019-07-01 21:45:21 +01:00
default_segment_size integer NOT NULL ,
default_encryption_cipher_suite integer NOT NULL ,
default_encryption_block_size integer NOT NULL ,
default_redundancy_algorithm integer NOT NULL ,
default_redundancy_share_size integer NOT NULL ,
default_redundancy_required_shares integer NOT NULL ,
default_redundancy_repair_shares integer NOT NULL ,
default_redundancy_optimal_shares integer NOT NULL ,
default_redundancy_total_shares integer NOT NULL ,
2019-11-19 20:52:57 +00:00
partner_id bytea ,
2019-07-01 21:45:21 +01:00
PRIMARY KEY ( id ) ,
UNIQUE ( name , project_id )
) ; ` ,
2019-11-19 20:52:57 +00:00
` CREATE TABLE project_invoice_stamps (
project_id bytea NOT NULL REFERENCES projects ( id ) ON DELETE CASCADE ,
invoice_id bytea NOT NULL UNIQUE ,
start_date timestamp with time zone NOT NULL ,
end_date timestamp with time zone NOT NULL ,
created_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( project_id , start_date , end_date )
) ; ` ,
` CREATE TABLE project_members (
member_id bytea NOT NULL REFERENCES users ( id ) ON DELETE CASCADE ,
2019-07-10 21:29:26 +01:00
project_id bytea NOT NULL REFERENCES projects ( id ) ON DELETE CASCADE ,
created_at timestamp with time zone NOT NULL ,
2019-11-19 20:52:57 +00:00
PRIMARY KEY ( member_id , project_id )
) ; ` ,
` CREATE TABLE used_serials (
serial_number_id integer NOT NULL REFERENCES serial_numbers ( id ) ON DELETE CASCADE ,
storage_node_id bytea NOT NULL ,
PRIMARY KEY ( serial_number_id , storage_node_id )
) ; ` ,
` CREATE TABLE user_credits (
id serial NOT NULL ,
user_id bytea NOT NULL REFERENCES users ( id ) ON DELETE CASCADE ,
offer_id integer NOT NULL REFERENCES offers ( id ) ,
referred_by bytea REFERENCES users ( id ) ON DELETE SET NULL ,
credits_earned_in_cents integer NOT NULL ,
credits_used_in_cents integer NOT NULL ,
expires_at timestamp with time zone NOT NULL ,
created_at timestamp with time zone NOT NULL ,
type text NOT NULL ,
2020-08-26 16:06:44 +01:00
PRIMARY KEY ( id ) ,
UNIQUE ( id , offer_id )
2019-07-10 21:29:26 +01:00
) ; ` ,
2019-11-19 20:52:57 +00:00
` CREATE UNIQUE INDEX credits_earned_user_id_offer_id ON user_credits (id, offer_id); ` ,
2019-07-12 15:19:38 +01:00
` INSERT INTO offers (
2019-12-11 23:49:57 +00:00
id ,
2019-07-12 15:19:38 +01:00
name ,
description ,
award_credit_in_cents ,
invitee_credit_in_cents ,
expires_at ,
created_at ,
status ,
2019-11-19 20:52:57 +00:00
type ,
award_credit_duration_days ,
invitee_credit_duration_days
)
2019-07-12 15:19:38 +01:00
VALUES (
2019-12-11 23:49:57 +00:00
1 ,
2019-07-12 15:19:38 +01:00
' Default referral offer ' ,
' Is active when no other active referral offer ' ,
300 ,
600 ,
' 2119 - 03 - 14 0 8 : 28 : 24.636949 + 00 ' ,
' 2019 - 07 - 14 0 8 : 28 : 24.636949 + 00 ' ,
1 ,
2019-11-19 20:52:57 +00:00
2 ,
365 ,
14
2019-07-12 15:19:38 +01:00
) ,
(
2019-12-11 23:49:57 +00:00
2 ,
2019-07-12 15:19:38 +01:00
' Default free credit offer ' ,
' Is active when no active free credit offer ' ,
0 ,
2019-11-19 20:52:57 +00:00
300 ,
2019-07-12 15:19:38 +01:00
' 2119 - 03 - 14 0 8 : 28 : 24.636949 + 00 ' ,
' 2019 - 07 - 14 0 8 : 28 : 24.636949 + 00 ' ,
1 ,
2019-11-19 20:52:57 +00:00
1 ,
NULL ,
14
2019-07-12 15:19:38 +01:00
) ON CONFLICT DO NOTHING ; ` ,
2019-08-07 13:28:13 +01:00
2019-09-13 17:57:32 +01:00
` CREATE TABLE graceful_exit_progress (
node_id bytea NOT NULL ,
bytes_transferred bigint NOT NULL ,
2020-08-26 16:06:44 +01:00
updated_at timestamp with time zone NOT NULL ,
2019-11-19 20:52:57 +00:00
pieces_transferred bigint NOT NULL DEFAULT 0 ,
pieces_failed bigint NOT NULL DEFAULT 0 ,
2019-09-13 17:57:32 +01:00
PRIMARY KEY ( node_id )
) ; ` ,
2019-11-19 20:52:57 +00:00
2019-09-13 17:57:32 +01:00
` CREATE TABLE graceful_exit_transfer_queue (
node_id bytea NOT NULL ,
path bytea NOT NULL ,
piece_num integer NOT NULL ,
durability_ratio double precision NOT NULL ,
2020-08-26 16:06:44 +01:00
queued_at timestamp with time zone NOT NULL ,
requested_at timestamp with time zone ,
last_failed_at timestamp with time zone ,
2019-09-13 17:57:32 +01:00
last_failed_code integer ,
failed_count integer ,
2020-08-26 16:06:44 +01:00
finished_at timestamp with time zone ,
2019-11-22 19:59:46 +00:00
root_piece_id bytea ,
order_limit_send_count integer NOT NULL DEFAULT 0 ,
2019-11-19 20:52:57 +00:00
PRIMARY KEY ( node_id , path , piece_num )
2019-09-13 17:57:32 +01:00
) ; ` ,
2019-11-19 20:52:57 +00:00
2019-10-10 18:12:23 +01:00
` CREATE TABLE stripe_customers (
user_id bytea NOT NULL ,
2019-11-19 20:52:57 +00:00
customer_id text NOT NULL UNIQUE ,
2019-10-10 18:12:23 +01:00
created_at timestamp with time zone NOT NULL ,
2019-11-19 20:52:57 +00:00
PRIMARY KEY ( user_id )
2019-10-10 18:12:23 +01:00
) ; ` ,
2019-11-19 20:52:57 +00:00
2019-11-05 13:16:02 +00:00
` CREATE TABLE stripecoinpayments_invoice_project_records (
id bytea NOT NULL ,
project_id bytea NOT NULL ,
storage double precision NOT NULL ,
egress bigint NOT NULL ,
objects bigint NOT NULL ,
period_start timestamp with time zone NOT NULL ,
period_end timestamp with time zone NOT NULL ,
state integer NOT NULL ,
created_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( id ) ,
UNIQUE ( project_id , period_start , period_end )
) ; ` ,
2019-11-15 14:59:39 +00:00
` CREATE TABLE stripecoinpayments_tx_conversion_rates (
tx_id text NOT NULL ,
rate bytea NOT NULL ,
created_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( tx_id )
) ; ` ,
2019-11-22 19:59:46 +00:00
2019-11-15 14:59:39 +00:00
` CREATE TABLE coinpayments_transactions (
id text NOT NULL ,
user_id bytea NOT NULL ,
address text NOT NULL ,
amount bytea NOT NULL ,
received bytea NOT NULL ,
status integer NOT NULL ,
key text NOT NULL ,
timeout integer NOT NULL ,
created_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( id )
) ; ` ,
2019-11-22 19:59:46 +00:00
` CREATE TABLE stripecoinpayments_apply_balance_intents (
tx_id text NOT NULL REFERENCES coinpayments_transactions ( id ) ON DELETE CASCADE ,
state integer NOT NULL ,
created_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( tx_id )
) ; ` ,
2020-08-26 16:06:44 +01:00
2019-12-27 22:03:03 +00:00
` CREATE TABLE nodes_offline_times (
node_id bytea NOT NULL ,
tracked_at timestamp with time zone NOT NULL ,
seconds integer NOT NULL ,
PRIMARY KEY ( node_id , tracked_at )
) ; ` ,
` CREATE INDEX nodes_offline_times_node_id_index ON nodes_offline_times ( node_id ); ` ,
2020-08-26 16:06:44 +01:00
2020-01-07 10:41:19 +00:00
` CREATE TABLE coupons (
id bytea NOT NULL ,
project_id bytea NOT NULL ,
user_id bytea NOT NULL ,
amount bigint NOT NULL ,
description text NOT NULL ,
type integer NOT NULL ,
status integer NOT NULL ,
duration bigint NOT NULL ,
created_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( id )
) ; ` ,
` CREATE TABLE coupon_usages (
coupon_id bytea NOT NULL ,
amount bigint NOT NULL ,
status integer NOT NULL ,
period timestamp with time zone NOT NULL ,
PRIMARY KEY ( coupon_id , period )
) ; ` ,
2020-08-26 16:06:44 +01:00
2020-01-15 21:45:17 +00:00
` CREATE TABLE reported_serials (
2020-01-16 18:02:15 +00:00
expires_at timestamp with time zone NOT NULL ,
2020-01-15 21:45:17 +00:00
storage_node_id bytea NOT NULL ,
bucket_id bytea NOT NULL ,
action integer NOT NULL ,
serial_number bytea NOT NULL ,
settled bigint NOT NULL ,
2020-01-16 18:02:15 +00:00
observed_at timestamp with time zone NOT NULL ,
2020-01-15 21:45:17 +00:00
PRIMARY KEY ( expires_at , storage_node_id , bucket_id , action , serial_number )
) ; ` ,
2020-08-26 16:06:44 +01:00
2020-01-24 13:38:53 +00:00
` CREATE TABLE credits (
user_id bytea NOT NULL ,
transaction_id text NOT NULL ,
amount bigint NOT NULL ,
created_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( transaction_id )
) ; ` ,
2020-08-26 16:06:44 +01:00
2020-01-24 13:38:53 +00:00
` CREATE TABLE credits_spendings (
id bytea NOT NULL ,
user_id bytea NOT NULL ,
project_id bytea NOT NULL ,
amount bigint NOT NULL ,
status int NOT NULL ,
created_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( id )
) ; ` ,
2020-08-26 16:06:44 +01:00
2020-02-14 00:03:41 +00:00
` CREATE TABLE consumed_serials (
storage_node_id bytea NOT NULL ,
serial_number bytea NOT NULL ,
expires_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( storage_node_id , serial_number )
) ; ` ,
2020-08-26 16:06:44 +01:00
` CREATE INDEX consumed_serials_expires_at_index ON consumed_serials ( expires_at ); ` ,
2020-02-14 00:03:41 +00:00
` CREATE TABLE pending_serial_queue (
storage_node_id bytea NOT NULL ,
bucket_id bytea NOT NULL ,
serial_number bytea NOT NULL ,
action integer NOT NULL ,
settled bigint NOT NULL ,
expires_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( storage_node_id , bucket_id , serial_number )
) ; ` ,
2020-08-26 16:06:44 +01:00
2020-02-18 19:52:18 +00:00
` CREATE TABLE storagenode_payments (
id bigserial NOT NULL ,
created_at timestamp with time zone NOT NULL ,
node_id bytea NOT NULL ,
2020-08-26 16:06:44 +01:00
period text NOT NULL ,
2020-02-18 19:52:18 +00:00
amount bigint NOT NULL ,
receipt text ,
notes text ,
PRIMARY KEY ( id )
) ; ` ,
` CREATE INDEX storagenode_payments_node_id_period_index ON storagenode_payments ( node_id, period ); ` ,
2020-08-26 16:06:44 +01:00
2020-02-18 19:52:18 +00:00
` CREATE TABLE storagenode_paystubs (
period text NOT NULL ,
node_id bytea NOT NULL ,
created_at timestamp with time zone NOT NULL ,
codes text NOT NULL ,
usage_at_rest double precision NOT NULL ,
usage_get bigint NOT NULL ,
usage_put bigint NOT NULL ,
usage_get_repair bigint NOT NULL ,
usage_put_repair bigint NOT NULL ,
usage_get_audit bigint NOT NULL ,
comp_at_rest bigint NOT NULL ,
comp_get bigint NOT NULL ,
comp_put bigint NOT NULL ,
comp_get_repair bigint NOT NULL ,
comp_put_repair bigint NOT NULL ,
comp_get_audit bigint NOT NULL ,
surge_percent bigint NOT NULL ,
held bigint NOT NULL ,
owed bigint NOT NULL ,
disposed bigint NOT NULL ,
paid bigint NOT NULL ,
PRIMARY KEY ( period , node_id )
) ; ` ,
` CREATE INDEX storagenode_paystubs_node_id_index ON storagenode_paystubs ( node_id ); ` ,
2020-04-01 22:58:46 +01:00
} ,
} ,
2020-04-17 14:04:29 +01:00
{
DB : db . DB ,
Description : "Add missing bucket_bandwidth_rollups_action_interval_project_id_index index" ,
Version : 104 ,
Action : migrate . SQL {
` CREATE INDEX IF NOT EXISTS bucket_bandwidth_rollups_action_interval_project_id_index ON bucket_bandwidth_rollups(action, interval_start, project_id ); ` ,
} ,
} ,
2020-04-14 17:49:45 +01:00
{
DB : db . DB ,
Description : "Remove all nodes from suspension mode." ,
Version : 105 ,
Action : migrate . SQL {
` UPDATE nodes SET suspended=NULL; ` ,
} ,
} ,
2020-05-01 14:24:12 +01:00
{
DB : db . DB ,
Description : "Add project_bandwidth_rollup table and populate with current months data" ,
Version : 106 ,
Action : migrate . SQL {
` CREATE TABLE IF NOT EXISTS project_bandwidth_rollups (
project_id bytea NOT NULL ,
interval_month date NOT NULL ,
egress_allocated bigint NOT NULL ,
PRIMARY KEY ( project_id , interval_month )
) ;
INSERT INTO project_bandwidth_rollups ( project_id , interval_month , egress_allocated ) (
2020-05-11 20:31:49 +01:00
SELECT project_id , date_trunc ( ' MONTH ' , now ( ) ) : : DATE , sum ( allocated ) : : bigint FROM bucket_bandwidth_rollups
2020-05-01 14:24:12 +01:00
WHERE action = 2 AND interval_start >= date_trunc ( ' MONTH ' , now ( ) ) : : timestamp group by project_id )
ON CONFLICT ( project_id , interval_month ) DO UPDATE SET egress_allocated = EXCLUDED . egress_allocated : : bigint ; ` ,
} ,
} ,
2020-05-12 14:01:15 +01:00
{
DB : db . DB ,
Description : "add separate bandwidth column" ,
Version : 107 ,
2020-05-12 16:27:07 +01:00
Action : migrate . SQL {
` ALTER TABLE projects ADD COLUMN bandwidth_limit bigint NOT NULL DEFAULT 0; ` ,
} ,
2020-05-12 14:01:15 +01:00
} ,
{
DB : db . DB ,
Description : "backfill bandwidth column with previous limits" ,
Version : 108 ,
2020-06-25 12:23:39 +01:00
SeparateTx : true ,
Action : migrate . SQL {
` UPDATE projects SET bandwidth_limit = usage_limit; ` ,
} ,
2020-05-12 14:01:15 +01:00
} ,
2020-05-12 09:46:48 +01:00
{
DB : db . DB ,
Description : "add period column to the credits_spendings table (step 1)" ,
Version : 109 ,
2020-06-26 09:41:55 +01:00
SeparateTx : true ,
2020-06-25 12:23:39 +01:00
Action : migrate . SQL {
` ALTER TABLE credits_spendings ADD COLUMN period timestamp with time zone; ` ,
} ,
2020-05-12 09:46:48 +01:00
} ,
{
DB : db . DB ,
Description : "add period column to the credits_spendings table (step 2)" ,
Version : 110 ,
2020-06-25 12:23:39 +01:00
SeparateTx : true ,
Action : migrate . SQL {
` UPDATE credits_spendings SET period = 'epoch'; ` ,
} ,
2020-05-12 09:46:48 +01:00
} ,
{
DB : db . DB ,
Description : "add period column to the credits_spendings table (step 3)" ,
Version : 111 ,
2020-06-26 09:41:55 +01:00
SeparateTx : true ,
2020-06-25 12:23:39 +01:00
Action : migrate . SQL {
` ALTER TABLE credits_spendings ALTER COLUMN period SET NOT NULL; ` ,
} ,
2020-05-12 09:46:48 +01:00
} ,
2020-05-11 20:35:48 +01:00
{
DB : db . DB ,
Description : "fix incorrect calculations on backported paystub data" ,
Version : 112 ,
Action : migrate . SQL { `
UPDATE storagenode_paystubs SET
comp_at_rest = (
( ( owed + held - disposed ) : : float / GREATEST ( surge_percent : : float / 100 , 1 ) ) : : int
- comp_get - comp_get_repair - comp_get_audit
)
WHERE
(
abs (
( ( owed + held - disposed ) : : float / GREATEST ( surge_percent : : float / 100 , 1 ) ) : : int
- comp_get - comp_get_repair - comp_get_audit
) >= 10
OR comp_at_rest < 0
)
AND codes not like ' % O % '
AND codes not like ' % D % '
AND period < ' 2020 - 03 '
` } ,
} ,
2020-06-02 09:33:07 +01:00
{
DB : db . DB ,
Description : "drop project_id column from coupon table" ,
Version : 113 ,
Action : migrate . SQL {
` ALTER TABLE coupons DROP COLUMN project_id; ` ,
} ,
} ,
2020-06-09 22:49:12 +01:00
{
DB : db . DB ,
Description : "add new columns for suspension to node tables" ,
Version : 114 ,
Action : migrate . SQL {
` ALTER TABLE nodes ADD COLUMN unknown_audit_suspended TIMESTAMP WITH TIME ZONE; ` ,
` ALTER TABLE nodes ADD COLUMN offline_suspended TIMESTAMP WITH TIME ZONE; ` ,
` ALTER TABLE nodes ADD COLUMN under_review TIMESTAMP WITH TIME ZONE; ` ,
} ,
} ,
2020-06-03 14:51:02 +01:00
{
DB : db . DB ,
Description : "add revocations database" ,
Version : 115 ,
Action : migrate . SQL { `
CREATE TABLE revocations (
revoked bytea NOT NULL ,
api_key_id bytea NOT NULL ,
PRIMARY KEY ( revoked )
) ;
` } ,
} ,
2020-06-30 16:45:27 +01:00
{
DB : db . DB ,
Description : "add audit histories database" ,
Version : 116 ,
Action : migrate . SQL {
` CREATE TABLE audit_histories (
2020-07-01 16:25:20 +01:00
node_id bytea NOT NULL ,
history bytea NOT NULL ,
PRIMARY KEY ( node_id )
2020-06-30 16:45:27 +01:00
) ; ` ,
} ,
} ,
2020-07-01 16:25:20 +01:00
{
DB : db . DB ,
Description : "add node_api_versions table" ,
Version : 117 ,
Action : migrate . SQL { `
CREATE TABLE node_api_versions (
id bytea NOT NULL ,
api_version integer NOT NULL ,
created_at timestamp with time zone NOT NULL ,
updated_at timestamp with time zone NOT NULL ,
PRIMARY KEY ( id )
) ;
` } ,
} ,
2020-06-30 22:49:29 +01:00
{
DB : db . DB ,
Description : "add max_buckets field to projects and an implicit index on bucket_metainfos project_id,name" ,
SeparateTx : true ,
Version : 118 ,
Action : migrate . SQL {
` ALTER TABLE projects ADD COLUMN max_buckets INTEGER NOT NULL DEFAULT 0; ` ,
` ALTER TABLE bucket_metainfos ADD UNIQUE (project_id, name); ` ,
} ,
} ,
2020-07-15 16:14:09 +01:00
{
DB : db . DB ,
Description : "add project_limit field to users table" ,
Version : 119 ,
Action : migrate . SQL {
` ALTER TABLE users ADD COLUMN project_limit INTEGER NOT NULL DEFAULT 0; ` ,
} ,
} ,
2020-07-15 17:49:37 +01:00
{
DB : db . DB ,
Description : "back fill user project limits from existing registration tokens" ,
Version : 120 ,
SeparateTx : true ,
Action : migrate . SQL {
` UPDATE users SET project_limit = registration_tokens.project_limit FROM registration_tokens WHERE users.id = registration_tokens.owner_id; ` ,
} ,
} ,
2020-07-23 13:36:56 +01:00
{
DB : db . DB ,
Description : "drop tables related to credits (old deposit bonuses)" ,
Version : 121 ,
Action : migrate . SQL {
` DROP TABLE credits; ` ,
` DROP TABLE credits_spendings; ` ,
} ,
} ,
2020-08-10 13:02:44 +01:00
{
DB : db . DB ,
Description : "drop project_invoice_stamps table" ,
Version : 122 ,
Action : migrate . SQL {
` DROP TABLE project_invoice_stamps; ` ,
} ,
} ,
2020-08-28 20:43:53 +01:00
{
DB : db . DB ,
Description : "drop project_invoice_stamps table" ,
Version : 123 ,
Action : migrate . SQL {
` ALTER TABLE nodes ADD COLUMN online_score double precision NOT NULL DEFAULT 1; ` ,
} ,
} ,
2020-09-08 21:55:32 +01:00
{
DB : db . DB ,
Description : "add column and index updated_at to injuredsegments" ,
Version : 124 ,
Action : migrate . SQL {
` ALTER TABLE injuredsegments ADD COLUMN updated_at timestamp with time zone NOT NULL DEFAULT current_timestamp; ` ,
` CREATE INDEX injuredsegments_updated_at_index ON injuredsegments ( updated_at ); ` ,
} ,
} ,
2019-02-14 21:55:21 +00:00
} ,
}
}