Skip to content

Commit

Permalink
Modifying ConcurrentMap Generalized Constraints
Browse files Browse the repository at this point in the history
  • Loading branch information
lxzan committed Dec 13, 2023
1 parent 5318d69 commit d1a5d3b
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 53 deletions.
2 changes: 2 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ linters:
- gocognit
- ifshort
- gochecknoinits
- goconst
- depguard
# Enable presets.
# https://golangci-lint.run/usage/linters
# Run only fast linters from enabled linters set (first run won't be fast)
Expand Down
25 changes: 25 additions & 0 deletions benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,28 @@ func BenchmarkMask(b *testing.B) {
internal.MaskXOR(s2, key[:4])
}
}

func BenchmarkConcurrentMap_ReadWrite(b *testing.B) {
const count = 1000000
var cm = NewConcurrentMap[string, uint8](64)
var keys = make([]string, 0, count)
for i := 0; i < count; i++ {
key := string(internal.AlphabetNumeric.Generate(16))
keys = append(keys, key)
cm.Store(key, 1)
}

b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
var i = 0
for pb.Next() {
i++
var key = keys[i%count]
if i&15 == 0 {
cm.Store(key, 1)
} else {
cm.Load(key)
}
}
})
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/lxzan/gws
go 1.18

require (
github.com/dolthub/maphash v0.1.0
github.com/klauspost/compress v1.16.5
github.com/stretchr/testify v1.8.1
)
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dolthub/maphash v0.1.0 h1:bsQ7JsF4FkkWyrP3oCnFJgrCUAFbFf3kOl4L/QxPDyQ=
github.com/dolthub/maphash v0.1.0/go.mod h1:gkg4Ch4CdCDu5h6PMriVLawB7koZ+5ijb9puGMV50a4=
github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=
github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand Down
49 changes: 15 additions & 34 deletions session_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package gws
import (
"sync"

"github.com/dolthub/maphash"
"github.com/lxzan/gws/internal"
)

Expand Down Expand Up @@ -57,55 +58,35 @@ func (c *smap) Range(f func(key string, value any) bool) {
}

type (
Comparable interface {
~string | ~int | ~int64 | ~int32 | ~uint | ~uint64 | ~uint32
}

ConcurrentMap[K Comparable, V any] struct {
segments uint64
ConcurrentMap[K comparable, V any] struct {
hasher maphash.Hasher[K]
sharding uint64
buckets []*bucket[K, V]
}

bucket[K Comparable, V any] struct {
bucket[K comparable, V any] struct {
sync.Mutex
m map[K]V
}
)

func NewConcurrentMap[K Comparable, V any](segments uint64) *ConcurrentMap[K, V] {
segments = internal.SelectValue(segments == 0, 16, segments)
segments = internal.ToBinaryNumber(segments)
var cm = &ConcurrentMap[K, V]{segments: segments, buckets: make([]*bucket[K, V], segments)}
func NewConcurrentMap[K comparable, V any](sharding uint64) *ConcurrentMap[K, V] {
sharding = internal.SelectValue(sharding == 0, 16, sharding)
sharding = internal.ToBinaryNumber(sharding)
var cm = &ConcurrentMap[K, V]{
hasher: maphash.NewHasher[K](),
sharding: sharding,
buckets: make([]*bucket[K, V], sharding),
}
for i, _ := range cm.buckets {
cm.buckets[i] = &bucket[K, V]{m: make(map[K]V)}
}
return cm
}

func (c *ConcurrentMap[K, V]) hash(key any) uint64 {
switch k := key.(type) {
case string:
return internal.FnvString(k)
case int:
return internal.FnvNumber(k)
case int64:
return internal.FnvNumber(k)
case int32:
return internal.FnvNumber(k)
case uint:
return internal.FnvNumber(k)
case uint64:
return internal.FnvNumber(k)
case uint32:
return internal.FnvNumber(k)
default:
return 0
}
}

func (c *ConcurrentMap[K, V]) getBucket(key K) *bucket[K, V] {
var hashCode = c.hash(key)
var index = hashCode & (c.segments - 1)
var hashCode = c.hasher.Hash(key)
var index = hashCode & (c.sharding - 1)
return c.buckets[index]
}

Expand Down
28 changes: 9 additions & 19 deletions session_storage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package gws
import (
"testing"

"github.com/dolthub/maphash"

"github.com/lxzan/gws/internal"
"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -162,23 +164,11 @@ func TestConcurrentMap_Range(t *testing.T) {
}

func TestHash(t *testing.T) {
m := NewConcurrentMap[string, uint32](8)
m.hash("1")

m.hash(int(1))
m.hash(int64(1))
m.hash(int32(1))
m.hash(int16(1))
m.hash(int8(1))

m.hash(uint(1))
m.hash(uint64(1))
m.hash(uint32(1))
m.hash(uint16(1))
m.hash(uint8(1))

assert.Equal(t, uint64(0), m.hash(map[string]string{}))

m = NewConcurrentMap[string, uint32](0)
assert.Equal(t, uint64(16), m.segments)
var h = maphash.NewHasher[string]()
for i := 0; i < 1000; i++ {
var a = string(internal.AlphabetNumeric.Generate(16))
var b = string(internal.AlphabetNumeric.Generate(16))
assert.Equal(t, h.Hash(a), h.Hash(a))
assert.NotEqual(t, h.Hash(a), h.Hash(b))
}
}

0 comments on commit d1a5d3b

Please sign in to comment.