Skip to content

Commit

Permalink
optimized the fine-grained lock and fixed some bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
PotatoCloud committed Jun 12, 2023
1 parent 2ce9d33 commit 071a912
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 17 deletions.
34 changes: 17 additions & 17 deletions map.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// implementation of high performance concurrent safe ordered map

package seqMap
package orderMap

import (
"sort"
Expand All @@ -24,13 +24,13 @@ func (s KVs[K, V]) Len() int { return len(s) }
func (s KVs[K, V]) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s KVs[K, V]) Less(i, j int) bool { return s[i].Value.Load().Seq < s[j].Value.Load().Seq }

type SeqMap[K comparable, V any] struct {
type Map[K comparable, V any] struct {
offset int32
mu sync.Mutex
mu sync.RWMutex
dirty map[K]*atomic.Pointer[Value[V]]
}

func (s *SeqMap[K, V]) Store(key K, value V) {
func (s *Map[K, V]) Store(key K, value V) {
s.mu.Lock()
ptr, ok := s.dirty[key]
if ok {
Expand All @@ -49,10 +49,10 @@ func (s *SeqMap[K, V]) Store(key K, value V) {
s.mu.Unlock()
}

func (s *SeqMap[K, V]) Load(key K) (V, bool) {
s.mu.Lock()
func (s *Map[K, V]) Load(key K) (V, bool) {
s.mu.RLock()
ptr, ok := s.dirty[key]
s.mu.Unlock()
s.mu.RUnlock()
if !ok {
var zero V
return zero, false
Expand All @@ -61,7 +61,7 @@ func (s *SeqMap[K, V]) Load(key K) (V, bool) {
return val.Value, true
}

func (s *SeqMap[K, V]) Delete(key K) {
func (s *Map[K, V]) Delete(key K) {
s.mu.Lock()
ptr, ok := s.dirty[key]
if !ok {
Expand All @@ -76,8 +76,8 @@ func (s *SeqMap[K, V]) Delete(key K) {
s.mu.Unlock()
}

func (s *SeqMap[K, V]) Range(f func(key K, value V) bool) {
s.mu.Lock()
func (s *Map[K, V]) Range(f func(key K, value V) bool) {
s.mu.RLock()

vs := make(KVs[K, V], atomic.LoadInt32(&s.offset))
vsi := 0
Expand All @@ -98,20 +98,20 @@ func (s *SeqMap[K, V]) Range(f func(key K, value V) bool) {
}
}

s.mu.Unlock()
s.mu.RUnlock()
}

func (s *SeqMap[K, V]) DisorderedRange(f func(key K, value V) bool) {
s.mu.Lock()
func (s *Map[K, V]) DisorderedRange(f func(key K, value V) bool) {
s.mu.RLock()
for key, val := range s.dirty {
if !f(key, val.Load().Value) {
break
}
}
s.mu.Unlock()
s.mu.RUnlock()
}

func (s *SeqMap[K, V]) Map() map[K]V {
func (s *Map[K, V]) Map() map[K]V {
m := make(map[K]V)
s.DisorderedRange(func(key K, value V) bool {
m[key] = value
Expand All @@ -120,6 +120,6 @@ func (s *SeqMap[K, V]) Map() map[K]V {
return m
}

func NewSeqMap[K comparable, V any]() *SeqMap[K, V] {
return &SeqMap[K, V]{dirty: make(map[K]*atomic.Pointer[Value[V]])}
func New[K comparable, V any]() *Map[K, V] {
return &Map[K, V]{dirty: make(map[K]*atomic.Pointer[Value[V]])}
}
68 changes: 68 additions & 0 deletions map_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package orderMap_test

import (
orderMap "github.com/RealFax/order-map"
"strconv"
"testing"
)

var (
testMap = orderMap.New[string, string]()
)

func init() {
testMap.Store("hello", "bonjour")
}

func TestMap_Store(t *testing.T) {
testMap.Store("hello1", "bonjour")
}

func TestMap_Load(t *testing.T) {
val, ok := testMap.Load("hello")
t.Log("State:", ok, ", Value:", val)
}

func TestMap_Delete(t *testing.T) {
testMap.Store("hello1", "bonjour")
val, ok := testMap.Load("hello1")
t.Log("State:", ok, ", Value:", val)

testMap.Delete("hello1")
val, ok = testMap.Load("hello1")
t.Log("State:", ok, ", Value:", val)
}

func TestMap_Range(t *testing.T) {
for i := 0; i < 5; i++ {
testMap.Store("test"+strconv.Itoa(i), "range!")
}

testMap.Range(func(key string, value string) bool {
t.Log("Key:", key, ", Value:", value)
return true
})
}

func TestMap_DisorderedRange(t *testing.T) {
for i := 0; i < 5; i++ {
testMap.Store("_test"+strconv.Itoa(i), "disordered_range!")
}

testMap.DisorderedRange(func(key string, value string) bool {
t.Log("Key:", key, ", Value:", value)
return true
})
}

func BenchmarkMap_Store(b *testing.B) {
for i := 0; i < b.N; i++ {
testMap.Store("key", "value")
}
}

func BenchmarkMap_Load(b *testing.B) {
for i := 0; i < b.N; i++ {
testMap.Load("hello")
}
}

0 comments on commit 071a912

Please sign in to comment.