Expose interfaces for pruner and make pruner tool.

In order to run database cleanups and diagnostics, we should have
a means for pruning a database---even if LevelDB does this for us.
This commit is contained in:
Matt T. Proud 2013-05-10 16:41:02 +02:00
parent 76521c3ff0
commit fa6a1f97d0
8 changed files with 184 additions and 3 deletions

View File

@ -23,12 +23,13 @@ advice:
binary: build
go build $(BUILDFLAGS) .
build: preparation config model web
build: preparation config model tools web
clean:
$(MAKE) -C build clean
$(MAKE) -C config clean
$(MAKE) -C model clean
$(MAKE) -C tools clean
$(MAKE) -C web clean
rm -rf $(TEST_ARTIFACTS)
-find . -type f -iname '*~' -exec rm '{}' ';'
@ -72,7 +73,10 @@ source_path:
test: build
go test ./... $(GO_TEST_FLAGS)
tools:
$(MAKE) -C tools
web: preparation config model
$(MAKE) -C web
.PHONY: advice binary build clean config documentation format model package preparation run search_index source_path test
.PHONY: advice binary build clean config documentation format model package preparation run search_index source_path test tools

View File

@ -876,3 +876,35 @@ func (l *LevelDBMetricPersistence) GetAllValuesForLabel(labelName model.LabelNam
func (l *LevelDBMetricPersistence) ForEachSample(builder IteratorsForFingerprintBuilder) (err error) {
panic("not implemented")
}
// CompactKeyspace compacts each database's keyspace serially. An error may
// be returned if there are difficulties with the underlying database or if
// it's empty.
//
// Beware that it would probably be imprudent to run this on a live user-facing
// server due to latency implications.
func (l *LevelDBMetricPersistence) CompactKeyspaces() error {
if err := l.CurationRemarks.CompactKeyspace(); err != nil {
return fmt.Errorf("Could not compact curation remarks: %s", err)
}
if err := l.fingerprintToMetrics.CompactKeyspace(); err != nil {
return fmt.Errorf("Could not compact fingerprint to metric index: %s", err)
}
if err := l.labelNameToFingerprints.CompactKeyspace(); err != nil {
return fmt.Errorf("Could not compact label name to fingerprint index: %s", err)
}
if err := l.labelSetToFingerprints.CompactKeyspace(); err != nil {
return fmt.Errorf("Could not compact label pair to fingerprint index: %s", err)
}
if err := l.MetricHighWatermarks.CompactKeyspace(); err != nil {
return fmt.Errorf("Could not compact metric high watermarks: %s", err)
}
if err := l.metricMembershipIndex.CompactKeyspace(); err != nil {
return fmt.Errorf("Could not compact metric membership index: %s", err)
}
if err := l.MetricSamples.CompactKeyspace(); err != nil {
return fmt.Errorf("Could not compact metric samples database: %s", err)
}
return nil
}

View File

@ -61,3 +61,13 @@ func NewLevelDBMembershipIndex(storageRoot string, cacheCapacity, bitsPerBloomFi
func (l *LevelDBMembershipIndex) Commit(batch raw.Batch) error {
return l.persistence.Commit(batch)
}
// CompactKeyspace compacts the entire database's keyspace. An error may be
// returned if there are difficulties with the underlying database or if it's
// empty.
//
// Beware that it would probably be imprudent to run this on a live user-facing
// server due to latency implications.
func (l *LevelDBMembershipIndex) CompactKeyspace() error {
return l.persistence.CompactKeyspace()
}

View File

@ -195,10 +195,12 @@ func NewLevelDBPersistence(storageRoot string, cacheCapacity, bitsPerBloomFilter
p = &LevelDBPersistence{
cache: cache,
filterPolicy: filterPolicy,
options: options,
readOptions: readOptions,
storage: storage,
writeOptions: writeOptions,
storage: storage,
}
return
@ -306,6 +308,35 @@ func (l *LevelDBPersistence) Commit(b raw.Batch) (err error) {
return l.storage.Write(l.writeOptions, batch.batch)
}
// CompactKeyspace compacts the entire database's keyspace. An error may be
// returned if there are difficulties with the underlying database or if it's
// empty.
//
// Beware that it would probably be imprudent to run this on a live user-facing
// server due to latency implications.
func (l *LevelDBPersistence) CompactKeyspace() error {
iterator := l.NewIterator(false)
defer iterator.Close()
if !iterator.SeekToFirst() {
return fmt.Errorf("could not seek to first key")
}
keyspace := levigo.Range{}
keyspace.Start = iterator.Key()
if !iterator.SeekToLast() {
return fmt.Errorf("could not seek to last key")
}
keyspace.Limit = iterator.Key()
l.storage.CompactRange(keyspace)
return nil
}
// NewIterator creates a new levigoIterator, which follows the Iterator
// interface.
//

26
tools/Makefile Normal file
View File

@ -0,0 +1,26 @@
# 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.
all: pruner
SUFFIXES:
include ../Makefile.INCLUDE
pruner:
$(MAKE) -C pruner
clean:
$(MAKE) -C pruner clean
.PHONY: clean pruner

1
tools/pruner/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
pruner

28
tools/pruner/Makefile Normal file
View File

@ -0,0 +1,28 @@
# 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.
MAKE_ARTIFACTS = pruner
all: pruner
SUFFIXES:
include ../../Makefile.INCLUDE
pruner: $(shell find . -iname '*.go')
go build -o pruner .
clean:
rm -rf $(MAKE_ARTIFACTS)
.PHONY: clean

49
tools/pruner/main.go Normal file
View File

@ -0,0 +1,49 @@
// 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.
// Pruner is responsible for cleaning all Prometheus disk databases, which
// minimally includes 1. applying pending commit logs, 2. compacting SSTables,
// 3. purging stale SSTables, and 4. removing old tombstones.
package main
import (
"flag"
"github.com/prometheus/prometheus/storage/metric"
"log"
"time"
)
var (
storageRoot = flag.String("storage.root", "", "The path to the storage root for Prometheus.")
)
func main() {
flag.Parse()
if storageRoot == nil || *storageRoot == "" {
log.Fatal("Must provide a path...")
}
persistences, err := metric.NewLevelDBMetricPersistence(*storageRoot)
if err != nil {
log.Fatal(err)
}
defer persistences.Close()
start := time.Now()
log.Printf("Starting compaction...")
if err := persistences.CompactKeyspaces(); err != nil {
log.Fatalf("Abording after %s", time.Since(start))
}
log.Printf("Finished in %s", time.Since(start))
}