Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: optimize MSet method, add MRemove method #94

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 37 additions & 3 deletions concurrent_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,24 @@ func New() ConcurrentMap {

// GetShard returns shard under given key
func (m ConcurrentMap) GetShard(key string) *ConcurrentMapShared {
return m[uint(fnv32(key))%uint(SHARD_COUNT)]
return m[hash(key)]
}

func (m ConcurrentMap) MSet(data map[string]interface{}) {
bucket := make(map[uint]map[string]interface{})
for key, value := range data {
shard := m.GetShard(key)
index := hash(key)
if _, ok := bucket[index]; !ok {
bucket[index] = make(map[string]interface{})
}
bucket[index][key] = value
}
for index, segment := range bucket {
shard := m[index]
shard.Lock()
shard.items[key] = value
for key, value := range segment {
shard.items[key] = value
}
shard.Unlock()
}
}
Expand Down Expand Up @@ -122,6 +132,26 @@ func (m ConcurrentMap) Remove(key string) {
shard.Unlock()
}

func (m ConcurrentMap) MRemove(keys []string) {
bucket := make(map[uint][]string)
for _, key := range keys {
index := hash(key)
if _, ok := bucket[index]; !ok {
bucket[index] = make([]string, 0)
}
bucket[index] = append(bucket[index], key)
}

for index, segment := range bucket {
shard := m[index]
shard.Lock()
for _, key := range segment {
delete(shard.items, key)
}
shard.Unlock()
}
}

// RemoveCb is a callback executed in a map.RemoveCb() call, while Lock is held
// If returns true, the element will be removed from the map
type RemoveCb func(key string, v interface{}, exists bool) bool
Expand Down Expand Up @@ -319,6 +349,10 @@ func fnv32(key string) uint32 {
return hash
}

func hash(key string) uint {
return uint(fnv32(key))%uint(SHARD_COUNT)
}

// Concurrent map uses Interface{} as its value, therefor JSON Unmarshal
// will probably won't know which to type to unmarshal into, in such case
// we'll end up with a value of type map[string]interface{}, In most cases this isn't
Expand Down
29 changes: 29 additions & 0 deletions concurrent_map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,35 @@ func TestRemove(t *testing.T) {
m.Remove("noone")
}

func TestMRemove(t *testing.T) {
m := New()
monkey := Animal{"monkey"}
m.Set("monkey", monkey)
elephant := Animal{"elephant"}
m.Set("elephant", elephant)

keys := []string{"monkey", "elephant"}
m.MRemove(keys)

if m.Count() != 0 {
t.Error("Expecting count to be zero once multi items were removed.")
}

temp, ok := m.Get("monkey")

if ok != false {
t.Error("Expecting ok to be false for missing items after multi items were removed..")
}

if temp != nil {
t.Error("Expecting item to be nil after multi items were removed.")
}

// Remove a none existing element.
m.Remove("noone")
}


func TestRemoveCb(t *testing.T) {
m := New()

Expand Down