mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-25 13:44:05 -08:00
Move to flock lockfile
Signed-off-by: Fabian Reinartz <freinartz@google.com>
This commit is contained in:
parent
3cf059159e
commit
7b578dea32
14
db.go
14
db.go
|
@ -31,7 +31,6 @@ import (
|
||||||
|
|
||||||
"github.com/go-kit/kit/log"
|
"github.com/go-kit/kit/log"
|
||||||
"github.com/go-kit/kit/log/level"
|
"github.com/go-kit/kit/log/level"
|
||||||
"github.com/nightlyone/lockfile"
|
|
||||||
"github.com/oklog/ulid"
|
"github.com/oklog/ulid"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
@ -94,7 +93,7 @@ type Appender interface {
|
||||||
// a hashed partition of a seriedb.
|
// a hashed partition of a seriedb.
|
||||||
type DB struct {
|
type DB struct {
|
||||||
dir string
|
dir string
|
||||||
lockf *lockfile.Lockfile
|
lockf fileutil.Releaser
|
||||||
|
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
metrics *dbMetrics
|
metrics *dbMetrics
|
||||||
|
@ -210,14 +209,11 @@ func Open(dir string, l log.Logger, r prometheus.Registerer, opts *Options) (db
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
lockf, err := lockfile.New(filepath.Join(absdir, "lock"))
|
lockf, _, err := fileutil.Flock(filepath.Join(absdir, "lock"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.Wrap(err, "lock DB directory")
|
||||||
}
|
}
|
||||||
if err := lockf.TryLock(); err != nil {
|
db.lockf = lockf
|
||||||
return nil, errors.Wrapf(err, "open DB in %s", dir)
|
|
||||||
}
|
|
||||||
db.lockf = &lockf
|
|
||||||
}
|
}
|
||||||
|
|
||||||
db.compactor, err = NewLeveledCompactor(r, l, opts.BlockRanges, db.chunkPool)
|
db.compactor, err = NewLeveledCompactor(r, l, opts.BlockRanges, db.chunkPool)
|
||||||
|
@ -719,7 +715,7 @@ func (db *DB) Close() error {
|
||||||
merr.Add(g.Wait())
|
merr.Add(g.Wait())
|
||||||
|
|
||||||
if db.lockf != nil {
|
if db.lockf != nil {
|
||||||
merr.Add(db.lockf.Unlock())
|
merr.Add(db.lockf.Release())
|
||||||
}
|
}
|
||||||
merr.Add(db.head.Close())
|
merr.Add(db.head.Close())
|
||||||
return merr.Err()
|
return merr.Err()
|
||||||
|
|
41
fileutil/flock.go
Normal file
41
fileutil/flock.go
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// Copyright 2016 The Prometheus Authors
|
||||||
|
// 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 fileutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Releaser provides the Release method to release a file lock.
|
||||||
|
type Releaser interface {
|
||||||
|
Release() error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flock locks the file with the provided name. If the file does not exist, it is
|
||||||
|
// created. The returned Releaser is used to release the lock. existed is true
|
||||||
|
// if the file to lock already existed. A non-nil error is returned if the
|
||||||
|
// locking has failed. Neither this function nor the returned Releaser is
|
||||||
|
// goroutine-safe.
|
||||||
|
func Flock(fileName string) (r Releaser, existed bool, err error) {
|
||||||
|
if err = os.MkdirAll(filepath.Dir(fileName), 0755); err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = os.Stat(fileName)
|
||||||
|
existed = err == nil
|
||||||
|
|
||||||
|
r, err = newLock(fileName)
|
||||||
|
return r, existed, err
|
||||||
|
}
|
32
fileutil/flock_plan9.go
Normal file
32
fileutil/flock_plan9.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright 2016 The Prometheus Authors
|
||||||
|
// 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 fileutil
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
type plan9Lock struct {
|
||||||
|
f *os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *plan9Lock) Release() error {
|
||||||
|
return l.f.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLock(fileName string) (Releaser, error) {
|
||||||
|
f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, os.ModeExclusive|0644)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &plan9Lock{f}, nil
|
||||||
|
}
|
59
fileutil/flock_solaris.go
Normal file
59
fileutil/flock_solaris.go
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
// Copyright 2016 The Prometheus Authors
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// +build solaris
|
||||||
|
|
||||||
|
package fileutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
type unixLock struct {
|
||||||
|
f *os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *unixLock) Release() error {
|
||||||
|
if err := l.set(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return l.f.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *unixLock) set(lock bool) error {
|
||||||
|
flock := syscall.Flock_t{
|
||||||
|
Type: syscall.F_UNLCK,
|
||||||
|
Start: 0,
|
||||||
|
Len: 0,
|
||||||
|
Whence: 1,
|
||||||
|
}
|
||||||
|
if lock {
|
||||||
|
flock.Type = syscall.F_WRLCK
|
||||||
|
}
|
||||||
|
return syscall.FcntlFlock(l.f.Fd(), syscall.F_SETLK, &flock)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLock(fileName string) (Releaser, error) {
|
||||||
|
f, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
l := &unixLock{f}
|
||||||
|
err = l.set(true)
|
||||||
|
if err != nil {
|
||||||
|
f.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return l, nil
|
||||||
|
}
|
80
fileutil/flock_test.go
Normal file
80
fileutil/flock_test.go
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
// Copyright 2016 The Prometheus Authors
|
||||||
|
// 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 fileutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/prometheus/prometheus/util/testutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLocking(t *testing.T) {
|
||||||
|
dir := testutil.NewTemporaryDirectory("test_flock", t)
|
||||||
|
defer dir.Close()
|
||||||
|
|
||||||
|
fileName := filepath.Join(dir.Path(), "LOCK")
|
||||||
|
|
||||||
|
if _, err := os.Stat(fileName); err == nil {
|
||||||
|
t.Fatalf("File %q unexpectedly exists.", fileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
lock, existed, err := Flock(fileName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error locking file %q: %s", fileName, err)
|
||||||
|
}
|
||||||
|
if existed {
|
||||||
|
t.Errorf("File %q reported as existing during locking.", fileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// File must now exist.
|
||||||
|
if _, err = os.Stat(fileName); err != nil {
|
||||||
|
t.Errorf("Could not stat file %q expected to exist: %s", fileName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to lock again.
|
||||||
|
lockedAgain, existed, err := Flock(fileName)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("File %q locked twice.", fileName)
|
||||||
|
}
|
||||||
|
if lockedAgain != nil {
|
||||||
|
t.Error("Unsuccessful locking did not return nil.")
|
||||||
|
}
|
||||||
|
if !existed {
|
||||||
|
t.Errorf("Existing file %q not recognized.", fileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := lock.Release(); err != nil {
|
||||||
|
t.Errorf("Error releasing lock for file %q: %s", fileName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// File must still exist.
|
||||||
|
if _, err = os.Stat(fileName); err != nil {
|
||||||
|
t.Errorf("Could not stat file %q expected to exist: %s", fileName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock existing file.
|
||||||
|
lock, existed, err = Flock(fileName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error locking file %q: %s", fileName, err)
|
||||||
|
}
|
||||||
|
if !existed {
|
||||||
|
t.Errorf("Existing file %q not recognized.", fileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := lock.Release(); err != nil {
|
||||||
|
t.Errorf("Error releasing lock for file %q: %s", fileName, err)
|
||||||
|
}
|
||||||
|
}
|
54
fileutil/flock_unix.go
Normal file
54
fileutil/flock_unix.go
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
// Copyright 2016 The Prometheus Authors
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// +build darwin dragonfly freebsd linux netbsd openbsd
|
||||||
|
|
||||||
|
package fileutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
type unixLock struct {
|
||||||
|
f *os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *unixLock) Release() error {
|
||||||
|
if err := l.set(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return l.f.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *unixLock) set(lock bool) error {
|
||||||
|
how := syscall.LOCK_UN
|
||||||
|
if lock {
|
||||||
|
how = syscall.LOCK_EX
|
||||||
|
}
|
||||||
|
return syscall.Flock(int(l.f.Fd()), how|syscall.LOCK_NB)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLock(fileName string) (Releaser, error) {
|
||||||
|
f, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
l := &unixLock{f}
|
||||||
|
err = l.set(true)
|
||||||
|
if err != nil {
|
||||||
|
f.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return l, nil
|
||||||
|
}
|
36
fileutil/flock_windows.go
Normal file
36
fileutil/flock_windows.go
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
// Copyright 2016 The Prometheus Authors
|
||||||
|
// 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 fileutil
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
type windowsLock struct {
|
||||||
|
fd syscall.Handle
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fl *windowsLock) Release() error {
|
||||||
|
return syscall.Close(fl.fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLock(fileName string) (Releaser, error) {
|
||||||
|
pathp, err := syscall.UTF16PtrFromString(fileName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fd, err := syscall.CreateFile(pathp, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.CREATE_ALWAYS, syscall.FILE_ATTRIBUTE_NORMAL, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &windowsLock{fd}, nil
|
||||||
|
}
|
Loading…
Reference in a new issue