//ref https://github.com/DeanThompson/syncmap/blob/master/syncmap.go
|
|
package shardmap
|
|
import (
|
"sync"
|
"encoding/json"
|
"fmt"
|
)
|
|
var commonmux sync.Mutex
|
const (
|
|
BKDR_SEED = 131 // 31 131 1313 13131 131313 etc...
|
)
|
|
type shardItem struct {
|
sync.RWMutex
|
data map[string]interface{}
|
}
|
|
type ShardMap struct {
|
shardCnt uint8
|
shards []*shardItem
|
}
|
|
var Count = make(chan int)
|
|
type wfOp func(a []byte, b string) float32
|
|
/**
|
* @param uint8, shardCnt must be pow of two
|
*/
|
func New(shardCnt uint8) *ShardMap {
|
|
s := &ShardMap{
|
shardCnt: shardCnt,
|
shards: make([]*shardItem, shardCnt),
|
}
|
|
for i, _ := range s.shards {
|
s.shards[i] = &shardItem{
|
data: make(map[string]interface{}),
|
}
|
}
|
|
return s
|
}
|
|
func (s *ShardMap) Get(key string) (interface{}, bool) {
|
si := s.locate(key)
|
|
si.RLock()
|
value, ok := si.data[key]
|
si.RUnlock()
|
return value, ok
|
}
|
|
func (s *ShardMap) Set(key string, value interface{}) {
|
si := s.locate(key)
|
|
si.Lock()
|
si.data[key] = value
|
si.Unlock()
|
}
|
|
func (s *ShardMap) Del(key string) {
|
si := s.locate(key)
|
|
si.Lock()
|
delete(si.data, key)
|
si.Unlock()
|
}
|
|
type kvItem struct {
|
key string
|
value interface{}
|
}
|
|
// modify by long.
|
func (s *ShardMap) Walk(wf wfOp, cfrom []byte) ([]byte){
|
var wg sync.WaitGroup
|
var second float32
|
var buf []byte
|
var err error
|
|
ids := make(map[string]float32)
|
for _, si := range s.shards {
|
var tempsi shardItem
|
tempsi = *si
|
|
|
wg.Add(1)
|
|
go func(st *shardItem, fw wfOp, cf []byte) {
|
defer wg.Done()
|
commonmux.Lock()
|
for id, feature := range st.data {
|
if str, ok := feature.(string); ok {
|
second = fw(cf,str)
|
if second == -1 {
|
continue
|
}
|
ids[id]=second
|
}
|
}
|
commonmux.Unlock()
|
}(&tempsi, wf, cfrom)
|
}
|
|
wg.Wait()
|
|
buf, err = json.Marshal(ids)
|
if err != nil {
|
fmt.Println("compare json err")
|
buf = nil
|
|
}
|
return buf
|
}
|
|
// print all
|
func (s *ShardMap) Printall() (infos []interface{}){
|
var wg sync.WaitGroup
|
|
for _, si := range s.shards {
|
wg.Add(1)
|
go func(s *shardItem) {
|
defer wg.Done()
|
s.RLock()
|
for _, value := range s.data {
|
infos = append(infos, value)
|
}
|
|
s.RUnlock()
|
}(si)
|
}
|
wg.Wait()
|
return
|
}
|
|
func (s * ShardMap)GetLen() int {
|
var slen int
|
for i:= 0 ; i<int(s.shardCnt); i++{
|
slen += len(s.shards[i].data)
|
}
|
return slen
|
}
|
|
func (s *ShardMap) locate(key string) *shardItem {
|
i := bkdrHash(key) & uint32(s.shardCnt-1)
|
|
return s.shards[i]
|
}
|
|
//https://www.byvoid.com/blog/string-hash-compare/
|
func bkdrHash(str string) uint32 {
|
var h uint32
|
|
for _, c := range str {
|
h = h*BKDR_SEED + uint32(c)
|
}
|
|
return h
|
}
|