github.com/rkt/rkt@v1.30.1-0.20200224141603-171c416fac02/store/imagestore/aciinfo.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  	"strings"
    21  	"time"
    22  )
    23  
    24  // ACIFetchInfo is used to store information about the fetching process of an ACI.
    25  type ACIFetchInfo struct {
    26  	// Latest defines if the ACI was imported using the latest pattern
    27  	// (no version label was provided on ACI discovery).
    28  	Latest bool
    29  }
    30  
    31  // ACIInfo is used to store information about an ACI.
    32  type ACIInfo struct {
    33  	// BlobKey is the key in the blob/imageManifest store of the related
    34  	// ACI file and is the db primary key.
    35  	BlobKey string
    36  	// Name is the name of the ACI.
    37  	Name string
    38  	// ImportTime is the time this ACI was imported in the store.
    39  	ImportTime time.Time
    40  	// LastUsed is the last time this image was read
    41  	LastUsed time.Time
    42  	// Size is the size in bytes of this image in the store
    43  	Size int64
    44  	// TreeStoreSize is the size in bytes of this image in the tree store
    45  	TreeStoreSize int64
    46  	// Latest defines if the ACI was imported using the latest pattern (no
    47  	// version label was provided on ACI discovery)
    48  	Latest bool
    49  }
    50  
    51  func NewACIInfo(blobKey string, latest bool, t time.Time, size int64, treeStoreSize int64) *ACIInfo {
    52  	return &ACIInfo{
    53  		BlobKey:       blobKey,
    54  		Latest:        latest,
    55  		ImportTime:    t,
    56  		LastUsed:      time.Now(),
    57  		Size:          size,
    58  		TreeStoreSize: treeStoreSize,
    59  	}
    60  }
    61  
    62  func aciinfoRowScan(rows *sql.Rows, aciinfo *ACIInfo) error {
    63  	// This ordering MUST match that in schema.go
    64  	return rows.Scan(&aciinfo.BlobKey, &aciinfo.Name, &aciinfo.ImportTime, &aciinfo.LastUsed, &aciinfo.Latest, &aciinfo.Size, &aciinfo.TreeStoreSize)
    65  }
    66  
    67  // GetAciInfosWithKeyPrefix returns all the ACIInfos with a blobkey starting with the given prefix.
    68  func GetACIInfosWithKeyPrefix(tx *sql.Tx, prefix string) ([]*ACIInfo, error) {
    69  	var aciinfos []*ACIInfo
    70  	rows, err := tx.Query("SELECT * from aciinfo WHERE hasPrefix(blobkey, $1)", prefix)
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  	defer rows.Close()
    75  	for rows.Next() {
    76  		aciinfo := &ACIInfo{}
    77  		if err := aciinfoRowScan(rows, aciinfo); err != nil {
    78  			return nil, err
    79  		}
    80  		aciinfos = append(aciinfos, aciinfo)
    81  	}
    82  	if err := rows.Err(); err != nil {
    83  		return nil, err
    84  	}
    85  	return aciinfos, err
    86  }
    87  
    88  // GetAciInfosWithName returns all the ACIInfos for a given name. found will be
    89  // false if no aciinfo exists.
    90  func GetACIInfosWithName(tx *sql.Tx, name string) ([]*ACIInfo, bool, error) {
    91  	var aciinfos []*ACIInfo
    92  	found := false
    93  	rows, err := tx.Query("SELECT * from aciinfo WHERE name == $1", name)
    94  	if err != nil {
    95  		return nil, false, err
    96  	}
    97  	defer rows.Close()
    98  	for rows.Next() {
    99  		found = true
   100  		aciinfo := &ACIInfo{}
   101  		if err := aciinfoRowScan(rows, aciinfo); err != nil {
   102  			return nil, false, err
   103  		}
   104  		aciinfos = append(aciinfos, aciinfo)
   105  	}
   106  	if err := rows.Err(); err != nil {
   107  		return nil, false, err
   108  	}
   109  	return aciinfos, found, err
   110  }
   111  
   112  // GetAciInfosWithBlobKey returns the ACIInfo with the given blobKey. found will be
   113  // false if no aciinfo exists.
   114  func GetACIInfoWithBlobKey(tx *sql.Tx, blobKey string) (*ACIInfo, bool, error) {
   115  	aciinfo := &ACIInfo{}
   116  	found := false
   117  	rows, err := tx.Query("SELECT * from aciinfo WHERE blobkey == $1", blobKey)
   118  	if err != nil {
   119  		return nil, false, err
   120  	}
   121  	defer rows.Close()
   122  	for rows.Next() {
   123  		found = true
   124  		if err := aciinfoRowScan(rows, aciinfo); err != nil {
   125  			return nil, false, err
   126  		}
   127  		// No more than one row for blobkey must exist.
   128  		break
   129  	}
   130  	if err := rows.Err(); err != nil {
   131  		return nil, false, err
   132  	}
   133  	return aciinfo, found, err
   134  }
   135  
   136  // GetAllACIInfos returns all the ACIInfos sorted by optional sortfields and
   137  // with ascending or descending order.
   138  func GetAllACIInfos(tx *sql.Tx, sortfields []string, ascending bool) ([]*ACIInfo, error) {
   139  	var aciinfos []*ACIInfo
   140  	query := "SELECT * from aciinfo"
   141  	if len(sortfields) > 0 {
   142  		query += fmt.Sprintf(" ORDER BY %s ", strings.Join(sortfields, ", "))
   143  		if ascending {
   144  			query += "ASC"
   145  		} else {
   146  			query += "DESC"
   147  		}
   148  	}
   149  	rows, err := tx.Query(query)
   150  	if err != nil {
   151  		return nil, err
   152  	}
   153  	defer rows.Close()
   154  	for rows.Next() {
   155  		aciinfo := &ACIInfo{}
   156  		if err := aciinfoRowScan(rows, aciinfo); err != nil {
   157  			return nil, err
   158  		}
   159  		aciinfos = append(aciinfos, aciinfo)
   160  	}
   161  	if err := rows.Err(); err != nil {
   162  		return nil, err
   163  	}
   164  	return aciinfos, err
   165  }
   166  
   167  // WriteACIInfo adds or updates the provided aciinfo.
   168  func WriteACIInfo(tx *sql.Tx, aciinfo *ACIInfo) error {
   169  	// ql doesn't have an INSERT OR UPDATE function so
   170  	// it's faster to remove and reinsert the row
   171  	_, err := tx.Exec("DELETE from aciinfo where blobkey == $1", aciinfo.BlobKey)
   172  	if err != nil {
   173  		return err
   174  	}
   175  	_, err = tx.Exec("INSERT into aciinfo (blobkey, name, importtime, lastused, latest, size, treestoresize) VALUES ($1, $2, $3, $4, $5, $6, $7)", aciinfo.BlobKey, aciinfo.Name, aciinfo.ImportTime, aciinfo.LastUsed, aciinfo.Latest, aciinfo.Size, aciinfo.TreeStoreSize)
   176  	if err != nil {
   177  		return err
   178  	}
   179  
   180  	return nil
   181  }
   182  
   183  // RemoveACIInfo removes the ACIInfo with the given blobKey.
   184  func RemoveACIInfo(tx *sql.Tx, blobKey string) error {
   185  	_, err := tx.Exec("DELETE from aciinfo where blobkey == $1", blobKey)
   186  	if err != nil {
   187  		return err
   188  	}
   189  	return nil
   190  }