Skip to content

Commit 2f1bfc1

Browse files
authored
Merge pull request #1370 from ydb-platform/xsync
internal/xsync improvements
2 parents 4a3769b + f723185 commit 2f1bfc1

File tree

4 files changed

+72
-31
lines changed

4 files changed

+72
-31
lines changed

internal/xsync/map.go

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ package xsync
33
import (
44
"fmt"
55
"sync"
6+
"sync/atomic"
67
)
78

89
type Map[K comparable, V any] struct {
9-
m sync.Map
10+
m sync.Map
11+
size atomic.Int32
1012
}
1113

12-
func (m *Map[K, V]) Load(key K) (value V, ok bool) {
14+
func (m *Map[K, V]) Get(key K) (value V, ok bool) {
1315
v, ok := m.m.Load(key)
1416
if !ok {
1517
return value, false
@@ -38,22 +40,36 @@ func (m *Map[K, V]) Has(key K) bool {
3840
return ok
3941
}
4042

41-
func (m *Map[K, V]) Store(key K, value V) {
42-
m.m.Store(key, value)
43+
func (m *Map[K, V]) Set(key K, value V) {
44+
_, exists := m.m.LoadOrStore(key, value)
45+
46+
if !exists {
47+
m.size.Add(1)
48+
}
4349
}
4450

45-
func (m *Map[K, V]) Delete(key K) (ok bool) {
46-
_, ok = m.LoadAndDelete(key)
51+
func (m *Map[K, V]) Delete(key K) bool {
52+
_, exists := m.Extract(key)
4753

48-
return ok
54+
if !exists {
55+
m.size.Add(-1)
56+
}
57+
58+
return exists
4959
}
5060

51-
func (m *Map[K, V]) LoadAndDelete(key K) (value V, ok bool) {
52-
v, ok := m.m.LoadAndDelete(key)
53-
if !ok {
61+
func (m *Map[K, V]) Size() int {
62+
return int(m.size.Load())
63+
}
64+
65+
func (m *Map[K, V]) Extract(key K) (value V, ok bool) {
66+
v, exists := m.m.LoadAndDelete(key)
67+
if !exists {
5468
return value, false
5569
}
5670

71+
m.size.Add(-1)
72+
5773
value, ok = v.(V)
5874

5975
return value, ok
@@ -65,10 +81,16 @@ func (m *Map[K, V]) Range(f func(key K, value V) bool) {
6581
})
6682
}
6783

68-
func (m *Map[K, V]) Clear() {
84+
func (m *Map[K, V]) Clear() (removed int) {
6985
m.m.Range(func(k, v any) bool {
86+
removed++
87+
7088
m.m.Delete(k)
7189

7290
return true
7391
})
92+
93+
m.size.Add(int32(-removed))
94+
95+
return removed
7496
}

internal/xsync/map_test.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import (
88

99
func TestMap(t *testing.T) {
1010
var m Map[int, string]
11-
v, ok := m.Load(1)
11+
v, ok := m.Get(1)
1212
require.False(t, ok)
13-
m.Store(1, "one")
13+
m.Set(1, "one")
1414
require.NotPanics(t, func() {
1515
v = m.Must(1)
1616
require.Equal(t, "one", v)
@@ -23,25 +23,26 @@ func TestMap(t *testing.T) {
2323
v = m.Must(2)
2424
})
2525
m.m.Delete(2)
26-
v, ok = m.LoadAndDelete(2)
26+
v, ok = m.Extract(2)
2727
require.False(t, ok)
2828
require.Equal(t, "", v)
29-
m.Store(2, "two")
30-
v, ok = m.Load(2)
29+
m.Set(2, "two")
30+
v, ok = m.Get(2)
3131
require.True(t, ok)
3232
require.Equal(t, "two", v)
33-
v, ok = m.LoadAndDelete(1)
33+
v, ok = m.Extract(1)
3434
require.True(t, ok)
3535
require.Equal(t, "one", v)
3636
require.False(t, m.Has(1))
37-
m.Store(3, "three")
38-
v, ok = m.Load(3)
37+
m.Set(3, "three")
38+
v, ok = m.Get(3)
3939
require.True(t, ok)
4040
require.Equal(t, "three", v)
4141
exp := map[int]string{
4242
2: "two",
4343
3: "three",
4444
}
45+
require.Equal(t, 2, m.Size())
4546
var unexp map[int]string
4647
m.Range(func(key int, value string) bool {
4748
if v, ok := exp[key]; ok && v == value {
@@ -55,6 +56,7 @@ func TestMap(t *testing.T) {
5556
require.Empty(t, exp)
5657
require.Empty(t, unexp)
5758
m.Clear()
59+
require.Zero(t, m.Size())
5860
empty := true
5961
m.Range(func(key int, value string) bool {
6062
empty = false

internal/xsync/set.go

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,53 @@ package xsync
22

33
import (
44
"sync"
5+
"sync/atomic"
56
)
67

78
type Set[K comparable] struct {
8-
m sync.Map
9+
m sync.Map
10+
size atomic.Int32
911
}
1012

11-
func (m *Set[K]) Has(key K) bool {
12-
_, ok := m.m.Load(key)
13+
func (s *Set[K]) Has(key K) bool {
14+
_, ok := s.m.Load(key)
1315

1416
return ok
1517
}
1618

17-
func (m *Set[K]) Add(key K) bool {
18-
_, loaded := m.m.LoadOrStore(key, struct{}{})
19+
func (s *Set[K]) Add(key K) bool {
20+
_, exists := s.m.LoadOrStore(key, struct{}{})
1921

20-
return !loaded
22+
if !exists {
23+
s.size.Add(1)
24+
}
25+
26+
return !exists
2127
}
2228

23-
func (m *Set[K]) Remove(key K) (ok bool) {
24-
_, ok = m.m.LoadAndDelete(key)
29+
func (s *Set[K]) Size() int {
30+
return int(s.size.Load())
31+
}
2532

26-
return ok
33+
func (s *Set[K]) Remove(key K) bool {
34+
_, exists := s.m.LoadAndDelete(key)
35+
36+
if exists {
37+
s.size.Add(-1)
38+
}
39+
40+
return exists
2741
}
2842

29-
func (m *Set[K]) Clear() (removed int) {
30-
m.m.Range(func(k, v any) bool {
43+
func (s *Set[K]) Clear() (removed int) {
44+
s.m.Range(func(k, v any) bool {
3145
removed++
3246

33-
m.m.Delete(k)
47+
s.m.Delete(k)
3448

3549
return true
3650
})
51+
s.size.Add(int32(-removed))
3752

3853
return removed
3954
}

internal/xsync/set_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,7 @@ func TestSet(t *testing.T) {
1515
require.True(t, s.Add(2))
1616
require.True(t, s.Remove(1))
1717
require.False(t, s.Has(1))
18+
require.Equal(t, 1, s.Size())
1819
require.Equal(t, 1, s.Clear())
20+
require.Zero(t, s.Size())
1921
}

0 commit comments

Comments
 (0)