Store PotentialNamespace in database
PotentialNamespace is part of layer_feature table and it is also stored in namespace table.
This commit is contained in:
parent
34c2d96b36
commit
44c4a6f3ce
@ -17,6 +17,7 @@ package database
|
|||||||
import (
|
import (
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/coreos/clair/pkg/pagination"
|
"github.com/coreos/clair/pkg/pagination"
|
||||||
@ -123,10 +124,13 @@ func (l *Layer) GetFeatures() []Feature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *Layer) GetNamespaces() []Namespace {
|
func (l *Layer) GetNamespaces() []Namespace {
|
||||||
namespaces := make([]Namespace, 0, len(l.Namespaces))
|
namespaces := make([]Namespace, 0, len(l.Namespaces)+len(l.Features))
|
||||||
for _, ns := range l.Namespaces {
|
for _, ns := range l.Namespaces {
|
||||||
namespaces = append(namespaces, ns.Namespace)
|
namespaces = append(namespaces, ns.Namespace)
|
||||||
}
|
}
|
||||||
|
for _, f := range l.Features {
|
||||||
|
namespaces = append(namespaces, f.Feature.PotentialNamespace)
|
||||||
|
}
|
||||||
|
|
||||||
return namespaces
|
return namespaces
|
||||||
}
|
}
|
||||||
@ -195,6 +199,10 @@ type NamespacedFeature struct {
|
|||||||
Namespace Namespace `json:"namespace"`
|
Namespace Namespace `json:"namespace"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (nf *NamespacedFeature) Key() string {
|
||||||
|
return fmt.Sprintf("%s-%s-%s-%s-%s-%s", nf.Name, nf.Version, nf.VersionFormat, nf.Type, nf.Namespace.Name, nf.Namespace.VersionFormat)
|
||||||
|
}
|
||||||
|
|
||||||
func NewNamespacedFeature(namespace *Namespace, feature *Feature) *NamespacedFeature {
|
func NewNamespacedFeature(namespace *Namespace, feature *Feature) *NamespacedFeature {
|
||||||
// TODO: namespaced feature should use pointer values
|
// TODO: namespaced feature should use pointer values
|
||||||
return &NamespacedFeature{*feature, *namespace}
|
return &NamespacedFeature{*feature, *namespace}
|
||||||
|
@ -17,6 +17,7 @@ package pgsql
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/lib/pq"
|
"github.com/lib/pq"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@ -311,7 +312,7 @@ func (tx *pgSession) findNamespacedFeatureIDs(nfs []database.NamespacedFeature)
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
nfsMap := map[database.NamespacedFeature]int64{}
|
nfsMap := map[string]int64{}
|
||||||
keys := make([]interface{}, 0, len(nfs)*5)
|
keys := make([]interface{}, 0, len(nfs)*5)
|
||||||
for _, nf := range nfs {
|
for _, nf := range nfs {
|
||||||
keys = append(keys, nf.Name, nf.Version, nf.VersionFormat, nf.Type, nf.Namespace.Name)
|
keys = append(keys, nf.Name, nf.Version, nf.VersionFormat, nf.Type, nf.Namespace.Name)
|
||||||
@ -334,12 +335,12 @@ func (tx *pgSession) findNamespacedFeatureIDs(nfs []database.NamespacedFeature)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, handleError("searchNamespacedFeature", err)
|
return nil, handleError("searchNamespacedFeature", err)
|
||||||
}
|
}
|
||||||
nfsMap[nf] = id
|
nfsMap[nf.Key()] = id
|
||||||
}
|
}
|
||||||
|
|
||||||
ids := make([]sql.NullInt64, len(nfs))
|
ids := make([]sql.NullInt64, len(nfs))
|
||||||
for i, nf := range nfs {
|
for i, nf := range nfs {
|
||||||
if id, ok := nfsMap[nf]; ok {
|
if id, ok := nfsMap[nf.Key()]; ok {
|
||||||
ids[i] = sql.NullInt64{id, true}
|
ids[i] = sql.NullInt64{id, true}
|
||||||
} else {
|
} else {
|
||||||
ids[i] = sql.NullInt64{}
|
ids[i] = sql.NullInt64{}
|
||||||
@ -359,13 +360,14 @@ func (tx *pgSession) findFeatureIDs(fs []database.Feature) ([]sql.NullInt64, err
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fMap := map[database.Feature]sql.NullInt64{}
|
fMap := map[string]sql.NullInt64{}
|
||||||
|
|
||||||
keys := make([]interface{}, 0, len(fs)*4)
|
keys := make([]interface{}, 0, len(fs)*4)
|
||||||
for _, f := range fs {
|
for _, f := range fs {
|
||||||
typeID := types.byName[f.Type]
|
typeID := types.byName[f.Type]
|
||||||
keys = append(keys, f.Name, f.Version, f.VersionFormat, typeID)
|
keys = append(keys, f.Name, f.Version, f.VersionFormat, typeID)
|
||||||
fMap[f] = sql.NullInt64{}
|
mapKey := f.Name + f.Version + f.VersionFormat + strconv.Itoa(typeID)
|
||||||
|
fMap[mapKey] = sql.NullInt64{}
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, err := tx.Query(querySearchFeatureID(len(fs)), keys...)
|
rows, err := tx.Query(querySearchFeatureID(len(fs)), keys...)
|
||||||
@ -386,12 +388,15 @@ func (tx *pgSession) findFeatureIDs(fs []database.Feature) ([]sql.NullInt64, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
f.Type = types.byID[typeID]
|
f.Type = types.byID[typeID]
|
||||||
fMap[f] = id
|
mapKey := f.Name + f.Version + f.VersionFormat + strconv.Itoa(typeID)
|
||||||
|
fMap[mapKey] = id
|
||||||
}
|
}
|
||||||
|
|
||||||
ids := make([]sql.NullInt64, len(fs))
|
ids := make([]sql.NullInt64, len(fs))
|
||||||
for i, f := range fs {
|
for i, f := range fs {
|
||||||
ids[i] = fMap[f]
|
typeID := types.byName[f.Type]
|
||||||
|
mapKey := f.Name + f.Version + f.VersionFormat + strconv.Itoa(typeID)
|
||||||
|
ids[i] = fMap[mapKey]
|
||||||
}
|
}
|
||||||
|
|
||||||
return ids, nil
|
return ids, nil
|
||||||
|
@ -182,7 +182,7 @@ func TestFindNamespacedFeatureIDs(t *testing.T) {
|
|||||||
expectedIDs = append(expectedIDs, 1)
|
expectedIDs = append(expectedIDs, 1)
|
||||||
|
|
||||||
namespace := realNamespaces[1]
|
namespace := realNamespaces[1]
|
||||||
features = append(features, *database.NewNamespacedFeature(&namespace, database.NewBinaryPackage("not-found", "1.0", "dpkg"))) // test not found feature
|
features = append(features, *database.NewNamespacedFeature(&namespace, database.NewBinaryPackage("not-found", "1.0", "dpkg", database.Namespace{}))) // test not found feature
|
||||||
|
|
||||||
ids, err := tx.findNamespacedFeatureIDs(features)
|
ids, err := tx.findNamespacedFeatureIDs(features)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
@ -37,10 +37,11 @@ const (
|
|||||||
SELECT id FROM layer WHERE hash = $1`
|
SELECT id FROM layer WHERE hash = $1`
|
||||||
|
|
||||||
findLayerFeatures = `
|
findLayerFeatures = `
|
||||||
SELECT f.name, f.version, f.version_format, t.name, lf.detector_id
|
SELECT f.name, f.version, f.version_format, t.name, lf.detector_id, ns.name, ns.version_format
|
||||||
FROM layer_feature AS lf, feature AS f, feature_type AS t
|
FROM layer_feature AS lf, feature AS f, feature_type AS t, namespace AS ns
|
||||||
WHERE lf.feature_id = f.id
|
WHERE lf.feature_id = f.id
|
||||||
AND t.id = f.type
|
AND t.id = f.type
|
||||||
|
AND lf.namespace_id = ns.id
|
||||||
AND lf.layer_id = $1`
|
AND lf.layer_id = $1`
|
||||||
|
|
||||||
findLayerNamespaces = `
|
findLayerNamespaces = `
|
||||||
@ -61,9 +62,10 @@ type dbLayerNamespace struct {
|
|||||||
|
|
||||||
// dbLayerFeature represents the layer_feature table
|
// dbLayerFeature represents the layer_feature table
|
||||||
type dbLayerFeature struct {
|
type dbLayerFeature struct {
|
||||||
layerID int64
|
layerID int64
|
||||||
featureID int64
|
featureID int64
|
||||||
detectorID int64
|
detectorID int64
|
||||||
|
namespaceID int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *pgSession) FindLayer(hash string) (database.Layer, bool, error) {
|
func (tx *pgSession) FindLayer(hash string) (database.Layer, bool, error) {
|
||||||
@ -199,10 +201,16 @@ func (tx *pgSession) persistAllLayerFeatures(layerID int64, features []database.
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
var namespaces []database.Namespace
|
||||||
|
for _, feature := range features {
|
||||||
|
namespaces = append(namespaces, feature.PotentialNamespace)
|
||||||
|
}
|
||||||
|
nameSpaceIDs, _ := tx.findNamespaceIDs(namespaces)
|
||||||
|
featureNamespaceMap := map[database.Namespace]sql.NullInt64{}
|
||||||
rawFeatures := make([]database.Feature, 0, len(features))
|
rawFeatures := make([]database.Feature, 0, len(features))
|
||||||
for _, f := range features {
|
for i, f := range features {
|
||||||
rawFeatures = append(rawFeatures, f.Feature)
|
rawFeatures = append(rawFeatures, f.Feature)
|
||||||
|
featureNamespaceMap[f.PotentialNamespace] = nameSpaceIDs[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
featureIDs, err := tx.findFeatureIDs(rawFeatures)
|
featureIDs, err := tx.findFeatureIDs(rawFeatures)
|
||||||
@ -213,12 +221,16 @@ func (tx *pgSession) persistAllLayerFeatures(layerID int64, features []database.
|
|||||||
dbFeatures := make([]dbLayerFeature, 0, len(features))
|
dbFeatures := make([]dbLayerFeature, 0, len(features))
|
||||||
for i, f := range features {
|
for i, f := range features {
|
||||||
detectorID := detectorMap.byValue[f.By]
|
detectorID := detectorMap.byValue[f.By]
|
||||||
featureID := featureIDs[i].Int64
|
|
||||||
if !featureIDs[i].Valid {
|
if !featureIDs[i].Valid {
|
||||||
return database.ErrMissingEntities
|
return database.ErrMissingEntities
|
||||||
}
|
}
|
||||||
|
featureID := featureIDs[i].Int64
|
||||||
|
if !featureNamespaceMap[f.PotentialNamespace].Valid {
|
||||||
|
return database.ErrMissingEntities
|
||||||
|
}
|
||||||
|
namespaceID := featureNamespaceMap[f.PotentialNamespace].Int64
|
||||||
|
|
||||||
dbFeatures = append(dbFeatures, dbLayerFeature{layerID, featureID, detectorID})
|
dbFeatures = append(dbFeatures, dbLayerFeature{layerID, featureID, detectorID, namespaceID})
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tx.persistLayerFeatures(dbFeatures); err != nil {
|
if err := tx.persistLayerFeatures(dbFeatures); err != nil {
|
||||||
@ -236,9 +248,9 @@ func (tx *pgSession) persistLayerFeatures(features []dbLayerFeature) error {
|
|||||||
sort.Slice(features, func(i, j int) bool {
|
sort.Slice(features, func(i, j int) bool {
|
||||||
return features[i].featureID < features[j].featureID
|
return features[i].featureID < features[j].featureID
|
||||||
})
|
})
|
||||||
keys := make([]interface{}, 0, len(features)*3)
|
keys := make([]interface{}, 0, len(features)*4)
|
||||||
for _, f := range features {
|
for _, f := range features {
|
||||||
keys = append(keys, f.layerID, f.featureID, f.detectorID)
|
keys = append(keys, f.layerID, f.featureID, f.detectorID, f.namespaceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := tx.Exec(queryPersistLayerFeature(len(features)), keys...)
|
_, err := tx.Exec(queryPersistLayerFeature(len(features)), keys...)
|
||||||
@ -308,7 +320,7 @@ func (tx *pgSession) findLayerFeatures(layerID int64, detectors detectorMap) ([]
|
|||||||
detectorID int64
|
detectorID int64
|
||||||
feature database.LayerFeature
|
feature database.LayerFeature
|
||||||
)
|
)
|
||||||
if err := rows.Scan(&feature.Name, &feature.Version, &feature.VersionFormat, &feature.Type, &detectorID); err != nil {
|
if err := rows.Scan(&feature.Name, &feature.Version, &feature.VersionFormat, &feature.Type, &detectorID, &feature.PotentialNamespace.Name, &feature.PotentialNamespace.VersionFormat); err != nil {
|
||||||
return nil, handleError("findLayerFeatures", err)
|
return nil, handleError("findLayerFeatures", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +89,7 @@ var (
|
|||||||
layer_id INT REFERENCES layer ON DELETE CASCADE,
|
layer_id INT REFERENCES layer ON DELETE CASCADE,
|
||||||
feature_id INT REFERENCES feature ON DELETE CASCADE,
|
feature_id INT REFERENCES feature ON DELETE CASCADE,
|
||||||
detector_id INT REFERENCES detector ON DELETE CASCADE,
|
detector_id INT REFERENCES detector ON DELETE CASCADE,
|
||||||
|
namespace_id INT REFERENCES namespace ON DELETE CASCADE,
|
||||||
UNIQUE (layer_id, feature_id));`,
|
UNIQUE (layer_id, feature_id));`,
|
||||||
`CREATE INDEX ON layer_feature(layer_id);`,
|
`CREATE INDEX ON layer_feature(layer_id);`,
|
||||||
|
|
||||||
|
@ -124,7 +124,8 @@ func queryPersistLayerFeature(count int) string {
|
|||||||
"layer_feature_layer_id_feature_id_key",
|
"layer_feature_layer_id_feature_id_key",
|
||||||
"layer_id",
|
"layer_id",
|
||||||
"feature_id",
|
"feature_id",
|
||||||
"detector_id")
|
"detector_id",
|
||||||
|
"namespace_id")
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryPersistNamespace(count int) string {
|
func queryPersistNamespace(count int) string {
|
||||||
|
Loading…
Reference in New Issue
Block a user