lnutils+lntemp: move SyncMap to lnutils
This commit moves the `SyncMap` from `lntemp/node` into `lnutils` so it can be used by other packages.
This commit is contained in:
4 files changed
+286
-21
No files matched your search
@@ -0,0 +1,53 @@
|
||||
package lnutils
|
||||
|
||||
import "sync"
|
||||
|
||||
// SyncMap wraps a sync.Map with type parameters such that it's easier to
|
||||
// access the items stored in the map since no type assertion is needed. It
|
||||
// also requires explicit type definition when declaring and initiating the
|
||||
// variables, which helps us understanding what's stored in a given map.
|
||||
type SyncMap[K comparable, V any] struct {
|
||||
sync.Map
|
||||
}
|
||||
|
||||
// Store puts an item in the map.
|
||||
func (m *SyncMap[K, V]) Store(key K, value V) {
|
||||
m.Map.Store(key, value)
|
||||
}
|
||||
|
||||
// Load queries an item from the map using the specified key. If the item
|
||||
// cannot be found, an empty value and false will be returned. If the stored
|
||||
// item fails the type assertion, a nil value and false will be returned.
|
||||
func (m *SyncMap[K, V]) Load(key K) (V, bool) {
|
||||
result, ok := m.Map.Load(key)
|
||||
if !ok {
|
||||
return *new(V), false // nolint: gocritic
|
||||
}
|
||||
|
||||
item, ok := result.(V)
|
||||
return item, ok
|
||||
}
|
||||
|
||||
// Delete removes an item from the map specified by the key.
|
||||
func (m *SyncMap[K, V]) Delete(key K) {
|
||||
m.Map.Delete(key)
|
||||
}
|
||||
|
||||
// LoadAndDelete queries an item and deletes it from the map using the
|
||||
// specified key.
|
||||
func (m *SyncMap[K, V]) LoadAndDelete(key K) (V, bool) {
|
||||
result, loaded := m.Map.LoadAndDelete(key)
|
||||
if !loaded {
|
||||
return *new(V), loaded // nolint: gocritic
|
||||
}
|
||||
|
||||
item, ok := result.(V)
|
||||
return item, ok
|
||||
}
|
||||
|
||||
// Range iterates the map.
|
||||
func (m *SyncMap[K, V]) Range(visitor func(K, V) bool) {
|
||||
m.Map.Range(func(k any, v any) bool {
|
||||
return visitor(k.(K), v.(V))
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
package lnutils_test
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"github.com/lightningnetwork/lnd/lnutils"
|
||||
)
|
||||
|
||||
func BenchmarkReadMutexMap(b *testing.B) {
|
||||
// Create a map with a mutex.
|
||||
m := make(map[int64]struct{})
|
||||
|
||||
// k is the unique key for each goroutine.
|
||||
k := int64(0)
|
||||
|
||||
// Create a general mutex.
|
||||
var mu sync.Mutex
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
// Increment k.
|
||||
atomic.AddInt64(&k, 1)
|
||||
|
||||
// Perform a lock read.
|
||||
mu.Lock()
|
||||
_ = m[k]
|
||||
mu.Unlock()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkReadRWMutexMap(b *testing.B) {
|
||||
// Create a map with a mutex.
|
||||
m := make(map[int64]struct{})
|
||||
|
||||
// k is the unique key for each goroutine.
|
||||
k := int64(0)
|
||||
|
||||
// Create a read write mutex.
|
||||
var mu sync.RWMutex
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
// Increment k.
|
||||
atomic.AddInt64(&k, 1)
|
||||
|
||||
// Perform a lock read.
|
||||
mu.RLock()
|
||||
_ = m[k]
|
||||
mu.RUnlock()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkReadSyncMap(b *testing.B) {
|
||||
// Create a sync.Map.
|
||||
syncMap := &sync.Map{}
|
||||
|
||||
// k is the unique key for each goroutine.
|
||||
k := int64(0)
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
// Increment k.
|
||||
atomic.AddInt64(&k, 1)
|
||||
|
||||
// Read the value.
|
||||
syncMap.Load(k)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkReadLndSyncMap(b *testing.B) {
|
||||
// Create a sync.Map.
|
||||
syncMap := &lnutils.SyncMap[int64, struct{}]{}
|
||||
|
||||
// k is the unique key for each goroutine.
|
||||
k := int64(0)
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
// Increment k.
|
||||
atomic.AddInt64(&k, 1)
|
||||
|
||||
// Read the value.
|
||||
syncMap.Load(k)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkWriteMutexMap(b *testing.B) {
|
||||
// Create a map with a mutex.
|
||||
m := make(map[int64]struct{})
|
||||
|
||||
// k is the unique key for each goroutine.
|
||||
k := int64(0)
|
||||
|
||||
// Create a general mutex.
|
||||
var mu sync.Mutex
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
// Increment k.
|
||||
atomic.AddInt64(&k, 1)
|
||||
|
||||
// Perform a lock write.
|
||||
mu.Lock()
|
||||
m[k] = struct{}{}
|
||||
mu.Unlock()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkWriteRWMutexMap(b *testing.B) {
|
||||
// Create a map with a mutex.
|
||||
m := make(map[int64]struct{})
|
||||
|
||||
// k is the unique key for each goroutine.
|
||||
k := int64(0)
|
||||
|
||||
// Create a read write mutex.
|
||||
var mu sync.RWMutex
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
// Increment k.
|
||||
atomic.AddInt64(&k, 1)
|
||||
|
||||
// Perform a lock write.
|
||||
mu.Lock()
|
||||
m[k] = struct{}{}
|
||||
mu.Unlock()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkWriteSyncMap(b *testing.B) {
|
||||
// Create a sync.Map.
|
||||
syncMap := &sync.Map{}
|
||||
|
||||
// k is the unique key for each goroutine.
|
||||
k := int64(0)
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
// Increment k.
|
||||
atomic.AddInt64(&k, 1)
|
||||
|
||||
// Write the value.
|
||||
syncMap.Store(k, struct{}{})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkWriteLndSyncMap(b *testing.B) {
|
||||
// Create a sync.Map.
|
||||
syncMap := &lnutils.SyncMap[int64, struct{}]{}
|
||||
|
||||
// k is the unique key for each goroutine.
|
||||
k := int64(0)
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
// Increment k.
|
||||
atomic.AddInt64(&k, 1)
|
||||
|
||||
// Write the value.
|
||||
syncMap.Store(k, struct{}{})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkDeleteMutexMap(b *testing.B) {
|
||||
// Create a map with a mutex.
|
||||
m := make(map[int64]struct{})
|
||||
|
||||
// k is the unique key for each goroutine.
|
||||
k := int64(0)
|
||||
|
||||
// Create a general mutex.
|
||||
var mu sync.Mutex
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
// Increment k.
|
||||
atomic.AddInt64(&k, 1)
|
||||
|
||||
// Perform a lock delete.
|
||||
mu.Lock()
|
||||
delete(m, k)
|
||||
mu.Unlock()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkDeleteRWMutexMap(b *testing.B) {
|
||||
// Create a map with a mutex.
|
||||
m := make(map[int64]struct{})
|
||||
|
||||
// k is the unique key for each goroutine.
|
||||
k := int64(0)
|
||||
|
||||
// Create a read write mutex.
|
||||
var mu sync.RWMutex
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
// Increment k.
|
||||
atomic.AddInt64(&k, 1)
|
||||
|
||||
// Perform a lock delete.
|
||||
mu.Lock()
|
||||
delete(m, k)
|
||||
mu.Unlock()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkDeleteSyncMap(b *testing.B) {
|
||||
// Create a sync.Map.
|
||||
syncMap := &sync.Map{}
|
||||
|
||||
// k is the unique key for each goroutine.
|
||||
k := int64(0)
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
// Increment k.
|
||||
atomic.AddInt64(&k, 1)
|
||||
|
||||
// Delete the value.
|
||||
syncMap.Delete(k)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkDeleteLndSyncMap(b *testing.B) {
|
||||
// Create a sync.Map.
|
||||
syncMap := &lnutils.SyncMap[int64, struct{}]{}
|
||||
|
||||
// k is the unique key for each goroutine.
|
||||
k := int64(0)
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
// Increment k.
|
||||
atomic.AddInt64(&k, 1)
|
||||
|
||||
// Delete the value.
|
||||
syncMap.Delete(k)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user