mirror of
https://github.com/cubefs/cubefs.git
synced 2026-08-02 02:00:56 +00:00
perf(util): add mutex with run function safely
. #22309205 Signed-off-by: slasher <shenjie1@oppo.com>
This commit is contained in:
parent
c65a4aa48b
commit
1d1efefa15
98
blobstore/util/mutex/example_test.go
Normal file
98
blobstore/util/mutex/example_test.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// Copyright 2024 The CubeFS 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 mutex_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/cubefs/cubefs/blobstore/util/mutex"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleMutex() {
|
||||||
|
var m mutex.Mutex
|
||||||
|
m.Lock()
|
||||||
|
fmt.Println("mutex locked")
|
||||||
|
m.Unlock()
|
||||||
|
|
||||||
|
err := m.WithLock(func() error { return mutex.Nil })
|
||||||
|
fmt.Println("mutex got error:", err)
|
||||||
|
|
||||||
|
fmt.Println()
|
||||||
|
l := mutex.NewLocker(&sync.Mutex{})
|
||||||
|
l.Lock()
|
||||||
|
fmt.Println("locker locked")
|
||||||
|
l.Unlock()
|
||||||
|
|
||||||
|
err = l.WithLock(func() error { return fmt.Errorf("locker error") })
|
||||||
|
fmt.Println("locker got error:", err)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// mutex locked
|
||||||
|
// mutex got error: mutex.Nil
|
||||||
|
//
|
||||||
|
// locker locked
|
||||||
|
// locker got error: locker error
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleRWMutex() {
|
||||||
|
var m mutex.RWMutex
|
||||||
|
m.Lock()
|
||||||
|
fmt.Println("rwmutex locked")
|
||||||
|
m.Unlock()
|
||||||
|
|
||||||
|
m.RLock()
|
||||||
|
fmt.Println("rwmutex rlocked")
|
||||||
|
m.RUnlock()
|
||||||
|
|
||||||
|
err := m.WithLock(func() error { return mutex.Nil })
|
||||||
|
fmt.Println("rwmutex got error:", err)
|
||||||
|
err = m.WithRLock(func() error { return nil })
|
||||||
|
fmt.Println("rwmutex got nil:", err == nil)
|
||||||
|
|
||||||
|
rl := m.RLocker()
|
||||||
|
rl.Lock()
|
||||||
|
rl.Lock()
|
||||||
|
fmt.Println("rwmutex RLock as Lock")
|
||||||
|
rl.Unlock()
|
||||||
|
rl.Unlock()
|
||||||
|
|
||||||
|
fmt.Println()
|
||||||
|
l := mutex.NewRLocker(&sync.RWMutex{})
|
||||||
|
l.Lock()
|
||||||
|
fmt.Println("rlocker locked")
|
||||||
|
l.Unlock()
|
||||||
|
|
||||||
|
l.RLock()
|
||||||
|
fmt.Println("rlocker rlocked")
|
||||||
|
l.RUnlock()
|
||||||
|
|
||||||
|
err = l.WithLock(func() error { return mutex.Nil })
|
||||||
|
fmt.Println("rlocker got error:", err)
|
||||||
|
err = l.WithRLock(func() error { return nil })
|
||||||
|
fmt.Println("rlocker got nil:", err == nil)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// rwmutex locked
|
||||||
|
// rwmutex rlocked
|
||||||
|
// rwmutex got error: mutex.Nil
|
||||||
|
// rwmutex got nil: true
|
||||||
|
// rwmutex RLock as Lock
|
||||||
|
//
|
||||||
|
// rlocker locked
|
||||||
|
// rlocker rlocked
|
||||||
|
// rlocker got error: mutex.Nil
|
||||||
|
// rlocker got nil: true
|
||||||
|
}
|
||||||
116
blobstore/util/mutex/mutex.go
Normal file
116
blobstore/util/mutex/mutex.go
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
// Copyright 2024 The CubeFS 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 mutex
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: add TryLock and TryRLock upgrating to Go1.18+
|
||||||
|
|
||||||
|
type nilError struct{}
|
||||||
|
|
||||||
|
func (nilError) Error() string { return "mutex.Nil" }
|
||||||
|
|
||||||
|
// Nil is the error which you want an error in function WithLock or WithRLock,
|
||||||
|
// and then returns it outside to do other choice.
|
||||||
|
var Nil error = nilError{}
|
||||||
|
|
||||||
|
// Locker represents an object that can be locked, unlocked.
|
||||||
|
type Locker interface {
|
||||||
|
sync.Locker
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithLocker represents a function to run with locker.
|
||||||
|
type WithLocker interface {
|
||||||
|
Locker
|
||||||
|
// WithLock runs function in lock.
|
||||||
|
WithLock(func() error) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// RLocker represents a reader/writer mutual exclusion locker.
|
||||||
|
type RLocker interface {
|
||||||
|
Locker
|
||||||
|
RLock()
|
||||||
|
RUnlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithRLocker represents a function to run with reading locker.
|
||||||
|
type WithRLocker interface {
|
||||||
|
RLocker
|
||||||
|
WithLocker
|
||||||
|
// WithRLock runs function in reading lock.
|
||||||
|
WithRLock(func() error) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mutex is a WithLocker with sync.Mutex.
|
||||||
|
type Mutex struct{ sync.Mutex }
|
||||||
|
|
||||||
|
var _ WithLocker = (*Mutex)(nil)
|
||||||
|
|
||||||
|
func (m *Mutex) WithLock(f func() error) error {
|
||||||
|
m.Lock()
|
||||||
|
defer m.Unlock()
|
||||||
|
return f()
|
||||||
|
}
|
||||||
|
|
||||||
|
type mutex struct{ Locker }
|
||||||
|
|
||||||
|
func (m *mutex) WithLock(f func() error) error {
|
||||||
|
m.Locker.Lock()
|
||||||
|
defer m.Locker.Unlock()
|
||||||
|
return f()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLocker returns a WithLocker with the Locker.
|
||||||
|
func NewLocker(locker Locker) WithLocker {
|
||||||
|
return &mutex{Locker: locker}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RWMutex is a WithRLocker with sync.RWMutex.
|
||||||
|
type RWMutex struct{ sync.RWMutex }
|
||||||
|
|
||||||
|
var _ WithRLocker = (*RWMutex)(nil)
|
||||||
|
|
||||||
|
func (m *RWMutex) WithLock(f func() error) error {
|
||||||
|
m.Lock()
|
||||||
|
defer m.Unlock()
|
||||||
|
return f()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *RWMutex) WithRLock(f func() error) error {
|
||||||
|
m.RLock()
|
||||||
|
defer m.RUnlock()
|
||||||
|
return f()
|
||||||
|
}
|
||||||
|
|
||||||
|
type rwMutex struct{ RLocker }
|
||||||
|
|
||||||
|
func (m *rwMutex) WithLock(f func() error) error {
|
||||||
|
m.RLocker.Lock()
|
||||||
|
defer m.RLocker.Unlock()
|
||||||
|
return f()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *rwMutex) WithRLock(f func() error) error {
|
||||||
|
m.RLocker.RLock()
|
||||||
|
defer m.RLocker.RUnlock()
|
||||||
|
return f()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRLocker returns a WithRLocker with the RLocker.
|
||||||
|
func NewRLocker(rlocker RLocker) WithRLocker {
|
||||||
|
return &rwMutex{RLocker: rlocker}
|
||||||
|
}
|
||||||
78
blobstore/util/mutex/mutex_test.go
Normal file
78
blobstore/util/mutex/mutex_test.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
// Copyright 2024 The CubeFS 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 mutex_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/cubefs/cubefs/blobstore/util/mutex"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMutexWith(t *testing.T) {
|
||||||
|
var m mutex.Mutex
|
||||||
|
val := -1
|
||||||
|
f := func() error {
|
||||||
|
val++
|
||||||
|
switch val {
|
||||||
|
case 0:
|
||||||
|
return nil
|
||||||
|
case 1:
|
||||||
|
return mutex.Nil
|
||||||
|
default:
|
||||||
|
return errors.New("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
require.Nil(t, m.WithLock(f))
|
||||||
|
nilErr := m.WithLock(f)
|
||||||
|
require.ErrorIs(t, nilErr, mutex.Nil)
|
||||||
|
require.Equal(t, mutex.Nil, nilErr)
|
||||||
|
require.Error(t, m.WithLock(f))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_Span_Assertion(b *testing.B) {
|
||||||
|
var m mutex.RWMutex
|
||||||
|
f := func() error { return nil }
|
||||||
|
b.Run("Lock", func(b *testing.B) {
|
||||||
|
b.ResetTimer()
|
||||||
|
for ii := 0; ii <= b.N; ii++ {
|
||||||
|
m.Lock()
|
||||||
|
_ = struct{}{}
|
||||||
|
m.Unlock()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
b.Run("WithLock", func(b *testing.B) {
|
||||||
|
b.ResetTimer()
|
||||||
|
for ii := 0; ii <= b.N; ii++ {
|
||||||
|
m.WithLock(f)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Run("RLock", func(b *testing.B) {
|
||||||
|
b.ResetTimer()
|
||||||
|
for ii := 0; ii <= b.N; ii++ {
|
||||||
|
m.RLock()
|
||||||
|
_ = struct{}{}
|
||||||
|
m.RUnlock()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
b.Run("WithRLock", func(b *testing.B) {
|
||||||
|
b.ResetTimer()
|
||||||
|
for ii := 0; ii <= b.N; ii++ {
|
||||||
|
m.WithRLock(f)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user