github.com/quay/claircore@v1.5.28/datastore/postgres/indexdistributions.go (about) 1 package postgres 2 3 import ( 4 "context" 5 "fmt" 6 "time" 7 8 "github.com/prometheus/client_golang/prometheus" 9 "github.com/prometheus/client_golang/prometheus/promauto" 10 "github.com/quay/claircore" 11 "github.com/quay/claircore/indexer" 12 "github.com/quay/claircore/pkg/microbatch" 13 ) 14 15 var ( 16 indexDistributionsCounter = promauto.NewCounterVec( 17 prometheus.CounterOpts{ 18 Namespace: "claircore", 19 Subsystem: "indexer", 20 Name: "indexdistributions_total", 21 Help: "Total number of database queries issued in the IndexDistributions method.", 22 }, 23 []string{"query"}, 24 ) 25 26 indexDistributionsDuration = promauto.NewHistogramVec( 27 prometheus.HistogramOpts{ 28 Namespace: "claircore", 29 Subsystem: "indexer", 30 Name: "indexdistributions_duration_seconds", 31 Help: "The duration of all queries issued in the IndexDistributions method", 32 }, 33 []string{"query"}, 34 ) 35 ) 36 37 func (s *IndexerStore) IndexDistributions(ctx context.Context, dists []*claircore.Distribution, layer *claircore.Layer, scnr indexer.VersionedScanner) error { 38 const ( 39 insert = ` 40 INSERT INTO dist 41 (name, did, version, version_code_name, version_id, arch, cpe, pretty_name) 42 VALUES 43 ($1, $2, $3, $4, $5, $6, $7, $8) 44 ON CONFLICT (name, did, version, version_code_name, version_id, arch, cpe, pretty_name) DO NOTHING; 45 ` 46 47 insertWith = ` 48 WITH distributions AS ( 49 SELECT id AS dist_id 50 FROM dist 51 WHERE name = $1 52 AND did = $2 53 AND version = $3 54 AND version_code_name = $4 55 AND version_id = $5 56 AND arch = $6 57 AND cpe = $7 58 AND pretty_name = $8 59 ), 60 scanner AS ( 61 SELECT id AS scanner_id 62 FROM scanner 63 WHERE name = $9 64 AND version = $10 65 AND kind = $11 66 ), 67 layer AS ( 68 SELECT id AS layer_id 69 FROM layer 70 WHERE layer.hash = $12 71 ) 72 INSERT 73 INTO dist_scanartifact (layer_id, dist_id, scanner_id) 74 VALUES ((SELECT layer_id FROM layer), 75 (SELECT dist_id FROM distributions), 76 (SELECT scanner_id FROM scanner)) 77 ON CONFLICT DO NOTHING; 78 ` 79 ) 80 81 // obtain a transaction scoped batch 82 tx, err := s.pool.Begin(ctx) 83 if err != nil { 84 return fmt.Errorf("store:indexDistributions failed to create transaction: %v", err) 85 } 86 defer tx.Rollback(ctx) 87 88 insertDistStmt, err := tx.Prepare(ctx, "insertDistStmt", insert) 89 if err != nil { 90 return fmt.Errorf("failed to create statement: %w", err) 91 } 92 insertDistScanArtifactWithStmt, err := tx.Prepare(ctx, "insertDistScanArtifactWith", insertWith) 93 if err != nil { 94 return fmt.Errorf("failed to create statement: %w", err) 95 } 96 97 start := time.Now() 98 mBatcher := microbatch.NewInsert(tx, 500, time.Minute) 99 for _, dist := range dists { 100 err := mBatcher.Queue( 101 ctx, 102 insertDistStmt.SQL, 103 dist.Name, 104 dist.DID, 105 dist.Version, 106 dist.VersionCodeName, 107 dist.VersionID, 108 dist.Arch, 109 dist.CPE, 110 dist.PrettyName, 111 ) 112 if err != nil { 113 return fmt.Errorf("batch insert failed for dist %v: %w", dist, err) 114 } 115 } 116 err = mBatcher.Done(ctx) 117 if err != nil { 118 return fmt.Errorf("final batch insert failed for dist: %w", err) 119 } 120 indexDistributionsCounter.WithLabelValues("insert_batch").Add(1) 121 indexDistributionsDuration.WithLabelValues("insert_batch").Observe(time.Since(start).Seconds()) 122 123 // make dist scan artifacts 124 start = time.Now() 125 mBatcher = microbatch.NewInsert(tx, 500, time.Minute) 126 for _, dist := range dists { 127 err := mBatcher.Queue( 128 ctx, 129 insertDistScanArtifactWithStmt.SQL, 130 dist.Name, 131 dist.DID, 132 dist.Version, 133 dist.VersionCodeName, 134 dist.VersionID, 135 dist.Arch, 136 dist.CPE, 137 dist.PrettyName, 138 scnr.Name(), 139 scnr.Version(), 140 scnr.Kind(), 141 layer.Hash, 142 ) 143 if err != nil { 144 return fmt.Errorf("batch insert failed for dist_scanartifact %v: %w", dist, err) 145 } 146 } 147 err = mBatcher.Done(ctx) 148 if err != nil { 149 return fmt.Errorf("final batch insert failed for dist_scanartifact: %w", err) 150 } 151 indexDistributionsCounter.WithLabelValues("insertWith_batch").Add(1) 152 indexDistributionsDuration.WithLabelValues("insertWith_batch").Observe(time.Since(start).Seconds()) 153 154 err = tx.Commit(ctx) 155 if err != nil { 156 return fmt.Errorf("store:indexDistributions failed to commit tx: %w", err) 157 } 158 return nil 159 }