package combomatch import ( "bet24.com/log" "bet24.com/redis" "encoding/json" "strconv" "sync" "time" ) var freeCountMgr *userfreecount func getFreeCountManager() *userfreecount { if freeCountMgr == nil { freeCountMgr = new(userfreecount) } return freeCountMgr } type freeInfo struct { MatchId int FreeCount int } type userfreecount struct { lock *sync.RWMutex userFreeInfo map[int][]freeInfo isDirty bool lastCheckDay int } const refresh_usercount_config_sec = 600 func (m *userfreecount) run() { log.Release("combomatch.userfreecount.run()") m.lock = &sync.RWMutex{} m.userFreeInfo = make(map[int][]freeInfo) m.loadFromRedis() m.lastCheckDay = time.Now().Day() m.flush() } func getUserFreeCountRedisKey() string { return "combomatch:userfreecount" } func (m *userfreecount) loadFromRedis() { data, ok := redis.String_Get(getUserFreeCountRedisKey()) if data == "" || !ok { return } m.lock.Lock() err := json.Unmarshal([]byte(data), &m.userFreeInfo) m.lock.Unlock() if err != nil { log.Release("userfreecount.loadFromRedis Unmarshal failed err:%v,%s", err, data) return } } func (m *userfreecount) doFlush() { m.isDirty = true m.flush() } func (m *userfreecount) flush() { time.AfterFunc(refresh_usercount_config_sec*time.Second, m.flush) m.lock.RLock() if !m.isDirty { m.lock.RUnlock() return } m.isDirty = false d, _ := json.Marshal(m.userFreeInfo) m.lock.RUnlock() go redis.String_Set(getUserFreeCountRedisKey(), string(d)) } func (m *userfreecount) dump(userIdStr string) { log.Release("-------------------------------") log.Release("userfreecount.dumpUser[%s]", userIdStr) defer func() { log.Release("+++++++++++++++++++++++++++++++") log.Release("") }() userId, err := strconv.Atoi(userIdStr) if err != nil { log.Release(" atoi error %v", err) return } fi := m.getUserFreeInfo(userId) if len(fi) == 0 { log.Release(" user has no free count") return } for _, v := range fi { log.Release(" MatchId[%d],Count[%d]", v.MatchId, v.FreeCount) } } func (m *userfreecount) addFreeCount(userId int, matchId int) { m.checkDayRefresh() fi := m.getUserFreeInfo(userId) added := false for i := 0; i < len(fi); i++ { if fi[i].MatchId == matchId { fi[i].FreeCount++ added = true break } } // 之前没有 if !added { fi = append(fi, freeInfo{MatchId: matchId, FreeCount: 1}) } m.lock.Lock() m.userFreeInfo[userId] = fi m.lock.Unlock() m.isDirty = true return } func (m *userfreecount) reduceFreeCount(userId int, matchId int) { m.checkDayRefresh() fi := m.getUserFreeInfo(userId) for i := 0; i < len(fi); i++ { if fi[i].MatchId == matchId { fi[i].FreeCount-- if fi[i].FreeCount < 0 { fi[i].FreeCount = 0 } break } } m.lock.Lock() m.userFreeInfo[userId] = fi m.lock.Unlock() m.isDirty = true return } func (m *userfreecount) checkDayRefresh() { nowDay := time.Now().Day() if nowDay == m.lastCheckDay { return } m.lastCheckDay = nowDay // 清理数据 m.lock.Lock() m.userFreeInfo = make(map[int][]freeInfo) m.lock.Unlock() m.isDirty = true } func (m *userfreecount) getUserFreeInfo(userId int) []freeInfo { m.lock.RLock() defer m.lock.RUnlock() ret, ok := m.userFreeInfo[userId] if !ok { return []freeInfo{} } return ret } func (m *userfreecount) getUserFreeCount(userId, matchId int) int { fi := m.getUserFreeInfo(userId) for _, v := range fi { if v.MatchId == matchId { return v.FreeCount } } return 0 }