/
aciinfo.go
179 lines (167 loc) · 5.23 KB
/
aciinfo.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// Copyright 2015 The rkt Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package store
import (
"database/sql"
"fmt"
"strings"
"time"
)
// ACIInfo is used to store information about an ACI.
type ACIInfo struct {
// BlobKey is the key in the blob/imageManifest store of the related
// ACI file and is the db primary key.
BlobKey string
// Name is the name of the ACI.
Name string
// ImportTime is the time this ACI was imported in the store.
ImportTime time.Time
// LastUsed is the last time this image was read
LastUsed time.Time
// Size is the size in bytes of this image in the store
Size int64
// TreeStoreSize is the size in bytes of this image in the tree store
TreeStoreSize int64
// Latest defines if the ACI was imported using the latest pattern (no
// version label was provided on ACI discovery)
Latest bool
}
func NewACIInfo(blobKey string, latest bool, t time.Time, size int64, treeStoreSize int64) *ACIInfo {
return &ACIInfo{
BlobKey: blobKey,
Latest: latest,
ImportTime: t,
LastUsed: time.Now(),
Size: size,
TreeStoreSize: treeStoreSize,
}
}
func aciinfoRowScan(rows *sql.Rows, aciinfo *ACIInfo) error {
// This ordering MUST match that in schema.go
return rows.Scan(&aciinfo.BlobKey, &aciinfo.Name, &aciinfo.ImportTime, &aciinfo.LastUsed, &aciinfo.Latest, &aciinfo.Size, &aciinfo.TreeStoreSize)
}
// GetAciInfosWithKeyPrefix returns all the ACIInfos with a blobkey starting with the given prefix.
func GetACIInfosWithKeyPrefix(tx *sql.Tx, prefix string) ([]*ACIInfo, error) {
var aciinfos []*ACIInfo
rows, err := tx.Query("SELECT * from aciinfo WHERE hasPrefix(blobkey, $1)", prefix)
if err != nil {
return nil, err
}
for rows.Next() {
aciinfo := &ACIInfo{}
if err := aciinfoRowScan(rows, aciinfo); err != nil {
return nil, err
}
aciinfos = append(aciinfos, aciinfo)
}
if err := rows.Err(); err != nil {
return nil, err
}
return aciinfos, err
}
// GetAciInfosWithName returns all the ACIInfos for a given name. found will be
// false if no aciinfo exists.
func GetACIInfosWithName(tx *sql.Tx, name string) ([]*ACIInfo, bool, error) {
var aciinfos []*ACIInfo
found := false
rows, err := tx.Query("SELECT * from aciinfo WHERE name == $1", name)
if err != nil {
return nil, false, err
}
for rows.Next() {
found = true
aciinfo := &ACIInfo{}
if err := aciinfoRowScan(rows, aciinfo); err != nil {
return nil, false, err
}
aciinfos = append(aciinfos, aciinfo)
}
if err := rows.Err(); err != nil {
return nil, false, err
}
return aciinfos, found, err
}
// GetAciInfosWithBlobKey returns the ACIInfo with the given blobKey. found will be
// false if no aciinfo exists.
func GetACIInfoWithBlobKey(tx *sql.Tx, blobKey string) (*ACIInfo, bool, error) {
aciinfo := &ACIInfo{}
found := false
rows, err := tx.Query("SELECT * from aciinfo WHERE blobkey == $1", blobKey)
if err != nil {
return nil, false, err
}
for rows.Next() {
found = true
if err := aciinfoRowScan(rows, aciinfo); err != nil {
return nil, false, err
}
// No more than one row for blobkey must exist.
break
}
if err := rows.Err(); err != nil {
return nil, false, err
}
return aciinfo, found, err
}
// GetAllACIInfos returns all the ACIInfos sorted by optional sortfields and
// with ascending or descending order.
func GetAllACIInfos(tx *sql.Tx, sortfields []string, ascending bool) ([]*ACIInfo, error) {
var aciinfos []*ACIInfo
query := "SELECT * from aciinfo"
if len(sortfields) > 0 {
query += fmt.Sprintf(" ORDER BY %s ", strings.Join(sortfields, ", "))
if ascending {
query += "ASC"
} else {
query += "DESC"
}
}
rows, err := tx.Query(query)
if err != nil {
return nil, err
}
for rows.Next() {
aciinfo := &ACIInfo{}
if err := aciinfoRowScan(rows, aciinfo); err != nil {
return nil, err
}
aciinfos = append(aciinfos, aciinfo)
}
if err := rows.Err(); err != nil {
return nil, err
}
return aciinfos, err
}
// WriteACIInfo adds or updates the provided aciinfo.
func WriteACIInfo(tx *sql.Tx, aciinfo *ACIInfo) error {
// ql doesn't have an INSERT OR UPDATE function so
// it's faster to remove and reinsert the row
_, err := tx.Exec("DELETE from aciinfo where blobkey == $1", aciinfo.BlobKey)
if err != nil {
return err
}
_, 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)
if err != nil {
return err
}
return nil
}
// RemoveACIInfo removes the ACIInfo with the given blobKey.
func RemoveACIInfo(tx *sql.Tx, blobKey string) error {
_, err := tx.Exec("DELETE from aciinfo where blobkey == $1", blobKey)
if err != nil {
return err
}
return nil
}