Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(143)

Side by Side Diff: go/database/database.go

Issue 813443002: Overhaul database package (Closed) Base URL: https://skia.googlesource.com/buildbot@master
Patch Set: Add README for database package, re-add *.db to .gitignore Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 package database 1 package database
2 2
3 import ( 3 import (
4 "database/sql" 4 "database/sql"
5 "fmt" 5 "fmt"
6 "time" 6 "time"
7 7
8 _ "github.com/go-sql-driver/mysql" 8 _ "github.com/go-sql-driver/mysql"
9 "github.com/golang/glog" 9 "github.com/golang/glog"
10 _ "github.com/mattn/go-sqlite3"
11 "skia.googlesource.com/buildbot.git/go/util" 10 "skia.googlesource.com/buildbot.git/go/util"
12 ) 11 )
13 12
13 const (
14 // Template for DB connection strings.
15 DB_CONN_TMPL = "%s:%s@%s/%s?parseTime=true"
16
17 // Local test database.
18 TEST_DATABASE = "sk_testing"
19 TEST_DB_HOST = ""
20 TEST_USER = "test_user"
21 TEST_PASSWORD = ""
22 )
23
14 // Config information to create a database connection. 24 // Config information to create a database connection.
15 type DatabaseConfig struct { 25 type DatabaseConfig struct {
16 MySQLString string 26 MySQLString string
17 SQLiteFilePath string
18 MigrationSteps []MigrationStep 27 MigrationSteps []MigrationStep
19 } 28 }
20 29
30 func NewDatabaseConfig(user, password, host, database string, m []MigrationStep) *DatabaseConfig {
31 return &DatabaseConfig{
32 MySQLString: fmt.Sprintf(DB_CONN_TMPL, user, password, host, database),
33 MigrationSteps: m,
34 }
35 }
36
37 func LocalTestDatabaseConfig(m []MigrationStep) *DatabaseConfig {
38 return NewDatabaseConfig(TEST_USER, TEST_PASSWORD, TEST_DB_HOST, TEST_DA TABASE, m)
39 }
40
21 // Single step to migrated from one database version to the next and back. 41 // Single step to migrated from one database version to the next and back.
22 type MigrationStep struct { 42 type MigrationStep struct {
23 » MySQLUp []string 43 » MySQLUp []string
24 » MySQLDown []string 44 » MySQLDown []string
25 » SQLiteUp []string
26 » SQLiteDown []string
27 } 45 }
28 46
29 // Database handle to send queries to the underlying database. 47 // Database handle to send queries to the underlying database.
30 type VersionedDB struct { 48 type VersionedDB struct {
31 » // Database intance that is either backed by SQLite or MySQl. 49 » // Database intance that is backed by MySQL.
32 DB *sql.DB 50 DB *sql.DB
33 51
34 // Keeps track if we are connected to MySQL or SQLite
35 IsMySQL bool
36
37 // List of migration steps for this database. 52 // List of migration steps for this database.
38 migrationSteps []MigrationStep 53 migrationSteps []MigrationStep
39 } 54 }
40 55
41 // Init must be called once before DB is used. 56 // Init must be called once before DB is used.
42 // 57 //
43 // Since it used glog, make sure it is also called after flag.Parse is called. 58 // Since it used glog, make sure it is also called after flag.Parse is called.
44 func NewVersionedDB(conf *DatabaseConfig) *VersionedDB { 59 func NewVersionedDB(conf *DatabaseConfig) *VersionedDB {
45 // If there is a connection string then connect to the MySQL server. 60 // If there is a connection string then connect to the MySQL server.
46 // This is for testing only. In production we get the relevant informati on 61 // This is for testing only. In production we get the relevant informati on
47 // from the metadata server. 62 // from the metadata server.
48 var err error 63 var err error
49 var isMySQL = true
50 var DB *sql.DB = nil 64 var DB *sql.DB = nil
51 65
52 » if conf.MySQLString != "" { 66 » glog.Infoln("Opening SQL database.")
53 » » glog.Infoln("Opening SQL database.") 67 » if DB, err = sql.Open("mysql", conf.MySQLString); err == nil {
54 » » if DB, err = sql.Open("mysql", conf.MySQLString); err == nil { 68 » » glog.Infoln("Sending Ping.")
55 » » » glog.Infoln("Sending Ping.") 69 » » err = DB.Ping()
56 » » » err = DB.Ping() 70 » }
57 » » }
58 71
59 » » if err != nil { 72 » if err != nil {
60 » » » glog.Fatalln("Failed to open connection to SQL server:", err) 73 » » glog.Fatalln("Failed to open connection to SQL server:", err)
61 » » }
62 » } else {
63 » » // Open a local SQLite database instead.
64 » » glog.Infof("Opening local sqlite database at: %s", conf.SQLiteFi lePath)
65 » » // Fallback to sqlite for local use.
66 » » DB, err = sql.Open("sqlite3", conf.SQLiteFilePath)
67 » » if err != nil {
68 » » » glog.Fatalln("Failed to open:", err)
69 » » }
70 » » isMySQL = false
71 } 74 }
72 75
73 result := &VersionedDB{ 76 result := &VersionedDB{
74 DB: DB, 77 DB: DB,
75 IsMySQL: isMySQL,
76 migrationSteps: conf.MigrationSteps, 78 migrationSteps: conf.MigrationSteps,
77 } 79 }
78 80
79 // Make sure the migration table exists. 81 // Make sure the migration table exists.
80 if err := result.checkVersionTable(); err != nil { 82 if err := result.checkVersionTable(); err != nil {
81 // We are using panic() instead of Fataln() to be able to trap t his 83 // We are using panic() instead of Fataln() to be able to trap t his
82 // in tests and make sure it fails when no version table exists. 84 // in tests and make sure it fails when no version table exists.
83 glog.Errorln("Unable to create version table.") 85 glog.Errorln("Unable to create version table.")
84 panic("Attempt to create version table returned: " + err.Error() ) 86 panic("Attempt to create version table returned: " + err.Error() )
85 } 87 }
86 glog.Infoln("Version table OK.") 88 glog.Infoln("Version table OK.")
87 89
88 // Migrate to the latest version if we are using SQLite, so we don't hav e
89 // to run the *_migratdb command for a local database.
90 if !result.IsMySQL {
91 result.Migrate(result.MaxDBVersion())
92 }
93
94 // Ping the database occasionally to keep the connection fresh. 90 // Ping the database occasionally to keep the connection fresh.
95 go func() { 91 go func() {
96 c := time.Tick(1 * time.Minute) 92 c := time.Tick(1 * time.Minute)
97 for _ = range c { 93 for _ = range c {
98 if err := result.DB.Ping(); err != nil { 94 if err := result.DB.Ping(); err != nil {
99 glog.Warningln("Database failed to respond:", er r) 95 glog.Warningln("Database failed to respond:", er r)
100 } 96 }
101 glog.Infof("db: Successful ping") 97 glog.Infof("db: Successful ping")
102 } 98 }
103 }() 99 }()
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 return version, err 174 return version, err
179 } 175 }
180 176
181 // Returns the highest version currently available. 177 // Returns the highest version currently available.
182 func (vdb *VersionedDB) MaxDBVersion() int { 178 func (vdb *VersionedDB) MaxDBVersion() int {
183 return len(vdb.migrationSteps) 179 return len(vdb.migrationSteps)
184 } 180 }
185 181
186 // Returns an error if the version table does not exist. 182 // Returns an error if the version table does not exist.
187 func (vdb *VersionedDB) checkVersionTable() error { 183 func (vdb *VersionedDB) checkVersionTable() error {
188 » // Check if the table exists in MySQL or SQLite. 184 » // Check if the table exists in MySQL.
189 stmt := "SHOW TABLES LIKE 'sk_db_version'" 185 stmt := "SHOW TABLES LIKE 'sk_db_version'"
190 if !vdb.IsMySQL {
191 stmt = "SELECT name FROM sqlite_master WHERE type='table' AND na me='sk_db_version';"
192 }
193 186
194 var temp string 187 var temp string
195 err := vdb.DB.QueryRow(stmt).Scan(&temp) 188 err := vdb.DB.QueryRow(stmt).Scan(&temp)
196 if err != nil { 189 if err != nil {
197 // See if we can create the version table. 190 // See if we can create the version table.
198 return vdb.ensureVersionTable() 191 return vdb.ensureVersionTable()
199 } 192 }
200 193
201 return nil 194 return nil
202 } 195 }
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 if inc < 0 { 249 if inc < 0 {
257 idx = currentVersion - 1 250 idx = currentVersion - 1
258 } 251 }
259 delta := util.AbsInt(targetVersion - currentVersion) 252 delta := util.AbsInt(targetVersion - currentVersion)
260 result := make([][]string, 0, delta) 253 result := make([][]string, 0, delta)
261 254
262 for i := 0; i < delta; i++ { 255 for i := 0; i < delta; i++ {
263 var temp []string 256 var temp []string
264 switch { 257 switch {
265 // using mysqlp 258 // using mysqlp
266 » » case (inc > 0) && vdb.IsMySQL: 259 » » case (inc > 0):
267 temp = vdb.migrationSteps[idx].MySQLUp 260 temp = vdb.migrationSteps[idx].MySQLUp
268 » » case (inc < 0) && vdb.IsMySQL: 261 » » case (inc < 0):
269 temp = vdb.migrationSteps[idx].MySQLDown 262 temp = vdb.migrationSteps[idx].MySQLDown
270 // using sqlite
271 case (inc > 0):
272 temp = vdb.migrationSteps[idx].SQLiteUp
273 case (inc < 0):
274 temp = vdb.migrationSteps[idx].SQLiteDown
275 } 263 }
276 result = append(result, temp) 264 result = append(result, temp)
277 idx += inc 265 idx += inc
278 } 266 }
279 return result 267 return result
280 } 268 }
OLDNEW
« go/database/README ('K') | « go/database/README ('k') | go/database/setup_test_db » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698