Skip to content

Commit

Permalink
matcher: cache query results for the same query
Browse files Browse the repository at this point in the history
There is a possiblity that if the index record is referring to the same
package but different repositories and the Query() function isn't adding
a matcher constraint for the repository, queries to the DB can end up
being identical. This patch makes sure that the same query is only
executed once by caching the results and using them for subsequent
calls.

Signed-off-by: crozzy <[email protected]>
  • Loading branch information
crozzy committed Sep 3, 2024
1 parent 0e59253 commit 12e1dd0
Showing 1 changed file with 25 additions and 6 deletions.
31 changes: 25 additions & 6 deletions datastore/postgres/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ var (
)
)

type recordQuery struct {
record *claircore.IndexRecord
query string
}

// Get implements vulnstore.Vulnerability.
func (s *MatcherStore) Get(ctx context.Context, records []*claircore.IndexRecord, opts datastore.GetOpts) (map[string][]*claircore.Vulnerability, error) {
ctx = zlog.ContextWithValues(ctx, "component", "internal/vulnstore/postgres/Get")
Expand All @@ -46,6 +51,8 @@ func (s *MatcherStore) Get(ctx context.Context, records []*claircore.IndexRecord
defer tx.Rollback(ctx)
// start a batch
batch := &pgx.Batch{}
resCache := map[string]pgx.Rows{}
rqs := []*recordQuery{}
for _, record := range records {
query, err := buildGetQuery(record, &opts)
if err != nil {
Expand All @@ -56,8 +63,13 @@ func (s *MatcherStore) Get(ctx context.Context, records []*claircore.IndexRecord
Msg("could not build query for record")
continue
}
rqs = append(rqs, &recordQuery{query: query, record: record})
if _, ok := resCache[query]; ok {
continue

Check warning on line 68 in datastore/postgres/get.go

View check run for this annotation

Codecov / codecov/patch

datastore/postgres/get.go#L68

Added line #L68 was not covered by tests
}
// queue the select query
batch.Queue(query)
resCache[query] = nil
}
// send the batch

Expand All @@ -70,11 +82,18 @@ func (s *MatcherStore) Get(ctx context.Context, records []*claircore.IndexRecord
// gather all the returned vulns for each queued select statement
results := make(map[string][]*claircore.Vulnerability)
vulnSet := make(map[string]map[string]struct{})
for _, record := range records {
rows, err := res.Query()
if err != nil {
res.Close()
return nil, err
for _, rq := range rqs {
rows, ok := resCache[rq.query]
if !ok {
return nil, fmt.Errorf("unexpected vulnerability query: %s", rq.query)

Check warning on line 88 in datastore/postgres/get.go

View check run for this annotation

Codecov / codecov/patch

datastore/postgres/get.go#L88

Added line #L88 was not covered by tests
}
if rows == nil {
rows, err = res.Query()
if err != nil {
res.Close()
return nil, err

Check warning on line 94 in datastore/postgres/get.go

View check run for this annotation

Codecov / codecov/patch

datastore/postgres/get.go#L93-L94

Added lines #L93 - L94 were not covered by tests
}
resCache[rq.query] = rows
}

// unpack all returned rows into claircore.Vulnerability structs
Expand Down Expand Up @@ -121,7 +140,7 @@ func (s *MatcherStore) Get(ctx context.Context, records []*claircore.IndexRecord
return nil, fmt.Errorf("failed to scan vulnerability: %v", err)
}

rid := record.Package.ID
rid := rq.record.Package.ID
if _, ok := vulnSet[rid]; !ok {
vulnSet[rid] = make(map[string]struct{})
}
Expand Down

0 comments on commit 12e1dd0

Please sign in to comment.