diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-26 08:15:24 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-26 08:15:35 +0000 |
commit | f09848204fa5283d21ea43e262ee41aa578e1808 (patch) | |
tree | c62385d7adf209fa6a798635954d887f718fb3fb /src/go/plugin/go.d/agent/filelock | |
parent | Releasing debian version 1.46.3-2. (diff) | |
download | netdata-f09848204fa5283d21ea43e262ee41aa578e1808.tar.xz netdata-f09848204fa5283d21ea43e262ee41aa578e1808.zip |
Merging upstream version 1.47.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/go/plugin/go.d/agent/filelock')
-rw-r--r-- | src/go/plugin/go.d/agent/filelock/filelock.go | 64 | ||||
-rw-r--r-- | src/go/plugin/go.d/agent/filelock/filelock_test.go | 99 |
2 files changed, 163 insertions, 0 deletions
diff --git a/src/go/plugin/go.d/agent/filelock/filelock.go b/src/go/plugin/go.d/agent/filelock/filelock.go new file mode 100644 index 000000000..f266e0102 --- /dev/null +++ b/src/go/plugin/go.d/agent/filelock/filelock.go @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package filelock + +import ( + "path/filepath" + + "github.com/gofrs/flock" +) + +func New(dir string) *Locker { + return &Locker{ + suffix: ".collector.lock", + dir: dir, + locks: make(map[string]*flock.Flock), + } +} + +type Locker struct { + suffix string + dir string + locks map[string]*flock.Flock +} + +func (l *Locker) Lock(name string) (bool, error) { + filename := l.filename(name) + + if _, ok := l.locks[filename]; ok { + return true, nil + } + + locker := flock.New(filename) + + ok, err := locker.TryLock() + if ok { + l.locks[filename] = locker + } else { + _ = locker.Close() + } + + return ok, err +} + +func (l *Locker) Unlock(name string) { + filename := l.filename(name) + + locker, ok := l.locks[filename] + if !ok { + return + } + + delete(l.locks, filename) + + _ = locker.Close() +} + +func (l *Locker) isLocked(name string) bool { + _, ok := l.locks[l.filename(name)] + return ok +} + +func (l *Locker) filename(name string) string { + return filepath.Join(l.dir, name+l.suffix) +} diff --git a/src/go/plugin/go.d/agent/filelock/filelock_test.go b/src/go/plugin/go.d/agent/filelock/filelock_test.go new file mode 100644 index 000000000..6ffc794ec --- /dev/null +++ b/src/go/plugin/go.d/agent/filelock/filelock_test.go @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package filelock + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNew(t *testing.T) { + assert.NotNil(t, New("")) +} + +func TestLocker_Lock(t *testing.T) { + tests := map[string]func(t *testing.T, dir string){ + "register a lock": func(t *testing.T, dir string) { + reg := New(dir) + + ok, err := reg.Lock("name") + assert.True(t, ok) + assert.NoError(t, err) + }, + "register the same lock twice": func(t *testing.T, dir string) { + reg := New(dir) + + ok, err := reg.Lock("name") + require.True(t, ok) + require.NoError(t, err) + + ok, err = reg.Lock("name") + assert.True(t, ok) + assert.NoError(t, err) + }, + "failed to register locked by other process lock": func(t *testing.T, dir string) { + reg1 := New(dir) + reg2 := New(dir) + + ok, err := reg1.Lock("name") + require.True(t, ok) + require.NoError(t, err) + + ok, err = reg2.Lock("name") + assert.False(t, ok) + assert.NoError(t, err) + }, + "failed to register because a directory doesnt exist": func(t *testing.T, dir string) { + reg := New(dir + dir) + + ok, err := reg.Lock("name") + assert.False(t, ok) + assert.Error(t, err) + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + dir, err := os.MkdirTemp(os.TempDir(), "netdata-go-test-file-lock-registry") + require.NoError(t, err) + defer func() { require.NoError(t, os.RemoveAll(dir)) }() + + test(t, dir) + }) + } +} + +func TestLocker_Unlock(t *testing.T) { + tests := map[string]func(t *testing.T, dir string){ + "unregister a lock": func(t *testing.T, dir string) { + reg := New(dir) + + ok, err := reg.Lock("name") + require.True(t, ok) + require.NoError(t, err) + reg.Unlock("name") + + assert.False(t, reg.isLocked("name")) + }, + "unregister not registered lock": func(t *testing.T, dir string) { + reg := New(dir) + + reg.Unlock("name") + + assert.False(t, reg.isLocked("name")) + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + dir, err := os.MkdirTemp(os.TempDir(), "netdata-go-test-file-lock-registry") + require.NoError(t, err) + defer func() { require.NoError(t, os.RemoveAll(dir)) }() + + test(t, dir) + }) + } +} |