infoschema: change sieve Get() function Mutex to RWMutex (#58243)
close pingcap/tidb#58227
This commit is contained in:
@ -18,6 +18,7 @@ import (
|
||||
"container/list"
|
||||
"context"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/pingcap/failpoint"
|
||||
"github.com/pingcap/tidb/pkg/infoschema/internal"
|
||||
@ -27,7 +28,7 @@ import (
|
||||
type entry[K comparable, V any] struct {
|
||||
key K
|
||||
value V
|
||||
visited bool
|
||||
visited atomic.Bool
|
||||
element *list.Element
|
||||
size uint64
|
||||
}
|
||||
@ -48,7 +49,7 @@ func (t *entry[K, V]) Size() uint64 {
|
||||
type Sieve[K comparable, V any] struct {
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
mu sync.Mutex
|
||||
mu sync.RWMutex
|
||||
size uint64
|
||||
// capacity can be set to zero for disabling infoschema v2
|
||||
capacity uint64
|
||||
@ -132,7 +133,7 @@ func (s *Sieve[K, V]) Set(key K, value V) {
|
||||
|
||||
if e, ok := s.items[key]; ok {
|
||||
e.value = value
|
||||
e.visited = true
|
||||
e.visited.Store(true)
|
||||
return
|
||||
}
|
||||
|
||||
@ -156,10 +157,13 @@ func (s *Sieve[K, V]) Get(key K) (value V, ok bool) {
|
||||
var v V
|
||||
failpoint.Return(v, false)
|
||||
})
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if e, ok := s.items[key]; ok {
|
||||
e.visited = true
|
||||
|
||||
s.mu.RLock()
|
||||
e, ok := s.items[key]
|
||||
s.mu.RUnlock()
|
||||
|
||||
if ok {
|
||||
e.visited.Store(true)
|
||||
s.hook.onHit()
|
||||
return e.value, true
|
||||
}
|
||||
@ -254,8 +258,8 @@ func (s *Sieve[K, V]) evict() {
|
||||
panic("sieve: evicting non-existent element")
|
||||
}
|
||||
|
||||
for el.visited {
|
||||
el.visited = false
|
||||
for el.visited.Load() {
|
||||
el.visited.Store(false)
|
||||
o = o.Prev()
|
||||
if o == nil {
|
||||
o = s.ll.Back()
|
||||
|
||||
@ -15,6 +15,9 @@
|
||||
package infoschema
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/rand"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"github.com/pingcap/tidb/pkg/util/size"
|
||||
@ -135,3 +138,43 @@ func TestPurge(t *testing.T) {
|
||||
|
||||
cache.Close()
|
||||
}
|
||||
|
||||
func BenchmarkSieveGet(b *testing.B) {
|
||||
c := newSieve[int, int](8192)
|
||||
ent := make([]int, b.N)
|
||||
for i := 0; i < b.N; i++ {
|
||||
var k int
|
||||
if i%2 == 0 {
|
||||
k = int(rand.Int63() % 16384)
|
||||
} else {
|
||||
k = int(rand.Int63() % 32768)
|
||||
}
|
||||
c.Set(k, k)
|
||||
ent[i] = k
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
for {
|
||||
v := int(rand.Int63() % 8192)
|
||||
c.Set(v, v)
|
||||
if ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
var hit, miss int64
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, ok := c.Get(ent[i]); ok {
|
||||
atomic.AddInt64(&hit, 1)
|
||||
} else {
|
||||
atomic.AddInt64(&miss, 1)
|
||||
}
|
||||
}
|
||||
|
||||
b.Logf("%d: hit %d, miss %d, ratio %4.2f", b.N, hit, miss, float64(hit)/float64(hit+miss))
|
||||
cancel()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user