Skip to content

Commit

Permalink
use slice to replace map
Browse files Browse the repository at this point in the history
  • Loading branch information
lixizan committed Feb 27, 2023
1 parent 1afb5ba commit 3024097
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 49 deletions.
5 changes: 1 addition & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
test:
go test -count 1 -timeout 30s -run ^Test ./...
go test -timeout 30s -run ^Test ./...

bench:
go test -benchmem -bench ^Benchmark github.com/lxzan/gws

build:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bin/gws-linux-amd64 github.com/lxzan/gws/examples/testsuite

run-testsuite-server:
go run github.com/lxzan/gws/examples/testsuite

cover:
go test -coverprofile=./bin/cover.out --cover ./...
104 changes: 66 additions & 38 deletions session_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,59 +8,87 @@ import (
// SessionStorage because sync.Map is not easy to debug, so I implemented my own map.
// if you don't like it, use sync.Map instead.
type SessionStorage interface {
Load(key interface{}) (value interface{}, exist bool)
Delete(key interface{})
Store(key interface{}, value interface{})
Range(f func(key, value interface{}) bool)
Load(key string) (value interface{}, exist bool)
Delete(key string)
Store(key string, value interface{})
Range(f func(key string, value interface{}) bool)
}

func NewMap() *Map {
return &Map{mu: sync.RWMutex{}, d: make(map[interface{}]interface{})}
}
type (
sliceMap struct {
sync.RWMutex
data []kv
}

type Map struct {
mu sync.RWMutex
d map[interface{}]interface{}
}
kv struct {
deleted bool
key string
value interface{}
}
)

func (c *Map) Len() int {
c.mu.RLock()
n := len(c.d)
c.mu.RUnlock()
func (c *sliceMap) Len() int {
c.RLock()
defer c.RUnlock()
var n = len(c.data)
for _, v := range c.data {
if v.deleted {
n--
}
}
return n
}

func (c *Map) Load(key interface{}) (value interface{}, exist bool) {
c.mu.RLock()
value, exist = c.d[key]
c.mu.RUnlock()
return
func (c *sliceMap) Load(key string) (value interface{}, exist bool) {
c.RLock()
defer c.RUnlock()
for _, v := range c.data {
if v.key == key && !v.deleted {
return v.value, true
}
}
return nil, false
}

// Delete deletes the value for a key.
func (c *Map) Delete(key interface{}) {
c.mu.Lock()
delete(c.d, key)
c.mu.Unlock()
func (c *sliceMap) Delete(key string) {
c.Lock()
defer c.Unlock()
for i, v := range c.data {
if v.key == key {
c.data[i].deleted = true
}
}
}

// Store sets the value for a key.
func (c *Map) Store(key interface{}, value interface{}) {
c.mu.Lock()
c.d[key] = value
c.mu.Unlock()
func (c *sliceMap) Store(key string, value interface{}) {
c.Lock()
defer c.Unlock()

for i, v := range c.data {
if v.key == key && !v.deleted {
c.data[i].value = value
return
}
}

c.data = append(c.data, kv{
deleted: false,
key: key,
value: value,
})
}

// Range calls f sequentially for each key and value present in the map.
// If f returns false, range stops the iteration.
func (c *Map) Range(f func(key, value interface{}) bool) {
c.mu.RLock()
for k, v := range c.d {
if ok := f(k, v); !ok {
break
func (c *sliceMap) Range(f func(key string, value interface{}) bool) {
c.Lock()
defer c.Unlock()

for _, v := range c.data {
if !v.deleted {
if !f(v.key, v.value) {
return
}
}
}
c.mu.RUnlock()
}

/*
Expand Down
12 changes: 6 additions & 6 deletions session_storage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import (

func TestMap(t *testing.T) {
var as = assert.New(t)
var m1 = make(map[interface{}]interface{})
var m2 = NewMap()
var m1 = make(map[string]interface{})
var m2 = &sliceMap{}
var count = internal.AlphabetNumeric.Intn(1000)
for i := 0; i < count; i++ {
var key = string(internal.AlphabetNumeric.Generate(10))
Expand All @@ -18,7 +18,7 @@ func TestMap(t *testing.T) {
m2.Store(key, val)
}

var keys = make([]interface{}, 0)
var keys = make([]string, 0)
for k, _ := range m1 {
keys = append(keys, k)
}
Expand All @@ -38,7 +38,7 @@ func TestMap(t *testing.T) {
func TestMap_Range(t *testing.T) {
var as = assert.New(t)
var m1 = make(map[interface{}]interface{})
var m2 = NewMap()
var m2 = &sliceMap{}
var count = 1000
for i := 0; i < count; i++ {
var key = string(internal.AlphabetNumeric.Generate(10))
Expand All @@ -49,7 +49,7 @@ func TestMap_Range(t *testing.T) {

{
var keys []interface{}
m2.Range(func(key interface{}, value interface{}) bool {
m2.Range(func(key string, value interface{}) bool {
v, ok := m1[key]
as.Equal(true, ok)
as.Equal(v, value)
Expand All @@ -61,7 +61,7 @@ func TestMap_Range(t *testing.T) {

{
var keys []interface{}
m2.Range(func(key interface{}, value interface{}) bool {
m2.Range(func(key string, value interface{}) bool {
v, ok := m1[key]
as.Equal(true, ok)
as.Equal(v, value)
Expand Down
2 changes: 1 addition & 1 deletion updrader.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ func (c *Upgrader) Accept(w http.ResponseWriter, r *http.Request) (*Conn, error)
}

func (c *Upgrader) doAccept(w http.ResponseWriter, r *http.Request) (*Conn, error) {
var request = &Request{Request: r, SessionStorage: NewMap()}
var request = &Request{Request: r, SessionStorage: &sliceMap{}}
var header = internal.CloneHeader(c.ResponseHeader)
if !c.CheckOrigin(request) {
return nil, internal.ErrCheckOrigin
Expand Down

0 comments on commit 3024097

Please sign in to comment.