package cache import ( "encoding/json" "errors" "os" "time" . "code.hoteas.com/golang/hotime/common" ) const debugLogPath = `d:\work\hotimev1.5\.cursor\debug.log` // debugLog 写入调试日志 func debugLog(hypothesisId, location, message string, data map[string]interface{}) { // #region agent log logFile, _ := os.OpenFile(debugLogPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if logFile != nil { logEntry, _ := json.Marshal(map[string]interface{}{ "sessionId": "cache-debug", "runId": "test-run", "hypothesisId": hypothesisId, "location": location, "message": message, "data": data, "timestamp": time.Now().UnixMilli(), }) logFile.Write(append(logEntry, '\n')) logFile.Close() } // #endregion } // HoTimeCache 可配置memory,db,redis,默认启用memory,默认优先级为memory>redis>db,memory与数据库缓存设置项一致, // 缓存数据填充会自动反方向反哺,加入memory缓存过期将自动从redis更新,但memory永远不会更新redis,如果是集群建议不要开启memory,配置即启用 type HoTimeCache struct { *Error dbCache *CacheDb redisCache *CacheRedis memoryCache *CacheMemory Config Map } func (that *HoTimeCache) Session(key string, data ...interface{}) *Obj { var reData *Obj if len(data) == 0 { //内存缓存有 if that.memoryCache != nil && that.memoryCache.SessionSet { reData = that.memoryCache.Cache(key, data...) if reData.Data != nil { return reData } } //redis缓存有 if that.redisCache != nil && that.redisCache.SessionSet { reData = that.redisCache.Cache(key, data...) if reData.Data != nil { if that.memoryCache != nil && that.memoryCache.SessionSet { that.memoryCache.Cache(key, reData.Data) } return reData } } //db缓存有 if that.dbCache != nil && that.dbCache.SessionSet { reData = that.dbCache.Cache(key, data...) if reData.Data != nil { if that.memoryCache != nil && that.memoryCache.SessionSet { that.memoryCache.Cache(key, reData.Data) } if that.redisCache != nil && that.redisCache.SessionSet { that.redisCache.Cache(key, reData.Data) } return reData } } return reData } //设置缓存 //设置内存缓存 if that.memoryCache != nil && that.memoryCache.SessionSet { reData = that.memoryCache.Cache(key, data...) } //redis缓存有 if that.redisCache != nil && that.redisCache.SessionSet { reData = that.redisCache.Cache(key, data...) } //redis缓存有 if that.dbCache != nil && that.dbCache.SessionSet { reData = that.dbCache.Cache(key, data...) } return reData } func (that *HoTimeCache) Db(key string, data ...interface{}) *Obj { var reData *Obj if len(data) == 0 { //内存缓存有 if that.memoryCache != nil && that.memoryCache.DbSet { reData = that.memoryCache.Cache(key, data...) if reData.Data != nil { return reData } } //redis缓存有 if that.redisCache != nil && that.redisCache.DbSet { reData = that.redisCache.Cache(key, data...) if reData.Data != nil { if that.memoryCache != nil && that.memoryCache.DbSet { that.memoryCache.Cache(key, reData.Data) } return reData } } //db缓存有 if that.dbCache != nil && that.dbCache.DbSet { reData = that.dbCache.Cache(key, data...) if reData.Data != nil { if that.memoryCache != nil && that.memoryCache.DbSet { that.memoryCache.Cache(key, reData.Data) } if that.redisCache != nil && that.redisCache.DbSet { that.redisCache.Cache(key, reData.Data) } return reData } } return reData } //设置缓存 //设置内存缓存 if that.memoryCache != nil && that.memoryCache.DbSet { reData = that.memoryCache.Cache(key, data...) } //redis缓存有 if that.redisCache != nil && that.redisCache.DbSet { reData = that.redisCache.Cache(key, data...) } //db缓存有 if that.dbCache != nil && that.dbCache.DbSet { reData = that.dbCache.Cache(key, data...) } return reData } func (that *HoTimeCache) Cache(key string, data ...interface{}) *Obj { var reData *Obj if len(data) == 0 { //内存缓存有 if that.memoryCache != nil { reData = that.memoryCache.Cache(key, data...) if reData != nil && reData.Data != nil { return reData } } //redis缓存有 if that.redisCache != nil { reData = that.redisCache.Cache(key, data...) if reData != nil && reData.Data != nil { if that.memoryCache != nil { that.memoryCache.Cache(key, reData.Data) } return reData } } //db缓存有 if that.dbCache != nil { reData = that.dbCache.Cache(key, data...) if reData != nil && reData.Data != nil { if that.memoryCache != nil { that.memoryCache.Cache(key, reData.Data) } if that.redisCache != nil { that.redisCache.Cache(key, reData.Data) } return reData } } return reData } //设置缓存 //设置内存缓存 if that.memoryCache != nil { reData = that.memoryCache.Cache(key, data...) } //redis缓存有 if that.redisCache != nil { reData = that.redisCache.Cache(key, data...) } //db缓存有 if that.dbCache != nil { reData = that.dbCache.Cache(key, data...) } return reData } // SessionsGet 批量获取 Session 缓存 // 返回 Map,key 为缓存键,value 为缓存值 // 优先级:memory > redis > db,低优先级数据会反哺到高优先级缓存 func (that *HoTimeCache) SessionsGet(keys []string) Map { if len(keys) == 0 { return Map{} } // #region agent log debugLog("D", "cache.go:SessionsGet:start", "SessionsGet开始", map[string]interface{}{ "keys_count": len(keys), "has_memory": that.memoryCache != nil, "has_redis": that.redisCache != nil, "has_db": that.dbCache != nil, }) // #endregion result := make(Map, len(keys)) missingKeys := keys // 从 memory 获取 if that.memoryCache != nil && that.memoryCache.SessionSet { memResult := that.memoryCache.CachesGet(keys) // #region agent log debugLog("D", "cache.go:SessionsGet:memory", "从Memory获取", map[string]interface{}{ "found_count": len(memResult), }) // #endregion for k, v := range memResult { result[k] = v } // 计算未命中的 keys missingKeys = make([]string, 0) for _, k := range keys { if _, exists := result[k]; !exists { missingKeys = append(missingKeys, k) } } } // 从 redis 获取未命中的 if len(missingKeys) > 0 && that.redisCache != nil && that.redisCache.SessionSet { redisResult := that.redisCache.CachesGet(missingKeys) // #region agent log debugLog("D", "cache.go:SessionsGet:redis", "从Redis获取", map[string]interface{}{ "missing_count": len(missingKeys), "found_count": len(redisResult), }) // #endregion // 反哺到 memory if that.memoryCache != nil && that.memoryCache.SessionSet && len(redisResult) > 0 { that.memoryCache.CachesSet(redisResult) // #region agent log debugLog("D", "cache.go:SessionsGet:backfill_redis_to_mem", "Redis数据反哺到Memory", map[string]interface{}{ "backfill_count": len(redisResult), }) // #endregion } for k, v := range redisResult { result[k] = v } // 更新未命中的 keys newMissing := make([]string, 0) for _, k := range missingKeys { if _, exists := result[k]; !exists { newMissing = append(newMissing, k) } } missingKeys = newMissing } // 从 db 获取未命中的 if len(missingKeys) > 0 && that.dbCache != nil && that.dbCache.SessionSet { dbResult := that.dbCache.CachesGet(missingKeys) // #region agent log debugLog("D", "cache.go:SessionsGet:db", "从DB获取", map[string]interface{}{ "missing_count": len(missingKeys), "found_count": len(dbResult), }) // #endregion // 反哺到 memory 和 redis if len(dbResult) > 0 { if that.memoryCache != nil && that.memoryCache.SessionSet { that.memoryCache.CachesSet(dbResult) // #region agent log debugLog("D", "cache.go:SessionsGet:backfill_db_to_mem", "DB数据反哺到Memory", map[string]interface{}{ "backfill_count": len(dbResult), }) // #endregion } if that.redisCache != nil && that.redisCache.SessionSet { that.redisCache.CachesSet(dbResult) // #region agent log debugLog("D", "cache.go:SessionsGet:backfill_db_to_redis", "DB数据反哺到Redis", map[string]interface{}{ "backfill_count": len(dbResult), }) // #endregion } } for k, v := range dbResult { result[k] = v } } // #region agent log debugLog("D", "cache.go:SessionsGet:end", "SessionsGet完成", map[string]interface{}{ "total_found": len(result), }) // #endregion return result } // SessionsSet 批量设置 Session 缓存 // data: Map,key 为缓存键,value 为缓存值 func (that *HoTimeCache) SessionsSet(data Map) { if len(data) == 0 { return } // #region agent log debugLog("A", "cache.go:SessionsSet:start", "SessionsSet开始", map[string]interface{}{ "data_count": len(data), "has_memory": that.memoryCache != nil, "has_redis": that.redisCache != nil, "has_db": that.dbCache != nil, }) // #endregion if that.memoryCache != nil && that.memoryCache.SessionSet { that.memoryCache.CachesSet(data) // #region agent log debugLog("A", "cache.go:SessionsSet:memory", "写入Memory完成", map[string]interface{}{"count": len(data)}) // #endregion } if that.redisCache != nil && that.redisCache.SessionSet { that.redisCache.CachesSet(data) // #region agent log debugLog("A", "cache.go:SessionsSet:redis", "写入Redis完成", map[string]interface{}{"count": len(data)}) // #endregion } if that.dbCache != nil && that.dbCache.SessionSet { that.dbCache.CachesSet(data) // #region agent log debugLog("A", "cache.go:SessionsSet:db", "写入DB完成", map[string]interface{}{"count": len(data)}) // #endregion } // #region agent log debugLog("A", "cache.go:SessionsSet:end", "SessionsSet完成", nil) // #endregion } // SessionsDelete 批量删除 Session 缓存 func (that *HoTimeCache) SessionsDelete(keys []string) { if len(keys) == 0 { return } // #region agent log debugLog("C", "cache.go:SessionsDelete:start", "SessionsDelete开始", map[string]interface{}{ "keys_count": len(keys), "has_memory": that.memoryCache != nil, "has_redis": that.redisCache != nil, "has_db": that.dbCache != nil, }) // #endregion if that.memoryCache != nil && that.memoryCache.SessionSet { that.memoryCache.CachesDelete(keys) // #region agent log debugLog("C", "cache.go:SessionsDelete:memory", "从Memory删除完成", map[string]interface{}{"count": len(keys)}) // #endregion } if that.redisCache != nil && that.redisCache.SessionSet { that.redisCache.CachesDelete(keys) // #region agent log debugLog("C", "cache.go:SessionsDelete:redis", "从Redis删除完成", map[string]interface{}{"count": len(keys)}) // #endregion } if that.dbCache != nil && that.dbCache.SessionSet { that.dbCache.CachesDelete(keys) // #region agent log debugLog("C", "cache.go:SessionsDelete:db", "从DB删除完成", map[string]interface{}{"count": len(keys)}) // #endregion } // #region agent log debugLog("C", "cache.go:SessionsDelete:end", "SessionsDelete完成", nil) // #endregion } // CachesGet 批量获取普通缓存 // 返回 Map,key 为缓存键,value 为缓存值 // 优先级:memory > redis > db,低优先级数据会反哺到高优先级缓存 func (that *HoTimeCache) CachesGet(keys []string) Map { if len(keys) == 0 { return Map{} } result := make(Map, len(keys)) missingKeys := keys // 从 memory 获取 if that.memoryCache != nil { memResult := that.memoryCache.CachesGet(keys) for k, v := range memResult { result[k] = v } // 计算未命中的 keys missingKeys = make([]string, 0) for _, k := range keys { if _, exists := result[k]; !exists { missingKeys = append(missingKeys, k) } } } // 从 redis 获取未命中的 if len(missingKeys) > 0 && that.redisCache != nil { redisResult := that.redisCache.CachesGet(missingKeys) // 反哺到 memory if that.memoryCache != nil && len(redisResult) > 0 { that.memoryCache.CachesSet(redisResult) } for k, v := range redisResult { result[k] = v } // 更新未命中的 keys newMissing := make([]string, 0) for _, k := range missingKeys { if _, exists := result[k]; !exists { newMissing = append(newMissing, k) } } missingKeys = newMissing } // 从 db 获取未命中的 if len(missingKeys) > 0 && that.dbCache != nil { dbResult := that.dbCache.CachesGet(missingKeys) // 反哺到 memory 和 redis if len(dbResult) > 0 { if that.memoryCache != nil { that.memoryCache.CachesSet(dbResult) } if that.redisCache != nil { that.redisCache.CachesSet(dbResult) } } for k, v := range dbResult { result[k] = v } } return result } // CachesSet 批量设置普通缓存 // data: Map,key 为缓存键,value 为缓存值 func (that *HoTimeCache) CachesSet(data Map) { if len(data) == 0 { return } if that.memoryCache != nil { that.memoryCache.CachesSet(data) } if that.redisCache != nil { that.redisCache.CachesSet(data) } if that.dbCache != nil { that.dbCache.CachesSet(data) } } // CachesDelete 批量删除普通缓存 func (that *HoTimeCache) CachesDelete(keys []string) { if len(keys) == 0 { return } if that.memoryCache != nil { that.memoryCache.CachesDelete(keys) } if that.redisCache != nil { that.redisCache.CachesDelete(keys) } if that.dbCache != nil { that.dbCache.CachesDelete(keys) } } func (that *HoTimeCache) Init(config Map, hotimeDb HoTimeDBInterface, err ...*Error) { //防止空数据问题 if config == nil { config = Map{} } if err[0] != nil { that.Error = err[0] } that.Config = config //memory配置初始化 memory := that.Config.GetMap("memory") if memory == nil { memory = Map{ "db": true, "session": true, "sort": 0, "timeout": 60 * 60 * 2, } } if memory.Get("db") == nil { memory["db"] = true } if memory.Get("session") == nil { memory["session"] = true } if memory.Get("timeout") == nil { memory["timeout"] = 60 * 60 * 2 } that.Config["memory"] = memory that.memoryCache = &CacheMemory{TimeOut: memory.GetCeilInt64("timeout"), DbSet: memory.GetBool("db"), SessionSet: memory.GetBool("session")} if err[0] != nil { that.memoryCache.SetError(err[0]) } //db配置初始化 redis := that.Config.GetMap("redis") if redis != nil { if redis.GetString("host") == "" || redis.GetString("port") == "" { if err[0] != nil { err[0].SetError(errors.New("请检查redis配置host和port配置")) } return } if redis.Get("db") == nil { redis["db"] = true } if redis.Get("session") == nil { redis["session"] = true } if redis.Get("timeout") == nil { redis["timeout"] = 60 * 60 * 24 * 15 } that.Config["redis"] = redis that.redisCache = &CacheRedis{TimeOut: redis.GetCeilInt64("timeout"), DbSet: redis.GetBool("db"), SessionSet: redis.GetBool("session"), Host: redis.GetString("host"), Pwd: redis.GetString("password"), Port: redis.GetCeilInt64("port")} if err[0] != nil { that.redisCache.SetError(err[0]) } } //db配置初始化 db := that.Config.GetMap("db") if db != nil { if db.Get("db") == nil { db["db"] = false } if db.Get("session") == nil { db["session"] = true } if db.Get("timeout") == nil { db["timeout"] = 60 * 60 * 24 * 30 } // mode 默认为 "compatible"(兼容模式,便于老系统平滑升级) if db.Get("mode") == nil { db["mode"] = CacheModeCompatible } that.Config["db"] = db that.dbCache = &CacheDb{ TimeOut: db.GetCeilInt64("timeout"), DbSet: db.GetBool("db"), SessionSet: db.GetBool("session"), HistorySet: db.GetBool("history"), Mode: db.GetString("mode"), Db: hotimeDb, } if err[0] != nil { that.dbCache.SetError(err[0]) } } }