diff --git a/main.go b/main.go index 0c215a6239..022b886ab2 100644 --- a/main.go +++ b/main.go @@ -28,6 +28,7 @@ import ( "github.com/prometheus/prometheus/retrieval" "github.com/prometheus/prometheus/rules" "github.com/prometheus/prometheus/storage/metric" + "github.com/prometheus/prometheus/web" "github.com/prometheus/prometheus/web/api" ) @@ -68,14 +69,13 @@ var ( ) type prometheus struct { - headCompactionTimer *time.Ticker - bodyCompactionTimer *time.Ticker - tailCompactionTimer *time.Ticker - deletionTimer *time.Ticker - reportDatabasesTimer *time.Ticker + headCompactionTimer *time.Ticker + bodyCompactionTimer *time.Ticker + tailCompactionTimer *time.Ticker + deletionTimer *time.Ticker + curationMutex sync.Mutex curationState chan metric.CurationState - databaseStates chan []string stopBackgroundOperations chan bool unwrittenSamples chan *extraction.Result @@ -141,10 +141,6 @@ func (p *prometheus) close() { p.deletionTimer.Stop() } - if p.reportDatabasesTimer != nil { - p.reportDatabasesTimer.Stop() - } - if len(p.stopBackgroundOperations) == 0 { p.stopBackgroundOperations <- true } @@ -157,26 +153,6 @@ func (p *prometheus) close() { close(p.notifications) close(p.stopBackgroundOperations) close(p.curationState) - close(p.databaseStates) -} - -func (p *prometheus) reportDatabaseState() { - for _ = range p.reportDatabasesTimer.C { - // BUG(matt): Per Julius, ... - // These channel magic tricks confuse me and seem a bit awkward just to - // pass a status around. Now that we have Go 1.1, would it be maybe be - // nicer to pass ts.DiskStorage.States as a method value - // (http://tip.golang.org/ref/spec#Method_values) to the web layer - // instead of doing this? - select { - case <-p.databaseStates: - // Reset the future database state if nobody consumes it. - case p.databaseStates <- p.storage.DiskStorage.States(): - // Set the database state so someone can consume it if they want. - default: - // Don't block. - } - } } func main() { @@ -206,7 +182,6 @@ func main() { unwrittenSamples := make(chan *extraction.Result, *samplesQueueCapacity) curationState := make(chan metric.CurationState, 1) - databaseStates := make(chan []string, 1) // Coprime numbers, fool! headCompactionTimer := time.NewTicker(*headCompactInterval) bodyCompactionTimer := time.NewTicker(*bodyCompactInterval) @@ -254,7 +229,7 @@ func main() { } databasesHandler := &web.DatabasesHandler{ - Incoming: databaseStates, + Provider: ts.DiskStorage, } metricsService := &api.MetricsService{ @@ -277,10 +252,7 @@ func main() { deletionTimer: deletionTimer, - reportDatabasesTimer: time.NewTicker(15 * time.Minute), - - curationState: curationState, - databaseStates: databaseStates, + curationState: curationState, unwrittenSamples: unwrittenSamples, @@ -297,7 +269,6 @@ func main() { <-storageStarted go prometheus.interruptHandler() - go prometheus.reportDatabaseState() go func() { for _ = range prometheus.headCompactionTimer.C { diff --git a/storage/metric/index.go b/storage/metric/index.go index 6bbca3b9b0..9ed8b84128 100644 --- a/storage/metric/index.go +++ b/storage/metric/index.go @@ -14,6 +14,7 @@ package metric import ( + "io" "sort" "code.google.com/p/goprotobuf/proto" @@ -30,14 +31,16 @@ import ( type FingerprintMetricMapping map[clientmodel.Fingerprint]clientmodel.Metric type FingerprintMetricIndex interface { + io.Closer + raw.Pruner + IndexBatch(FingerprintMetricMapping) error Lookup(*clientmodel.Fingerprint) (m clientmodel.Metric, ok bool, err error) - Close() error - State() string + State() *raw.DatabaseState Size() (s uint64, present bool, err error) } -type leveldbFingerprintMetricIndex struct { +type LeveldbFingerprintMetricIndex struct { p *leveldb.LevelDBPersistence } @@ -45,22 +48,22 @@ type LevelDBFingerprintMetricIndexOptions struct { leveldb.LevelDBOptions } -func (i *leveldbFingerprintMetricIndex) Close() error { +func (i *LeveldbFingerprintMetricIndex) Close() error { i.p.Close() return nil } -func (i *leveldbFingerprintMetricIndex) State() string { +func (i *LeveldbFingerprintMetricIndex) State() *raw.DatabaseState { return i.p.State() } -func (i *leveldbFingerprintMetricIndex) Size() (uint64, bool, error) { +func (i *LeveldbFingerprintMetricIndex) Size() (uint64, bool, error) { s, err := i.p.ApproximateSize() return s, true, err } -func (i *leveldbFingerprintMetricIndex) IndexBatch(mapping FingerprintMetricMapping) error { +func (i *LeveldbFingerprintMetricIndex) IndexBatch(mapping FingerprintMetricMapping) error { b := leveldb.NewBatch() defer b.Close() @@ -76,7 +79,7 @@ func (i *leveldbFingerprintMetricIndex) IndexBatch(mapping FingerprintMetricMapp return i.p.Commit(b) } -func (i *leveldbFingerprintMetricIndex) Lookup(f *clientmodel.Fingerprint) (m clientmodel.Metric, ok bool, err error) { +func (i *LeveldbFingerprintMetricIndex) Lookup(f *clientmodel.Fingerprint) (m clientmodel.Metric, ok bool, err error) { k := new(dto.Fingerprint) dumpFingerprint(k, f) v := new(dto.Metric) @@ -95,13 +98,19 @@ func (i *leveldbFingerprintMetricIndex) Lookup(f *clientmodel.Fingerprint) (m cl return m, true, nil } +func (i *LeveldbFingerprintMetricIndex) Prune() (bool, error) { + i.p.Prune() + + return false, nil +} + func NewLevelDBFingerprintMetricIndex(o *LevelDBFingerprintMetricIndexOptions) (FingerprintMetricIndex, error) { s, err := leveldb.NewLevelDBPersistence(&o.LevelDBOptions) if err != nil { return nil, err } - return &leveldbFingerprintMetricIndex{ + return &LeveldbFingerprintMetricIndex{ p: s, }, nil } @@ -109,19 +118,21 @@ func NewLevelDBFingerprintMetricIndex(o *LevelDBFingerprintMetricIndexOptions) ( type LabelNameFingerprintMapping map[clientmodel.LabelName]clientmodel.Fingerprints type LabelNameFingerprintIndex interface { + io.Closer + raw.Pruner + IndexBatch(LabelNameFingerprintMapping) error Lookup(clientmodel.LabelName) (fps clientmodel.Fingerprints, ok bool, err error) Has(clientmodel.LabelName) (ok bool, err error) - Close() error - State() string + State() *raw.DatabaseState Size() (s uint64, present bool, err error) } -type leveldbLabelNameFingerprintIndex struct { +type LeveldbLabelNameFingerprintIndex struct { p *leveldb.LevelDBPersistence } -func (i *leveldbLabelNameFingerprintIndex) IndexBatch(b LabelNameFingerprintMapping) error { +func (i *LeveldbLabelNameFingerprintIndex) IndexBatch(b LabelNameFingerprintMapping) error { batch := leveldb.NewBatch() defer batch.Close() @@ -144,7 +155,7 @@ func (i *leveldbLabelNameFingerprintIndex) IndexBatch(b LabelNameFingerprintMapp return i.p.Commit(batch) } -func (i *leveldbLabelNameFingerprintIndex) Lookup(l clientmodel.LabelName) (fps clientmodel.Fingerprints, ok bool, err error) { +func (i *LeveldbLabelNameFingerprintIndex) Lookup(l clientmodel.LabelName) (fps clientmodel.Fingerprints, ok bool, err error) { k := new(dto.LabelName) dumpLabelName(k, l) v := new(dto.FingerprintCollection) @@ -165,24 +176,30 @@ func (i *leveldbLabelNameFingerprintIndex) Lookup(l clientmodel.LabelName) (fps return fps, true, nil } -func (i *leveldbLabelNameFingerprintIndex) Has(l clientmodel.LabelName) (ok bool, err error) { +func (i *LeveldbLabelNameFingerprintIndex) Has(l clientmodel.LabelName) (ok bool, err error) { return i.p.Has(&dto.LabelName{ Name: proto.String(string(l)), }) } -func (i *leveldbLabelNameFingerprintIndex) Close() error { +func (i *LeveldbLabelNameFingerprintIndex) Prune() (bool, error) { + i.p.Prune() + + return false, nil +} + +func (i *LeveldbLabelNameFingerprintIndex) Close() error { i.p.Close() return nil } -func (i *leveldbLabelNameFingerprintIndex) Size() (uint64, bool, error) { +func (i *LeveldbLabelNameFingerprintIndex) Size() (uint64, bool, error) { s, err := i.p.ApproximateSize() return s, true, err } -func (i *leveldbLabelNameFingerprintIndex) State() string { +func (i *LeveldbLabelNameFingerprintIndex) State() *raw.DatabaseState { return i.p.State() } @@ -196,7 +213,7 @@ func NewLevelLabelNameFingerprintIndex(o *LevelDBLabelNameFingerprintIndexOption return nil, err } - return &leveldbLabelNameFingerprintIndex{ + return &LeveldbLabelNameFingerprintIndex{ p: s, }, nil } @@ -204,17 +221,18 @@ func NewLevelLabelNameFingerprintIndex(o *LevelDBLabelNameFingerprintIndexOption type LabelSetFingerprintMapping map[LabelPair]clientmodel.Fingerprints type LabelSetFingerprintIndex interface { + io.Closer raw.ForEacher + raw.Pruner IndexBatch(LabelSetFingerprintMapping) error Lookup(*LabelPair) (m clientmodel.Fingerprints, ok bool, err error) Has(*LabelPair) (ok bool, err error) - Close() error - State() string + State() *raw.DatabaseState Size() (s uint64, present bool, err error) } -type leveldbLabelSetFingerprintIndex struct { +type LeveldbLabelSetFingerprintIndex struct { p *leveldb.LevelDBPersistence } @@ -222,7 +240,7 @@ type LevelDBLabelSetFingerprintIndexOptions struct { leveldb.LevelDBOptions } -func (i *leveldbLabelSetFingerprintIndex) IndexBatch(m LabelSetFingerprintMapping) error { +func (i *LeveldbLabelSetFingerprintIndex) IndexBatch(m LabelSetFingerprintMapping) error { batch := leveldb.NewBatch() defer batch.Close() @@ -246,7 +264,7 @@ func (i *leveldbLabelSetFingerprintIndex) IndexBatch(m LabelSetFingerprintMappin return i.p.Commit(batch) } -func (i *leveldbLabelSetFingerprintIndex) Lookup(p *LabelPair) (m clientmodel.Fingerprints, ok bool, err error) { +func (i *LeveldbLabelSetFingerprintIndex) Lookup(p *LabelPair) (m clientmodel.Fingerprints, ok bool, err error) { k := &dto.LabelPair{ Name: proto.String(string(p.Name)), Value: proto.String(string(p.Value)), @@ -271,7 +289,7 @@ func (i *leveldbLabelSetFingerprintIndex) Lookup(p *LabelPair) (m clientmodel.Fi return m, true, nil } -func (i *leveldbLabelSetFingerprintIndex) Has(p *LabelPair) (ok bool, err error) { +func (i *LeveldbLabelSetFingerprintIndex) Has(p *LabelPair) (ok bool, err error) { k := &dto.LabelPair{ Name: proto.String(string(p.Name)), Value: proto.String(string(p.Value)), @@ -280,21 +298,27 @@ func (i *leveldbLabelSetFingerprintIndex) Has(p *LabelPair) (ok bool, err error) return i.p.Has(k) } -func (i *leveldbLabelSetFingerprintIndex) ForEach(d storage.RecordDecoder, f storage.RecordFilter, o storage.RecordOperator) (bool, error) { +func (i *LeveldbLabelSetFingerprintIndex) ForEach(d storage.RecordDecoder, f storage.RecordFilter, o storage.RecordOperator) (bool, error) { return i.p.ForEach(d, f, o) } -func (i *leveldbLabelSetFingerprintIndex) Close() error { +func (i *LeveldbLabelSetFingerprintIndex) Prune() (bool, error) { + i.p.Prune() + return false, nil +} + +func (i *LeveldbLabelSetFingerprintIndex) Close() error { i.p.Close() + return nil } -func (i *leveldbLabelSetFingerprintIndex) Size() (uint64, bool, error) { +func (i *LeveldbLabelSetFingerprintIndex) Size() (uint64, bool, error) { s, err := i.p.ApproximateSize() return s, true, err } -func (i *leveldbLabelSetFingerprintIndex) State() string { +func (i *LeveldbLabelSetFingerprintIndex) State() *raw.DatabaseState { return i.p.State() } @@ -304,26 +328,28 @@ func NewLevelDBLabelSetFingerprintIndex(o *LevelDBLabelSetFingerprintIndexOption return nil, err } - return &leveldbLabelSetFingerprintIndex{ + return &LeveldbLabelSetFingerprintIndex{ p: s, }, nil } type MetricMembershipIndex interface { + io.Closer + raw.Pruner + IndexBatch([]clientmodel.Metric) error Has(clientmodel.Metric) (ok bool, err error) - Close() error - State() string + State() *raw.DatabaseState Size() (s uint64, present bool, err error) } -type leveldbMetricMembershipIndex struct { +type LeveldbMetricMembershipIndex struct { p *leveldb.LevelDBPersistence } var existenceIdentity = new(dto.MembershipIndexValue) -func (i *leveldbMetricMembershipIndex) IndexBatch(ms []clientmodel.Metric) error { +func (i *LeveldbMetricMembershipIndex) IndexBatch(ms []clientmodel.Metric) error { batch := leveldb.NewBatch() defer batch.Close() @@ -336,28 +362,34 @@ func (i *leveldbMetricMembershipIndex) IndexBatch(ms []clientmodel.Metric) error return i.p.Commit(batch) } -func (i *leveldbMetricMembershipIndex) Has(m clientmodel.Metric) (ok bool, err error) { +func (i *LeveldbMetricMembershipIndex) Has(m clientmodel.Metric) (ok bool, err error) { k := new(dto.Metric) dumpMetric(k, m) return i.p.Has(k) } -func (i *leveldbMetricMembershipIndex) Close() error { +func (i *LeveldbMetricMembershipIndex) Close() error { i.p.Close() return nil } -func (i *leveldbMetricMembershipIndex) Size() (uint64, bool, error) { +func (i *LeveldbMetricMembershipIndex) Size() (uint64, bool, error) { s, err := i.p.ApproximateSize() return s, true, err } -func (i *leveldbMetricMembershipIndex) State() string { +func (i *LeveldbMetricMembershipIndex) State() *raw.DatabaseState { return i.p.State() } +func (i *LeveldbMetricMembershipIndex) Prune() (bool, error) { + i.p.Prune() + + return false, nil +} + type LevelDBMetricMembershipIndexOptions struct { leveldb.LevelDBOptions } @@ -368,7 +400,7 @@ func NewLevelDBMetricMembershipIndex(o *LevelDBMetricMembershipIndexOptions) (Me return nil, err } - return &leveldbMetricMembershipIndex{ + return &LeveldbMetricMembershipIndex{ p: s, }, nil } diff --git a/storage/metric/leveldb.go b/storage/metric/leveldb.go index 4fc0dba145..6b251ba3bd 100644 --- a/storage/metric/leveldb.go +++ b/storage/metric/leveldb.go @@ -28,6 +28,7 @@ import ( dto "github.com/prometheus/prometheus/model/generated" "github.com/prometheus/prometheus/storage" + "github.com/prometheus/prometheus/storage/raw" "github.com/prometheus/prometheus/storage/raw/leveldb" "github.com/prometheus/prometheus/utility" ) @@ -88,7 +89,7 @@ func (l *LevelDBMetricPersistence) Close() { closer.Close() case errorCloser: if err := closer.Close(); err != nil { - log.Println("anomaly closing", err) + log.Println("anomaly closing:", err) } } } @@ -767,14 +768,14 @@ func (l *LevelDBMetricPersistence) GetAllValuesForLabel(labelName clientmodel.La // // Beware that it would probably be imprudent to run this on a live user-facing // server due to latency implications. -func (l *LevelDBMetricPersistence) CompactKeyspaces() { - l.CurationRemarks.CompactKeyspace() - // l.fingerprintToMetrics.CompactKeyspace() - // l.labelNameToFingerprints.CompactKeyspace() - // l.labelSetToFingerprints.CompactKeyspace() - // l.MetricHighWatermarks.CompactKeyspace() - // l.metricMembershipIndex.CompactKeyspace() - l.MetricSamples.CompactKeyspace() +func (l *LevelDBMetricPersistence) Prune() { + l.CurationRemarks.Prune() + l.fingerprintToMetrics.Prune() + l.labelNameToFingerprints.Prune() + l.labelSetToFingerprints.Prune() + l.MetricHighWatermarks.Prune() + l.metricMembershipIndex.Prune() + l.MetricSamples.Prune() } func (l *LevelDBMetricPersistence) ApproximateSizes() (total uint64, err error) { @@ -818,8 +819,8 @@ func (l *LevelDBMetricPersistence) ApproximateSizes() (total uint64, err error) return total, nil } -func (l *LevelDBMetricPersistence) States() []string { - return []string{ +func (l *LevelDBMetricPersistence) States() raw.DatabaseStates { + return raw.DatabaseStates{ l.CurationRemarks.State(), l.fingerprintToMetrics.State(), l.labelNameToFingerprints.State(), diff --git a/storage/metric/watermark.go b/storage/metric/watermark.go index d198064096..e6b0ab3e38 100644 --- a/storage/metric/watermark.go +++ b/storage/metric/watermark.go @@ -15,6 +15,7 @@ package metric import ( "container/list" + "io" "sync" "time" @@ -170,20 +171,21 @@ func (lru *WatermarkCache) checkCapacity() { type FingerprintHighWatermarkMapping map[clientmodel.Fingerprint]time.Time type HighWatermarker interface { + io.Closer raw.ForEacher + raw.Pruner UpdateBatch(FingerprintHighWatermarkMapping) error Get(*clientmodel.Fingerprint) (t time.Time, ok bool, err error) - Close() error - State() string + State() *raw.DatabaseState Size() (uint64, bool, error) } -type leveldbHighWatermarker struct { +type LeveldbHighWatermarker struct { p *leveldb.LevelDBPersistence } -func (w *leveldbHighWatermarker) Get(f *clientmodel.Fingerprint) (t time.Time, ok bool, err error) { +func (w *LeveldbHighWatermarker) Get(f *clientmodel.Fingerprint) (t time.Time, ok bool, err error) { k := new(dto.Fingerprint) dumpFingerprint(k, f) v := new(dto.MetricHighWatermark) @@ -198,7 +200,7 @@ func (w *leveldbHighWatermarker) Get(f *clientmodel.Fingerprint) (t time.Time, o return t, true, nil } -func (w *leveldbHighWatermarker) UpdateBatch(m FingerprintHighWatermarkMapping) error { +func (w *LeveldbHighWatermarker) UpdateBatch(m FingerprintHighWatermarkMapping) error { batch := leveldb.NewBatch() defer batch.Close() @@ -217,7 +219,7 @@ func (w *leveldbHighWatermarker) UpdateBatch(m FingerprintHighWatermarkMapping) continue } - // BUG(matt): Repace this with watermark management. + // BUG(matt): Replace this with watermark management. if t.After(existing) { v.Timestamp = proto.Int64(t.Unix()) batch.Put(k, v) @@ -227,21 +229,27 @@ func (w *leveldbHighWatermarker) UpdateBatch(m FingerprintHighWatermarkMapping) return w.p.Commit(batch) } -func (i *leveldbHighWatermarker) ForEach(d storage.RecordDecoder, f storage.RecordFilter, o storage.RecordOperator) (bool, error) { +func (i *LeveldbHighWatermarker) ForEach(d storage.RecordDecoder, f storage.RecordFilter, o storage.RecordOperator) (bool, error) { return i.p.ForEach(d, f, o) } -func (i *leveldbHighWatermarker) Close() error { +func (i *LeveldbHighWatermarker) Prune() (bool, error) { + i.p.Prune() + + return false, nil +} + +func (i *LeveldbHighWatermarker) Close() error { i.p.Close() return nil } -func (i *leveldbHighWatermarker) State() string { +func (i *LeveldbHighWatermarker) State() *raw.DatabaseState { return i.p.State() } -func (i *leveldbHighWatermarker) Size() (uint64, bool, error) { +func (i *LeveldbHighWatermarker) Size() (uint64, bool, error) { s, err := i.p.ApproximateSize() return s, true, err } @@ -256,7 +264,7 @@ func NewLevelDBHighWatermarker(o *LevelDBHighWatermarkerOptions) (HighWatermarke return nil, err } - return &leveldbHighWatermarker{ + return &LeveldbHighWatermarker{ p: s, }, nil } diff --git a/storage/raw/index/leveldb/leveldb.go b/storage/raw/index/leveldb/leveldb.go index b8c768f667..16a8edd224 100644 --- a/storage/raw/index/leveldb/leveldb.go +++ b/storage/raw/index/leveldb/leveldb.go @@ -67,14 +67,14 @@ func (l *LevelDBMembershipIndex) Commit(batch raw.Batch) error { // // Beware that it would probably be imprudent to run this on a live user-facing // server due to latency implications. -func (l *LevelDBMembershipIndex) CompactKeyspace() { - l.persistence.CompactKeyspace() +func (l *LevelDBMembershipIndex) Prune() { + l.persistence.Prune() } func (l *LevelDBMembershipIndex) ApproximateSize() (uint64, error) { return l.persistence.ApproximateSize() } -func (l *LevelDBMembershipIndex) State() string { +func (l *LevelDBMembershipIndex) State() *raw.DatabaseState { return l.persistence.State() } diff --git a/storage/raw/interface.go b/storage/raw/interface.go index be4cf695b3..25f226803d 100644 --- a/storage/raw/interface.go +++ b/storage/raw/interface.go @@ -64,3 +64,7 @@ type Batch interface { // Drop follows the same protocol as Persistence.Drop. Drop(key proto.Message) } + +type Pruner interface { + Prune() (noop bool, err error) +} diff --git a/storage/raw/leveldb/leveldb.go b/storage/raw/leveldb/leveldb.go index d5678041d8..22f23f0970 100644 --- a/storage/raw/leveldb/leveldb.go +++ b/storage/raw/leveldb/leveldb.go @@ -163,6 +163,13 @@ func (i levigoIterator) GetError() (err error) { return i.iterator.GetError() } +type Compression uint + +const ( + Snappy Compression = iota + Uncompressed +) + type LevelDBOptions struct { Path string Name string @@ -174,15 +181,16 @@ type LevelDBOptions struct { FlushOnMutate bool UseParanoidChecks bool - NotUseSnappy bool + Compression Compression } func NewLevelDBPersistence(o *LevelDBOptions) (*LevelDBPersistence, error) { options := levigo.NewOptions() options.SetCreateIfMissing(true) options.SetParanoidChecks(o.UseParanoidChecks) + compression := levigo.SnappyCompression - if !o.NotUseSnappy { + if o.Compression == Uncompressed { compression = levigo.NoCompression } options.SetCompression(compression) @@ -313,7 +321,7 @@ func (l *LevelDBPersistence) Commit(b raw.Batch) (err error) { // // Beware that it would probably be imprudent to run this on a live user-facing // server due to latency implications. -func (l *LevelDBPersistence) CompactKeyspace() { +func (l *LevelDBPersistence) Prune() { // Magic values per https://code.google.com/p/leveldb/source/browse/include/leveldb/db.h#131. keyspace := levigo.Range{ diff --git a/storage/raw/leveldb/state.go b/storage/raw/leveldb/state.go index 0af99f481a..3de6dc457b 100644 --- a/storage/raw/leveldb/state.go +++ b/storage/raw/leveldb/state.go @@ -14,9 +14,7 @@ package leveldb import ( - "bytes" - "fmt" - + "github.com/prometheus/prometheus/storage/raw" "github.com/prometheus/prometheus/utility" ) @@ -25,50 +23,22 @@ const ( sstablesKey = "leveldb.sstables" ) -// DatabaseState models a bundle of metadata about a LevelDB database used in -// template format string interpolation. -type DatabaseState struct { - Name string - Purpose string - Path string - LowLevelStatus string - SSTablesStatus string - ApproximateSize utility.ByteSize - Error error -} - -func (s DatabaseState) String() string { - b := new(bytes.Buffer) - - fmt.Fprintln(b, "Name:", s.Name) - fmt.Fprintln(b, "Path:", s.Path) - fmt.Fprintln(b, "Purpose:", s.Purpose) - fmt.Fprintln(b, "Low Level Diagnostics:", s.LowLevelStatus) - fmt.Fprintln(b, "SSTable Statistics:", s.SSTablesStatus) - fmt.Fprintln(b, "Approximate Size:", s.ApproximateSize) - fmt.Fprintln(b, "Error:", s.Error) - - return b.String() -} - -func (l *LevelDBPersistence) LowLevelState() DatabaseState { - databaseState := DatabaseState{ - Path: l.path, - Name: l.name, - Purpose: l.purpose, - LowLevelStatus: l.storage.PropertyValue(statsKey), - SSTablesStatus: l.storage.PropertyValue(sstablesKey), +func (l *LevelDBPersistence) State() *raw.DatabaseState { + databaseState := &raw.DatabaseState{ + Location: l.path, + Name: l.name, + Purpose: l.purpose, + Supplemental: map[string]string{}, } if size, err := l.ApproximateSize(); err != nil { - databaseState.Error = err + databaseState.Supplemental["Errors"] = err.Error() } else { - databaseState.ApproximateSize = utility.ByteSize(size) + databaseState.Size = utility.ByteSize(size) } + databaseState.Supplemental["Low Level"] = l.storage.PropertyValue(statsKey) + databaseState.Supplemental["SSTable"] = l.storage.PropertyValue(sstablesKey) + return databaseState } - -func (l *LevelDBPersistence) State() string { - return l.LowLevelState().String() -} diff --git a/storage/raw/state.go b/storage/raw/state.go new file mode 100644 index 0000000000..b5cd8698cb --- /dev/null +++ b/storage/raw/state.go @@ -0,0 +1,53 @@ +// Copyright 2013 Prometheus Team +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package raw + +import ( + "github.com/prometheus/prometheus/utility" +) + +type DatabaseState struct { + Name string + + Size utility.ByteSize + + Location string + Purpose string + + Supplemental map[string]string +} + +type DatabaseStates []*DatabaseState + +func (s DatabaseStates) Len() int { + return len(s) +} + +func (s DatabaseStates) Less(i, j int) bool { + l := s[i] + r := s[j] + + if l.Name > r.Name { + return false + } + if l.Name < r.Name { + return true + } + + return l.Size < r.Size +} + +func (s DatabaseStates) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} diff --git a/tools/pruner/main.go b/tools/pruner/main.go index 61acca5d1e..adb8924e8c 100644 --- a/tools/pruner/main.go +++ b/tools/pruner/main.go @@ -44,7 +44,7 @@ func main() { log.Printf("Starting compaction...") size, _ := persistences.ApproximateSizes() log.Printf("Original Size: %d", size) - persistences.CompactKeyspaces() + persistences.Prune() log.Printf("Finished in %s", time.Since(start)) size, _ = persistences.ApproximateSizes() log.Printf("New Size: %d", size) diff --git a/web/databases.go b/web/databases.go index ff482a5ec8..fb6d48e804 100644 --- a/web/databases.go +++ b/web/databases.go @@ -16,26 +16,45 @@ package web import ( "net/http" "sync" + "time" + + "github.com/prometheus/prometheus/storage/raw" ) -type DatabasesHandler struct { - States []string +type DatabaseStatesProvider interface { + States() raw.DatabaseStates +} - Incoming chan []string +type DatabasesHandler struct { + RefreshInterval time.Duration + NextRefresh time.Time + + Current raw.DatabaseStates + + Provider DatabaseStatesProvider mutex sync.RWMutex } func (h *DatabasesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - select { - case states := <-h.Incoming: - h.mutex.Lock() - defer h.mutex.Unlock() - h.States = states - default: - h.mutex.RLock() - defer h.mutex.RUnlock() - } + h.Refresh() + h.mutex.RLock() + defer h.mutex.RUnlock() executeTemplate(w, "databases", h) } + +func (h *DatabasesHandler) Refresh() { + h.mutex.RLock() + if !time.Now().After(h.NextRefresh) { + h.mutex.RUnlock() + return + } + h.mutex.RUnlock() + + h.mutex.Lock() + defer h.mutex.Unlock() + + h.Current = h.Provider.States() + h.NextRefresh = time.Now().Add(h.RefreshInterval) +} diff --git a/web/templates/databases.html b/web/templates/databases.html index 045222964c..dd6e6b7ec9 100644 --- a/web/templates/databases.html +++ b/web/templates/databases.html @@ -3,34 +3,28 @@ {{define "content"}}
| Path | -{{.Path}} | +Location | +{{$database.Location}} |
|---|---|---|---|
| Last Refreshed | -{{.LastRefreshed}} | +Purpose | +{{$database.Purpose}} |
| Type | -{{.Type}} | +Size | +{{$database.Size}} |
| Approximate Size | -{{.ApproximateSize}} | -||
| Low Level Status | -{{.LowLevelStatus}} |
- ||
| SSTable Status | -{{.SSTablesStatus}} |
+ {{$subject}} | +{{$state}} |