//ref https://github.com/DeanThompson/syncmap/blob/master/syncmap.go
|
|
package shardmap
|
|
import (
|
"basic.com/pubsub/protomsg.git"
|
"sync"
|
//"encoding/json"
|
//"fmt"
|
"time"
|
)
|
|
// 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
|
lasttime time.Time
|
}
|
|
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),
|
lasttime: time.Now(),
|
}
|
|
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) Gettime() time.Time {
|
tm := s.lasttime
|
return tm
|
}
|
|
func (s *ShardMap) Settime() {
|
s.lasttime = time.Now()
|
}
|
|
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{}
|
}
|
|
func (s *ShardMap) Walk(wf wfOp, sourceFea []byte, baseScore float32, isWebComp bool, target string) (targets []*protomsg.SdkCompareEach) {
|
var wg sync.WaitGroup
|
var lock sync.Mutex
|
for _, si := range s.shards {
|
var tempsi shardItem = *si
|
|
if len(tempsi.data) == 0 {
|
continue
|
}
|
|
wg.Add(1)
|
|
go func(st *shardItem, fw wfOp, sf []byte, baseSec float32, isWeb bool) {
|
defer wg.Done()
|
for _, feature := range st.data {
|
if eif, ok := feature.(*protomsg.Esinfo); ok {
|
if !isWeb { //不会比对抓拍库,只比对有效的人
|
if eif.Enable == 1 {
|
score := float32(0)
|
if target == "car" {
|
if eif.CarNo != "" {
|
score = strComp(sf, eif.CarNo)
|
} else {
|
continue
|
}
|
} else {
|
score = fw(sf, eif.FaceFeature)
|
}
|
if score > 0 && score >= baseScore {
|
lock.Lock()
|
targets = append(targets, &protomsg.SdkCompareEach{
|
Id: eif.Id,
|
CompareScore: score,
|
Tableid: eif.Tableid,
|
})
|
lock.Unlock()
|
}
|
}
|
} else { //来源是web,会比对抓拍库,不管是否有效都需要比对
|
score := float32(0)
|
if target == "car" {
|
if eif.CarNo != "" {
|
score = strComp(sf, eif.CarNo)
|
} else {
|
continue
|
}
|
} else {
|
score = fw(sf, eif.FaceFeature)
|
}
|
if score > 0 && score >= baseScore {
|
lock.Lock()
|
targets = append(targets, &protomsg.SdkCompareEach{
|
Id: eif.Id,
|
CompareScore: score,
|
Tableid: eif.Tableid,
|
})
|
lock.Unlock()
|
}
|
}
|
}
|
}
|
|
}(&tempsi, wf, sourceFea, baseScore, isWebComp)
|
}
|
|
wg.Wait()
|
return targets
|
|
}
|
|
// 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
|
}
|
|
func strComp(source []byte, target string) float32 {
|
sourceStr := string(source)
|
if sourceStr == target {
|
return 100
|
} else {
|
return 0
|
}
|
}
|