Code Review: First pass.

This commit is contained in:
Matt T. Proud 2013-08-05 17:31:49 +02:00
parent d8792cfd86
commit 07ac921aec
12 changed files with 237 additions and 177 deletions

45
main.go
View file

@ -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 {

View file

@ -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
}

View file

@ -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(),

View file

@ -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
}

View file

@ -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()
}

View file

@ -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)
}

View file

@ -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{

View file

@ -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()
}

53
storage/raw/state.go Normal file
View file

@ -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]
}

View file

@ -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)

View file

@ -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)
}

View file

@ -3,34 +3,28 @@
{{define "content"}}
<div class="container-fluid">
<h2>Database Information</h2>
{{range .States}}
<h3>{{.Name}}</h3>
{{range $database := .Current }}
<h3>{{$database.Name}}</h3>
<table class="table table-bordered table-condensed table-hover literal_output">
<tbody>
<tr>
<th>Path</th>
<td>{{.Path}}</td>
<th>Location</th>
<td>{{$database.Location}}</td>
</tr>
<tr>
<th>Last Refreshed</th>
<td>{{.LastRefreshed}}</td>
<th>Purpose</th>
<td>{{$database.Purpose}}</td>
</tr>
<tr>
<th>Type</th>
<td>{{.Type}}</td>
<th>Size</th>
<td>{{$database.Size}}</td>
</tr>
{{range $subject, $state := $database.Supplemental }}
<tr>
<th>Approximate Size</th>
<td>{{.ApproximateSize}}</td>
</tr>
<tr>
<th>Low Level Status</th>
<td><pre>{{.LowLevelStatus}}</pre></td>
</tr>
<tr>
<th>SSTable Status</th>
<td><pre>{{.SSTablesStatus}}</pre></td>
<th>{{$subject}}</th>
<td><pre>{{$state}}</pre></td>
</tr>
{{end}}
</tbody>
</table>
{{end}}