package pointmatch import ( "bet24.com/log" "bet24.com/redis" _ "bet24.com/servers/common" "bet24.com/servers/micros/matches/handler/matchbase" "encoding/json" "sort" "strconv" "sync" "time" ) const max_history_sec = 86400 * 3 // 最多存储时长 const refresh_history_config_sec = 600 func getRedisKey() string { return "pointmatch:history" } type historyItem struct { matchinstance HistoryTime int64 Users []*matchbase.MatchUserBrief Eliminates []*matchbase.MatchUserBrief } func (hi *historyItem) isUserRelated(userId int) bool { if hi.Owner == userId { return true } for _, v := range hi.UserList { if v.UserId == userId { return true } } for _, v := range hi.EliminateUsers { if v.UserId == userId { return true } } return false } func (hi *historyItem) toBrief() { hi.Users = make([]*matchbase.MatchUserBrief, len(hi.UserList)) for k, v := range hi.UserList { hi.Users[k] = v.ToBrief() } hi.UserList = nil hi.Eliminates = make([]*matchbase.MatchUserBrief, len(hi.EliminateUsers)) for k, v := range hi.EliminateUsers { hi.Eliminates[k] = v.ToBrief() } hi.EliminateUsers = nil } func (h *historyItem) dump(detail bool) { log.Release(" MatchNo:%d Creator:%d GameId:%d Rule:%s TotalUser:%d TableUser:%d CurrentRound:%d Start:%s", h.MatchNo, h.Owner, h.GameId, h.GameRule, h.TotalUser, h.TableUser, h.currentRound, h.StartTime) //common.TimeStampToString(h.StartTime)) if !detail { return } for _, v := range h.Users { if v == nil { continue } log.Release(" User[%d] Score[%d]", v.UserId, v.Score) } if len(h.Eliminates) > 0 { log.Release(" -- EliminateUsers:") for _, v := range h.Eliminates { if v == nil { continue } log.Release(" User[%d] Score[%d] Rank[%d]", v.UserId, v.Score, v.Rank) } } if len(h.RoomHistory) > 0 { log.Release(" RoomHistory:") for _, v := range h.RoomHistory { v.Dump() } } } type historyMgr struct { isDirty bool lock *sync.RWMutex histories []historyItem } var historymgr *historyMgr func getHistoryManager() *historyMgr { if historymgr == nil { historymgr = new(historyMgr) } return historymgr } func (m *historyMgr) run() { log.Release("pointmatch.historymgr.run()") m.lock = &sync.RWMutex{} m.loadHistoryFromRedis() m.flush() } func (m *historyMgr) loadHistoryFromRedis() { data, ok := redis.String_Get(getRedisKey()) if data == "" || !ok { return } m.lock.Lock() err := json.Unmarshal([]byte(data), &m.histories) m.lock.Unlock() if err != nil { log.Release("pointmatch.historyMgr.loadHistoryFromRedis Unmarshal failed err:%v,%s", err, data) return } } func (m *historyMgr) addHistory(item matchinstance) { hi := historyItem{matchinstance: item.getCopy(), HistoryTime: time.Now().Unix()} go writeRoomRecordToDB(&item) hi.toBrief() m.lock.Lock() m.isDirty = true m.histories = append(m.histories, hi) m.lock.Unlock() } func (m *historyMgr) checkTimeout() { now := time.Now().Unix() removeIndex := 0 m.lock.RLock() for i := 0; i < len(m.histories); i++ { removeIndex = i if now-m.histories[i].HistoryTime < max_history_sec { break } } m.lock.RUnlock() if removeIndex == 0 { return } log.Release("pointmatch.historymgr.checkTimeout removeIndex = %d", removeIndex) m.lock.Lock() m.isDirty = true m.histories = m.histories[removeIndex:] m.lock.Unlock() } func (m *historyMgr) forceFlush() { m.isDirty = true m.doFlush() } func (m *historyMgr) flush() { time.AfterFunc(refresh_history_config_sec*time.Second, m.flush) m.checkTimeout() if !m.isDirty { return } m.doFlush() } func (m *historyMgr) doFlush() { m.lock.RLock() m.isDirty = false d, _ := json.Marshal(m.histories) m.lock.RUnlock() go redis.String_Set(getRedisKey(), string(d)) } func (m *historyMgr) dump(param string) { log.Release("-------------------------------") log.Release("pointmatch.historyMgr.dump %s", param) defer func() { log.Release("+++++++++++++++++++++++++++++++") log.Release("") }() if param == "" { m.lock.RLock() for _, v := range m.histories { v.dump(false) } m.lock.RUnlock() return } matchNo, err := strconv.Atoi(param) if err != nil { log.Release("invalid param %s", param) return } m.lock.RLock() for _, v := range m.histories { if v.MatchNo != matchNo { continue } v.dump(true) } m.lock.RUnlock() } func (m *historyMgr) getHistory(userId int) string { var ret []historyItem m.lock.RLock() for _, v := range m.histories { if v.isUserRelated(userId) { ret = append(ret, v) } } m.lock.RUnlock() sort.Slice(ret, func(i, j int) bool { return ret[i].HistoryTime > ret[j].HistoryTime }) d, _ := json.Marshal(ret) return string(d) }