From 89f10e8eb2d829fd6ddda7bc2a79f366ebbe0bfa Mon Sep 17 00:00:00 2001 From: Bjoern Rabenstein Date: Tue, 9 Sep 2014 14:36:26 +0200 Subject: [PATCH] Move to using the standard library interfaces for encoding/decoding. BinaryMarshaler instead of encodable. BinaryUnmarshaler instead of decodable. Left 'codable' in place for lack of a better word. Change-Id: I8a104be7d6db916e8dbc47ff95e6ff73b845ac22 --- storage/local/index/batch.go | 24 +++++- storage/local/index/codec.go | 121 ++++++++++++++++++------------ storage/local/index/codec_test.go | 11 ++- storage/local/index/index.go | 43 +++++++---- storage/local/index/index_test.go | 4 +- storage/local/index/interface.go | 40 +++++++--- storage/local/index/leveldb.go | 39 +++++++--- storage/local/interface.go | 11 +-- storage/local/persistence.go | 28 ++----- 9 files changed, 198 insertions(+), 123 deletions(-) diff --git a/storage/local/index/batch.go b/storage/local/index/batch.go index 57d7761dc..defc1a40b 100644 --- a/storage/local/index/batch.go +++ b/storage/local/index/batch.go @@ -1,6 +1,8 @@ package index import ( + "encoding" + "github.com/syndtr/goleveldb/leveldb" ) @@ -8,12 +10,26 @@ type batch struct { batch *leveldb.Batch } -func (b *batch) Put(key, value encodable) { - b.batch.Put(key.encode(), value.encode()) +func (b *batch) Put(key, value encoding.BinaryMarshaler) error { + k, err := key.MarshalBinary() + if err != nil { + return err + } + v, err := value.MarshalBinary() + if err != nil { + return err + } + b.batch.Put(k, v) + return nil } -func (b *batch) Delete(k encodable) { - b.batch.Delete(k.encode()) +func (b *batch) Delete(key encoding.BinaryMarshaler) error { + k, err := key.MarshalBinary() + if err != nil { + return err + } + b.batch.Delete(k) + return nil } func (b *batch) Reset() { diff --git a/storage/local/index/codec.go b/storage/local/index/codec.go index b7eb1ff20..e7dd9a4cd 100644 --- a/storage/local/index/codec.go +++ b/storage/local/index/codec.go @@ -2,6 +2,7 @@ package index import ( "bytes" + "encoding" "encoding/binary" "io" "sync" @@ -12,16 +13,8 @@ import ( ) type codable interface { - encodable - decodable -} - -type encodable interface { - encode() []byte -} - -type decodable interface { - decode([]byte) + encoding.BinaryMarshaler + encoding.BinaryUnmarshaler } // TODO: yeah, this ain't ideal. A lot of locking and possibly even contention. @@ -36,27 +29,29 @@ func setTmpBufLen(l int) { } } -func encodeVarint(b *bytes.Buffer, i int) { +func encodeVarint(b *bytes.Buffer, i int) error { tmpBufMtx.Lock() defer tmpBufMtx.Unlock() bytesWritten := binary.PutVarint(tmpBuf, int64(i)) if _, err := b.Write(tmpBuf[:bytesWritten]); err != nil { - panic(err) + return err } + return nil } -func encodeString(b *bytes.Buffer, s string) { +func encodeString(b *bytes.Buffer, s string) error { encodeVarint(b, len(s)) if _, err := b.WriteString(s); err != nil { - panic(err) + return err } + return nil } -func decodeString(b *bytes.Reader) string { +func decodeString(b *bytes.Reader) (string, error) { length, err := binary.ReadVarint(b) if err != nil { - panic(err) + return "", err } tmpBufMtx.Lock() @@ -64,51 +59,59 @@ func decodeString(b *bytes.Reader) string { setTmpBufLen(int(length)) if _, err := io.ReadFull(b, tmpBuf); err != nil { - panic(err) + return "", err } - return string(tmpBuf) + return string(tmpBuf), nil } type codableMetric clientmodel.Metric -func (m codableMetric) encode() []byte { +func (m codableMetric) MarshalBinary() ([]byte, error) { buf := &bytes.Buffer{} encodeVarint(buf, len(m)) for l, v := range m { encodeString(buf, string(l)) encodeString(buf, string(v)) } - return buf.Bytes() + return buf.Bytes(), nil } -func (m codableMetric) decode(buf []byte) { +func (m codableMetric) UnmarshalBinary(buf []byte) error { r := bytes.NewReader(buf) numLabelPairs, err := binary.ReadVarint(r) if err != nil { - panic(err) + return err } for ; numLabelPairs > 0; numLabelPairs-- { - ln := decodeString(r) - lv := decodeString(r) + ln, err := decodeString(r) + if err != nil { + return err + } + lv, err := decodeString(r) + if err != nil { + return err + } m[clientmodel.LabelName(ln)] = clientmodel.LabelValue(lv) } + return nil } type codableFingerprint clientmodel.Fingerprint -func (fp codableFingerprint) encode() []byte { +func (fp codableFingerprint) MarshalBinary() ([]byte, error) { b := make([]byte, 8) binary.BigEndian.PutUint64(b, uint64(fp)) - return b + return b, nil } -func (fp *codableFingerprint) decode(buf []byte) { +func (fp *codableFingerprint) UnmarshalBinary(buf []byte) error { *fp = codableFingerprint(binary.BigEndian.Uint64(buf)) + return nil } type codableFingerprints clientmodel.Fingerprints -func (fps codableFingerprints) encode() []byte { +func (fps codableFingerprints) MarshalBinary() ([]byte, error) { buf := bytes.NewBuffer(make([]byte, 0, binary.MaxVarintLen64+len(fps)*8)) encodeVarint(buf, len(fps)) @@ -119,17 +122,17 @@ func (fps codableFingerprints) encode() []byte { for _, fp := range fps { binary.BigEndian.PutUint64(tmpBuf, uint64(fp)) if _, err := buf.Write(tmpBuf[:8]); err != nil { - panic(err) + return nil, err } } - return buf.Bytes() + return buf.Bytes(), nil } -func (fps *codableFingerprints) decode(buf []byte) { +func (fps *codableFingerprints) UnmarshalBinary(buf []byte) error { r := bytes.NewReader(buf) numFPs, err := binary.ReadVarint(r) if err != nil { - panic(err) + return err } *fps = make(codableFingerprints, numFPs) @@ -137,64 +140,84 @@ func (fps *codableFingerprints) decode(buf []byte) { for i, _ := range *fps { (*fps)[i] = clientmodel.Fingerprint(binary.BigEndian.Uint64(buf[offset+i*8:])) } + return nil } type codableLabelPair metric.LabelPair -func (lp codableLabelPair) encode() []byte { +func (lp codableLabelPair) MarshalBinary() ([]byte, error) { buf := &bytes.Buffer{} encodeString(buf, string(lp.Name)) encodeString(buf, string(lp.Value)) - return buf.Bytes() + return buf.Bytes(), nil } -func (lp *codableLabelPair) decode(buf []byte) { +func (lp *codableLabelPair) UnmarshalBinary(buf []byte) error { r := bytes.NewReader(buf) - lp.Name = clientmodel.LabelName(decodeString(r)) - lp.Value = clientmodel.LabelValue(decodeString(r)) + n, err := decodeString(r) + if err != nil { + return err + } + v, err := decodeString(r) + if err != nil { + return err + } + lp.Name = clientmodel.LabelName(n) + lp.Value = clientmodel.LabelValue(v) + return nil } type codableLabelName clientmodel.LabelName -func (l codableLabelName) encode() []byte { +func (l codableLabelName) MarshalBinary() ([]byte, error) { buf := &bytes.Buffer{} encodeString(buf, string(l)) - return buf.Bytes() + return buf.Bytes(), nil } -func (l *codableLabelName) decode(buf []byte) { +func (l *codableLabelName) UnmarshalBinary(buf []byte) error { r := bytes.NewReader(buf) - *l = codableLabelName(decodeString(r)) + n, err := decodeString(r) + if err != nil { + return err + } + *l = codableLabelName(n) + return nil } type codableLabelValues clientmodel.LabelValues -func (vs codableLabelValues) encode() []byte { +func (vs codableLabelValues) MarshalBinary() ([]byte, error) { buf := &bytes.Buffer{} encodeVarint(buf, len(vs)) for _, v := range vs { encodeString(buf, string(v)) } - return buf.Bytes() + return buf.Bytes(), nil } -func (vs *codableLabelValues) decode(buf []byte) { +func (vs *codableLabelValues) UnmarshalBinary(buf []byte) error { r := bytes.NewReader(buf) numValues, err := binary.ReadVarint(r) if err != nil { - panic(err) + return err } *vs = make(codableLabelValues, numValues) for i, _ := range *vs { - (*vs)[i] = clientmodel.LabelValue(decodeString(r)) + v, err := decodeString(r) + if err != nil { + return err + } + (*vs)[i] = clientmodel.LabelValue(v) } + return nil } type codableMembership struct{} -func (m codableMembership) encode() []byte { - return []byte{} +func (m codableMembership) MarshalBinary() ([]byte, error) { + return []byte{}, nil } -func (m codableMembership) decode(buf []byte) {} +func (m codableMembership) UnmarshalBinary(buf []byte) error { return nil } diff --git a/storage/local/index/codec_test.go b/storage/local/index/codec_test.go index d6c9c2f21..522b34558 100644 --- a/storage/local/index/codec_test.go +++ b/storage/local/index/codec_test.go @@ -103,10 +103,15 @@ func TestCodec(t *testing.T) { } for i, s := range scenarios { - encoded := s.in.encode() - s.out.decode(encoded) + encoded, err := s.in.MarshalBinary() + if err != nil { + t.Fatal(err) + } + if err := s.out.UnmarshalBinary(encoded); err != nil { + t.Fatal(err) + } if !s.equal(s.in, s.out) { - t.Fatalf("%d. Got: %v; want %v; encoded bytes are: %v", i, s.out, s.in, encoded) + t.Errorf("%d. Got: %v; want %v; encoded bytes are: %v", i, s.out, s.in, encoded) } } } diff --git a/storage/local/index/index.go b/storage/local/index/index.go index 97ba457f7..a6ed026ad 100644 --- a/storage/local/index/index.go +++ b/storage/local/index/index.go @@ -208,7 +208,7 @@ func (i *SynchronizedIndexer) IndexMetrics(b FingerprintMetricMapping) error { return i.i.IndexMetrics(b) } -// TotalIndexer is a MetricIndexer that indexes all standard facets of a metric +// DiskIndexer is a MetricIndexer that indexes all standard facets of a metric // that a user or the Prometheus subsystem would want to query against: // // -> @@ -218,7 +218,7 @@ func (i *SynchronizedIndexer) IndexMetrics(b FingerprintMetricMapping) error { // // This type supports concurrent queries, but only single writes, and it has no // locking semantics to enforce this. -type TotalIndexer struct { +type DiskIndexer struct { FingerprintToMetric *FingerprintMetricIndex LabelNameToLabelValues *LabelNameLabelValuesIndex LabelPairToFingerprints *LabelPairFingerprintIndex @@ -384,7 +384,7 @@ func extendLabelPairIndex(i *LabelPairFingerprintIndex, b FingerprintMetricMappi // IndexMetrics adds the facets of all unindexed metrics found in the given // FingerprintMetricMapping to the corresponding indices. -func (i *TotalIndexer) IndexMetrics(b FingerprintMetricMapping) error { +func (i *DiskIndexer) IndexMetrics(b FingerprintMetricMapping) error { unindexed, err := findUnindexed(i.FingerprintMembership, b) if err != nil { return err @@ -413,9 +413,8 @@ func (i *TotalIndexer) IndexMetrics(b FingerprintMetricMapping) error { return i.FingerprintMembership.IndexBatch(unindexed) } -// UnindexMetrics removes the facets of all indexed metrics found in the given -// FingerprintMetricMapping to the corresponding indices. -func (i *TotalIndexer) UnindexMetrics(b FingerprintMetricMapping) error { +// UnindexMetrics implements MetricIndexer. +func (i *DiskIndexer) UnindexMetrics(b FingerprintMetricMapping) error { indexed, err := findIndexed(i.FingerprintMembership, b) if err != nil { return err @@ -441,14 +440,19 @@ func (i *TotalIndexer) UnindexMetrics(b FingerprintMetricMapping) error { return i.FingerprintMembership.UnindexBatch(indexed) } -// GetMetricForFingerprint returns the metric associated with the provided fingerprint. -func (i *TotalIndexer) GetMetricForFingerprint(fp clientmodel.Fingerprint) (clientmodel.Metric, error) { +func (i *DiskIndexer) ArchiveMetrics(fp clientmodel.Fingerprint, first, last clientmodel.Timestamp) error { + // TODO: implement. + return nil +} + +// GetMetricForFingerprint implements MetricIndexer. +func (i *DiskIndexer) GetMetricForFingerprint(fp clientmodel.Fingerprint) (clientmodel.Metric, error) { m, _, err := i.FingerprintToMetric.Lookup(fp) return m, err } -// GetFingerprintsForLabelPair returns all fingerprints for the provided label pair. -func (i *TotalIndexer) GetFingerprintsForLabelPair(ln clientmodel.LabelName, lv clientmodel.LabelValue) (clientmodel.Fingerprints, error) { +// GetFingerprintsForLabelPair implements MetricIndexer. +func (i *DiskIndexer) GetFingerprintsForLabelPair(ln clientmodel.LabelName, lv clientmodel.LabelValue) (clientmodel.Fingerprints, error) { fps, _, err := i.LabelPairToFingerprints.Lookup(&metric.LabelPair{ Name: ln, Value: lv, @@ -456,13 +460,24 @@ func (i *TotalIndexer) GetFingerprintsForLabelPair(ln clientmodel.LabelName, lv return fps, err } -// GetLabelValuesForLabelName returns all label values associated with a given label name. -func (i *TotalIndexer) GetLabelValuesForLabelName(ln clientmodel.LabelName) (clientmodel.LabelValues, error) { +// GetLabelValuesForLabelName implements MetricIndexer. +func (i *DiskIndexer) GetLabelValuesForLabelName(ln clientmodel.LabelName) (clientmodel.LabelValues, error) { lvs, _, err := i.LabelNameToLabelValues.Lookup(ln) return lvs, err } -// HasFingerprint returns true if a metric with the given fingerprint has been indexed. -func (i *TotalIndexer) HasFingerprint(fp clientmodel.Fingerprint) (bool, error) { +// HasFingerprint implements MetricIndexer. +func (i *DiskIndexer) HasFingerprint(fp clientmodel.Fingerprint) (bool, error) { + // TODO: modify. return i.FingerprintMembership.Has(fp) } + +func (i *DiskIndexer) HasArchivedFingerprint(clientmodel.Fingerprint) (present bool, first, last clientmodel.Timestamp, err error) { + // TODO: implement. + return false, 0, 0, nil +} + +func (i *DiskIndexer) Close() error { + // TODO: implement + return nil +} diff --git a/storage/local/index/index_test.go b/storage/local/index/index_test.go index f70dbc23c..998d208e8 100644 --- a/storage/local/index/index_test.go +++ b/storage/local/index/index_test.go @@ -31,7 +31,7 @@ func newTestDB(t *testing.T) (KeyValueStore, test.Closer) { }) } -func verifyIndexedState(i int, t *testing.T, b incrementalBatch, indexedFpsToMetrics FingerprintMetricMapping, indexer *TotalIndexer) { +func verifyIndexedState(i int, t *testing.T, b incrementalBatch, indexedFpsToMetrics FingerprintMetricMapping, indexer *DiskIndexer) { for fp, m := range indexedFpsToMetrics { // Compare indexed metrics with input metrics. mOut, ok, err := indexer.FingerprintToMetric.Lookup(fp) @@ -224,7 +224,7 @@ func TestIndexing(t *testing.T) { fpMsDB, fpMsCloser := newTestDB(t) defer fpMsCloser.Close() - indexer := TotalIndexer{ + indexer := DiskIndexer{ FingerprintToMetric: NewFingerprintMetricIndex(fpToMetricDB), LabelNameToLabelValues: NewLabelNameLabelValuesIndex(lnToLvsDB), LabelPairToFingerprints: NewLabelPairFingerprintIndex(lpToFpDB), diff --git a/storage/local/index/interface.go b/storage/local/index/interface.go index 5c053547e..fd3a70332 100644 --- a/storage/local/index/interface.go +++ b/storage/local/index/interface.go @@ -1,16 +1,28 @@ package index import ( + "encoding" + clientmodel "github.com/prometheus/client_golang/model" ) -// MetricIndexer indexes facets of a clientmodel.Metric. The interface makes no -// assumptions about the concurrency safety of the underlying implementer. +// MetricIndexer indexes facets of a clientmodel.Metric. Implementers may or may +// not be concurrency-safe. type MetricIndexer interface { - // IndexMetrics adds metrics to the index. + // IndexMetrics adds metrics to the index. If the metrics was added + // before and has been archived in the meantime, it is now un-archived. IndexMetrics(FingerprintMetricMapping) error // UnindexMetrics removes metrics from the index. UnindexMetrics(FingerprintMetricMapping) error + // ArchiveMetrics marks the metric with the given fingerprint as + // 'archived', which has to be called if upon eviction of the + // corresponding time series from memory. By calling this method, the + // MetricIndexer learns about the time range of the evicted time series, + // which is used later for the decision if an evicted time series has to + // be moved back into memory. The implementer of MetricIndexer can make + // use of the archived state, e.g. by saving archived metrics in an + // on-disk index and non-archived metrics in an in-memory index. + ArchiveMetrics(fp clientmodel.Fingerprint, first, last clientmodel.Timestamp) error // GetMetricForFingerprint returns the metric associated with the provided fingerprint. GetMetricForFingerprint(clientmodel.Fingerprint) (clientmodel.Metric, error) @@ -18,16 +30,24 @@ type MetricIndexer interface { GetFingerprintsForLabelPair(l clientmodel.LabelName, v clientmodel.LabelValue) (clientmodel.Fingerprints, error) // GetLabelValuesForLabelName returns all label values associated with a given label name. GetLabelValuesForLabelName(clientmodel.LabelName) (clientmodel.LabelValues, error) - // HasFingerprint returns true if a metric with the given fingerprint has been indexed. + // HasFingerprint returns true if a metric with the given fingerprint + // has been indexed and has NOT been archived yet. HasFingerprint(clientmodel.Fingerprint) (bool, error) + // HasArchivedFingerprint returns true if a metric with the given + // fingerprint was indexed before and has been archived in the + // meantime. In that case, the time range of the archived metric is also + // returned. + HasArchivedFingerprint(clientmodel.Fingerprint) (present bool, first, last clientmodel.Timestamp, err error) + + Close() error } // KeyValueStore persists key/value pairs. type KeyValueStore interface { - Put(key, value encodable) error - Get(k encodable, v decodable) (bool, error) - Has(k encodable) (has bool, err error) - Delete(k encodable) error + Put(key, value encoding.BinaryMarshaler) error + Get(k encoding.BinaryMarshaler, v encoding.BinaryUnmarshaler) (bool, error) + Has(k encoding.BinaryMarshaler) (has bool, err error) + Delete(k encoding.BinaryMarshaler) error NewBatch() Batch Commit(b Batch) error @@ -37,7 +57,7 @@ type KeyValueStore interface { // Batch allows KeyValueStore mutations to be pooled and committed together. type Batch interface { - Put(key, value encodable) - Delete(key encodable) + Put(key, value encoding.BinaryMarshaler) error + Delete(key encoding.BinaryMarshaler) error Reset() } diff --git a/storage/local/index/leveldb.go b/storage/local/index/leveldb.go index d29cab134..4f98815f6 100644 --- a/storage/local/index/leveldb.go +++ b/storage/local/index/leveldb.go @@ -1,6 +1,8 @@ package index import ( + "encoding" + "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/cache" "github.com/syndtr/goleveldb/leveldb/filter" @@ -48,31 +50,46 @@ func (l *LevelDB) Close() error { return l.storage.Close() } -func (l *LevelDB) Get(k encodable, v decodable) (bool, error) { - raw, err := l.storage.Get(k.encode(), l.readOpts) +func (l *LevelDB) Get(key encoding.BinaryMarshaler, value encoding.BinaryUnmarshaler) (bool, error) { + k, err := key.MarshalBinary() + if err != nil { + return false, nil + } + raw, err := l.storage.Get(k, l.readOpts) if err == leveldb.ErrNotFound { return false, nil } if err != nil { return false, err } - if v == nil { + if value == nil { return true, nil } - v.decode(raw) - return true, err + return true, value.UnmarshalBinary(raw) } -func (l *LevelDB) Has(k encodable) (has bool, err error) { - return l.Get(k, nil) +func (l *LevelDB) Has(key encoding.BinaryMarshaler) (has bool, err error) { + return l.Get(key, nil) } -func (l *LevelDB) Delete(k encodable) error { - return l.storage.Delete(k.encode(), l.writeOpts) +func (l *LevelDB) Delete(key encoding.BinaryMarshaler) error { + k, err := key.MarshalBinary() + if err != nil { + return err + } + return l.storage.Delete(k, l.writeOpts) } -func (l *LevelDB) Put(key, value encodable) error { - return l.storage.Put(key.encode(), value.encode(), l.writeOpts) +func (l *LevelDB) Put(key, value encoding.BinaryMarshaler) error { + k, err := key.MarshalBinary() + if err != nil { + return err + } + v, err := value.MarshalBinary() + if err != nil { + return err + } + return l.storage.Put(k, v, l.writeOpts) } func (l *LevelDB) Commit(b Batch) error { diff --git a/storage/local/interface.go b/storage/local/interface.go index 410edcc89..bf6964f2e 100644 --- a/storage/local/interface.go +++ b/storage/local/interface.go @@ -2,8 +2,6 @@ package storage_ng import ( clientmodel "github.com/prometheus/client_golang/model" - - "github.com/prometheus/prometheus/storage/local/index" "github.com/prometheus/prometheus/storage/metric" ) @@ -64,9 +62,7 @@ type Persistence interface { LoadHeads(map[clientmodel.Fingerprint]*memorySeries) error // Close releases any held resources. - Close() - - index.MetricIndexer + Close() error } // A Preloader preloads series data necessary for a query into memory and pins @@ -86,8 +82,3 @@ type Preloader interface { // Close unpins any previously requested series data from memory. Close() } - -type Closer interface { - // Close cleans up any used resources. - Close() -} diff --git a/storage/local/persistence.go b/storage/local/persistence.go index dddccf206..948a83b5c 100644 --- a/storage/local/persistence.go +++ b/storage/local/persistence.go @@ -41,9 +41,9 @@ const ( var ( fingerprintToMetricCacheSize = flag.Int("storage.fingerprintToMetricCacheSizeBytes", 25*1024*1024, "The size in bytes for the fingerprint to metric index cache.") - labelNameToLabelValuesCacheSize = flag.Int("storage.labelNameToLabelValuesCacheSizeBytes", 25*1024*1024, "The size in bytes for the label name to label values index.") - labelPairToFingerprintsCacheSize = flag.Int("storage.labelPairToFingerprintsCacheSizeBytes", 25*1024*1024, "The size in bytes for the label pair to fingerprints index.") - fingerprintMembershipCacheSize = flag.Int("storage.fingerprintMembershipCacheSizeBytes", 5*1024*1024, "The size in bytes for the metric membership index.") + labelNameToLabelValuesCacheSize = flag.Int("storage.labelNameToLabelValuesCacheSizeBytes", 25*1024*1024, "The size in bytes for the label name to label values index cache.") + labelPairToFingerprintsCacheSize = flag.Int("storage.labelPairToFingerprintsCacheSizeBytes", 25*1024*1024, "The size in bytes for the label pair to fingerprints index cache.") + fingerprintMembershipCacheSize = flag.Int("storage.fingerprintMembershipCacheSizeBytes", 5*1024*1024, "The size in bytes for the metric membership index cache.") ) type diskPersistence struct { @@ -94,7 +94,7 @@ func NewDiskPersistence(basePath string, chunkLen int) (Persistence, error) { basePath: basePath, chunkLen: chunkLen, buf: make([]byte, binary.MaxVarintLen64), // Also sufficient for uint64. - MetricIndexer: &index.TotalIndexer{ + MetricIndexer: &index.DiskIndexer{ FingerprintToMetric: index.NewFingerprintMetricIndex(fingerprintToMetricDB), LabelNameToLabelValues: index.NewLabelNameLabelValuesIndex(labelNameToLabelValuesDB), LabelPairToFingerprints: index.NewLabelPairFingerprintIndex(labelPairToFingerprintsDB), @@ -395,25 +395,13 @@ func (p *diskPersistence) LoadHeads(fpToSeries map[clientmodel.Fingerprint]*memo return nil } -func (d *diskPersistence) Close() { +func (d *diskPersistence) Close() error { + var lastError error for _, db := range d.indexDBs { if err := db.Close(); err != nil { glog.Error("Error closing index DB: ", err) + lastError = err } } -} - -// Get all of the label values that are associated with a given label name. -func (d *diskPersistence) GetFingerprintsForLabelPair(l clientmodel.LabelName, v clientmodel.LabelValue) (clientmodel.Fingerprints, error) { - return nil, nil -} - -// Get all label values that are associated with a given label name. -func (d *diskPersistence) GetLabelValuesForLabelName(clientmodel.LabelName) (clientmodel.LabelValues, error) { - return nil, nil -} - -// Get the metric associated with the provided fingerprint. -func (d *diskPersistence) GetMetricForFingerprint(clientmodel.Fingerprint) (clientmodel.Metric, error) { - return nil, nil + return lastError }