blob: b5386eb0c4095c99f900debb6df615a35580f19e [file] [log] [blame]
package diffstore
import (
"github.com/boltdb/bolt"
"go.skia.org/infra/go/boltutil"
"go.skia.org/infra/go/util"
"go.skia.org/infra/golden/go/diff"
)
const (
// METRICSDB_NAME is the name of the boltdb caching diff metrics.
METRICSDB_NAME = "diffstore_metrics"
// METRICS_DIGEST_INDEX is the index name to keep track of digests in the metrics db.
METRICS_DIGEST_INDEX = "metric_digest_index"
)
// metricsStore stores diff metrics on disk.
type metricsStore struct {
// store stores the diff metrics in a boltdb database.
store *boltutil.IndexedBucket
}
// metricsRecIndices are the indices supported by the metricsRec type.
var metricsRecIndices = []string{METRICS_DIGEST_INDEX}
// metricsRec implements the boltutil.Record interface.
type metricsRec struct {
ID string `json:"id"`
*diff.DiffMetrics
}
// Key see the boltutil.Record interface.
func (m *metricsRec) Key() string {
return m.ID
}
// IndexValues see the boltutil.Record interface.
func (m *metricsRec) IndexValues() map[string][]string {
d1, d2 := splitDigests(m.ID)
return map[string][]string{METRICS_DIGEST_INDEX: {d1, d2}}
}
// newMetricsStore returns a new instance of metricsStore.
func newMetricStore(baseDir string) (*metricsStore, error) {
db, err := openBoltDB(baseDir, METRICSDB_NAME+".db")
if err != nil {
return nil, err
}
config := &boltutil.Config{
DB: db,
Name: METRICSDB_NAME,
Indices: metricsRecIndices,
Codec: util.JSONCodec(&metricsRec{}),
}
store, err := boltutil.NewIndexedBucket(config)
if err != nil {
return nil, err
}
return &metricsStore{
store: store,
}, nil
}
// loadDiffMetric loads a diffMetric from disk.
func (m *metricsStore) loadDiffMetric(id string) (*diff.DiffMetrics, error) {
recs, err := m.store.Read([]string{id})
if err != nil {
return nil, err
}
if recs[0] == nil {
return nil, nil
}
return recs[0].(*metricsRec).DiffMetrics, nil
}
// saveDiffMetric stores a diffmetric to disk.
func (m *metricsStore) saveDiffMetric(id string, dr *diff.DiffMetrics) error {
rec := &metricsRec{ID: id, DiffMetrics: dr}
return m.store.Insert([]boltutil.Record{rec})
}
// purgeMetrics removes all metrics that based on a specific digest.
func (m *metricsStore) purgeMetrics(digests []string) error {
updateFn := func(tx *bolt.Tx) error {
metricIDMap, err := m.store.ReadIndexTx(tx, METRICS_DIGEST_INDEX, digests)
if err != nil {
return err
}
metricIds := util.StringSet{}
for _, ids := range metricIDMap {
metricIds.AddLists(ids)
}
return m.store.DeleteTx(tx, metricIds.Keys())
}
return m.store.DB.Update(updateFn)
}