github.com/rkt/rkt@v1.30.1-0.20200224141603-171c416fac02/store/imagestore/migrate.go (about)

     1  // Copyright 2015 The rkt Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package imagestore
    16  
    17  import (
    18  	"database/sql"
    19  	"fmt"
    20  	"time"
    21  
    22  	"github.com/hashicorp/errwrap"
    23  	"github.com/jonboulle/clockwork"
    24  )
    25  
    26  type migrateFunc func(*sql.Tx) error
    27  
    28  var (
    29  	// migrateTable is a map of migrate functions. The key is the db
    30  	// version to migrate to.
    31  	migrateTable = map[int]migrateFunc{
    32  		1: migrateToV1,
    33  		2: migrateToV2,
    34  		3: migrateToV3,
    35  		4: migrateToV4,
    36  		5: migrateToV5,
    37  		6: migrateToV6,
    38  		7: migrateToV7,
    39  	}
    40  
    41  	clock = clockwork.NewRealClock()
    42  )
    43  
    44  func migrate(tx *sql.Tx, finalVersion int) error {
    45  	if finalVersion > dbVersion {
    46  		return fmt.Errorf("required migrate final version greater than the last supported db version")
    47  	}
    48  	version, err := getDBVersion(tx)
    49  	if err != nil {
    50  		return err
    51  	}
    52  
    53  	for v := version + 1; v <= finalVersion; v++ {
    54  		migrate, ok := migrateTable[v]
    55  		if !ok {
    56  			return fmt.Errorf("missing migrate function for version %d", v)
    57  		}
    58  
    59  		if err := migrate(tx); err != nil {
    60  			return errwrap.Wrap(fmt.Errorf("failed to migrate db to version %d", v), err)
    61  		}
    62  
    63  		if err := updateDBVersion(tx, v); err != nil {
    64  			return errwrap.Wrap(fmt.Errorf("updateDBVersion() failed to update the db to version %d", v), err)
    65  		}
    66  	}
    67  	return nil
    68  }
    69  
    70  func migrateToV1(tx *sql.Tx) error {
    71  	return nil
    72  }
    73  
    74  func migrateToV2(tx *sql.Tx) error {
    75  	_, err := tx.Exec("ALTER TABLE remote ADD cachemaxage int")
    76  	if err != nil {
    77  		return err
    78  	}
    79  	_, err = tx.Exec("ALTER TABLE remote ADD downloadedtime time")
    80  	if err != nil {
    81  		return err
    82  	}
    83  	// Set the default values for the new columns on the current rows
    84  	_, err = tx.Exec("UPDATE remote cachemaxage = 0")
    85  	if err != nil {
    86  		return err
    87  	}
    88  	t := time.Time{}.UTC()
    89  	_, err = tx.Exec("UPDATE remote downloadedtime = $1", t)
    90  	if err != nil {
    91  		return err
    92  	}
    93  	return nil
    94  }
    95  
    96  func migrateToV3(tx *sql.Tx) error {
    97  	for _, t := range []string{
    98  		"CREATE TABLE aciinfo_tmp (blobkey string, name string, importtime time, latest bool);",
    99  		"INSERT INTO aciinfo_tmp (blobkey, name, importtime, latest) SELECT blobkey, appname, importtime, latest from aciinfo",
   100  		"DROP TABLE aciinfo",
   101  		"CREATE TABLE aciinfo (blobkey string, name string, importtime time, latest bool);",
   102  		"CREATE UNIQUE INDEX IF NOT EXISTS blobkeyidx ON aciinfo (blobkey)",
   103  		"CREATE INDEX IF NOT EXISTS nameidx ON aciinfo (name)",
   104  		"INSERT INTO aciinfo SELECT * from aciinfo_tmp",
   105  		"DROP TABLE aciinfo_tmp",
   106  	} {
   107  		_, err := tx.Exec(t)
   108  		if err != nil {
   109  			return err
   110  		}
   111  	}
   112  	return nil
   113  }
   114  
   115  func migrateToV4(tx *sql.Tx) error {
   116  	for _, t := range []string{
   117  		"CREATE TABLE aciinfo_tmp (blobkey string, name string, importtime time, lastusedtime time, latest bool);",
   118  		"INSERT INTO aciinfo_tmp (blobkey, name, importtime, latest) SELECT blobkey, name, importtime, latest from aciinfo",
   119  		"DROP TABLE aciinfo",
   120  		// We don't use now() as a DEFAULT for lastusedtime because it doesn't
   121  		// return a UTC time, which is what we want. Instead, we UPDATE it
   122  		// below.
   123  		"CREATE TABLE aciinfo (blobkey string, name string, importtime time, lastusedtime time, latest bool);",
   124  		"CREATE UNIQUE INDEX IF NOT EXISTS blobkeyidx ON aciinfo (blobkey)",
   125  		"CREATE INDEX IF NOT EXISTS nameidx ON aciinfo (name)",
   126  		"INSERT INTO aciinfo SELECT * from aciinfo_tmp",
   127  		"DROP TABLE aciinfo_tmp",
   128  	} {
   129  		_, err := tx.Exec(t)
   130  		if err != nil {
   131  			return err
   132  		}
   133  	}
   134  	t := clock.Now().UTC()
   135  	_, err := tx.Exec("UPDATE aciinfo lastusedtime = $1", t)
   136  	if err != nil {
   137  		return err
   138  	}
   139  	return nil
   140  }
   141  
   142  func migrateToV5(tx *sql.Tx) error {
   143  	for _, t := range []string{
   144  		"CREATE TABLE aciinfo_tmp (blobkey string, name string, importtime time, lastused time, latest bool, size int64, treestoresize int64);",
   145  		"INSERT INTO aciinfo_tmp (blobkey, name, importtime, lastused, latest) SELECT blobkey, name, importtime, lastusedtime, latest from aciinfo",
   146  		"DROP TABLE aciinfo",
   147  		"CREATE TABLE aciinfo (blobkey string, name string, importtime time, lastused time, latest bool, size int64 DEFAULT 0, treestoresize int64 DEFAULT 0);",
   148  		"CREATE UNIQUE INDEX IF NOT EXISTS blobkeyidx ON aciinfo (blobkey)",
   149  		"CREATE INDEX IF NOT EXISTS nameidx ON aciinfo (name)",
   150  		"INSERT INTO aciinfo SELECT * from aciinfo_tmp",
   151  		"DROP TABLE aciinfo_tmp",
   152  	} {
   153  		_, err := tx.Exec(t)
   154  		if err != nil {
   155  			return err
   156  		}
   157  	}
   158  
   159  	return nil
   160  }
   161  
   162  func migrateToV6(tx *sql.Tx) error {
   163  	for _, t := range []string{
   164  		"CREATE TABLE aciinfo_tmp (blobkey string, name string, importtime time, lastused time, latest bool, size int64, treestoresize int64, insecureoptions int64 DEFAULT 0);",
   165  		"INSERT INTO aciinfo_tmp (blobkey, name, importtime, lastused, latest, size, treestoresize) SELECT blobkey, name, importtime, lastused, latest, size, treestoresize from aciinfo",
   166  		"DROP TABLE aciinfo",
   167  		"CREATE TABLE aciinfo (blobkey string, name string, importtime time, lastused time, latest bool, size int64 DEFAULT 0, treestoresize int64 DEFAULT 0, insecureoptions int64 DEFAULT 0);",
   168  		"CREATE UNIQUE INDEX IF NOT EXISTS blobkeyidx ON aciinfo (blobkey)",
   169  		"CREATE INDEX IF NOT EXISTS nameidx ON aciinfo (name)",
   170  		"INSERT INTO aciinfo SELECT * from aciinfo_tmp",
   171  		"DROP TABLE aciinfo_tmp",
   172  	} {
   173  		_, err := tx.Exec(t)
   174  		if err != nil {
   175  			return err
   176  		}
   177  	}
   178  
   179  	return nil
   180  }
   181  
   182  func migrateToV7(tx *sql.Tx) error {
   183  	for _, t := range []string{
   184  		"CREATE TABLE aciinfo_tmp (blobkey string, name string, importtime time, lastused time, latest bool, size int64, treestoresize int64, insecureoptions int64 DEFAULT 0);",
   185  		"INSERT INTO aciinfo_tmp (blobkey, name, importtime, lastused, latest, size, treestoresize) SELECT blobkey, name, importtime, lastused, latest, size, treestoresize from aciinfo",
   186  		"DROP TABLE aciinfo",
   187  		"CREATE TABLE aciinfo (blobkey string, name string, importtime time, lastused time, latest bool, size int64 DEFAULT 0, treestoresize int64 DEFAULT 0);",
   188  		"CREATE UNIQUE INDEX IF NOT EXISTS blobkeyidx ON aciinfo (blobkey)",
   189  		"CREATE INDEX IF NOT EXISTS nameidx ON aciinfo (name)",
   190  		"INSERT INTO aciinfo SELECT blobkey, name, importtime, lastused, latest, size, treestoresize from aciinfo_tmp",
   191  		"DROP TABLE aciinfo_tmp",
   192  	} {
   193  		_, err := tx.Exec(t)
   194  		if err != nil {
   195  			return err
   196  		}
   197  	}
   198  
   199  	return nil
   200  }