infoschema: change sieve Get() function Mutex to RWMutex (#58243)

close pingcap/tidb#58227
This commit is contained in:
tiancaiamao
2024-12-16 12:01:42 +08:00
committed by GitHub
parent df0c5d1f0c
commit 9dfb87cb52
2 changed files with 56 additions and 9 deletions

View File

@ -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()

View File

@ -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()
}