hotime/session.go
hoteas 3d83c41905 feat(cache): 增加批量操作支持以提升性能
- 在 HoTimeCache 中新增 SessionsGet、SessionsSet 和 SessionsDelete 方法,支持批量获取、设置和删除 Session 缓存
- 优化缓存逻辑,减少数据库写入次数,提升性能
- 更新文档,详细说明批量操作的使用方法和性能对比
- 添加调试日志记录,便于追踪批量操作的执行情况
2026-01-30 17:51:43 +08:00

203 lines
5.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package hotime
import (
"encoding/json"
"os"
"sync"
"time"
. "code.hoteas.com/golang/hotime/cache"
. "code.hoteas.com/golang/hotime/common"
)
// session对象
type SessionIns struct {
*HoTimeCache
SessionId string
Map
ContextBase
mutex sync.RWMutex
}
// set 保存 session 到缓存,必须在锁内调用或传入深拷贝的 map
func (that *SessionIns) setWithCopy() {
// #region agent log
logFile, _ := os.OpenFile(`d:\work\hotimev1.5\.cursor\debug.log`, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if logFile != nil {
logEntry, _ := json.Marshal(map[string]interface{}{"sessionId": "debug-session", "runId": "run1", "hypothesisId": "A", "location": "session.go:setWithCopy", "message": "Session写入数据库触发", "data": map[string]interface{}{"session_id": that.SessionId, "map_size": len(that.Map)}, "timestamp": time.Now().UnixMilli()})
logFile.Write(append(logEntry, '\n'))
logFile.Close()
}
// #endregion
// 深拷贝 Map 防止并发修改
that.mutex.RLock()
copyMap := make(Map, len(that.Map))
for k, v := range that.Map {
copyMap[k] = v
}
that.mutex.RUnlock()
that.HoTimeCache.Session(HEAD_SESSION_ADD+that.SessionId, copyMap)
}
func (that *SessionIns) Session(key string, data ...interface{}) *Obj {
that.mutex.Lock()
if that.Map == nil {
that.getWithoutLock()
}
that.mutex.Unlock()
if len(data) != 0 {
// #region agent log
logFile, _ := os.OpenFile(`d:\work\hotimev1.5\.cursor\debug.log`, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if logFile != nil {
logEntry, _ := json.Marshal(map[string]interface{}{"sessionId": "debug-session", "runId": "run1", "hypothesisId": "B", "location": "session.go:Session", "message": "Session.Set调用", "data": map[string]interface{}{"key": key, "is_delete": data[0] == nil}, "timestamp": time.Now().UnixMilli()})
logFile.Write(append(logEntry, '\n'))
logFile.Close()
}
// #endregion
that.mutex.Lock()
if data[0] == nil {
delete(that.Map, key)
} else {
that.Map[key] = data[0]
}
that.mutex.Unlock()
// 使用深拷贝版本保存,避免并发问题
that.setWithCopy()
return &Obj{Data: nil}
}
that.mutex.RLock()
result := &Obj{Data: that.Map.Get(key)}
that.mutex.RUnlock()
return result
}
// SessionsSet 批量设置session字段只触发一次数据库写入
// 用法that.SessionsSet(Map{"key1": value1, "key2": value2, ...})
// 性能优化设置N个字段只触发1次数据库写入而非N次
func (that *SessionIns) SessionsSet(data Map) {
if len(data) == 0 {
return
}
// #region agent log
logFile, _ := os.OpenFile(`d:\work\hotimev1.5\.cursor\debug.log`, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if logFile != nil {
keys := make([]string, 0, len(data))
for k := range data {
keys = append(keys, k)
}
logEntry, _ := json.Marshal(map[string]interface{}{"sessionId": "debug-session", "runId": "run1", "hypothesisId": "C", "location": "session.go:SessionsSet", "message": "SessionsSet批量设置", "data": map[string]interface{}{"keys": keys, "count": len(data)}, "timestamp": time.Now().UnixMilli()})
logFile.Write(append(logEntry, '\n'))
logFile.Close()
}
// #endregion
that.mutex.Lock()
if that.Map == nil {
that.getWithoutLock()
}
// 批量设置所有字段
for key, value := range data {
if value == nil {
delete(that.Map, key)
} else {
that.Map[key] = value
}
}
that.mutex.Unlock()
// 只触发一次数据库写入
that.setWithCopy()
}
// SessionsDelete 批量删除session字段只触发一次数据库写入
// 用法that.SessionsDelete("key1", "key2", ...)
func (that *SessionIns) SessionsDelete(keys ...string) {
if len(keys) == 0 {
return
}
// #region agent log
logFile, _ := os.OpenFile(`d:\work\hotimev1.5\.cursor\debug.log`, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if logFile != nil {
logEntry, _ := json.Marshal(map[string]interface{}{"sessionId": "debug-session", "runId": "run1", "hypothesisId": "C", "location": "session.go:SessionsDelete", "message": "SessionsDelete批量删除", "data": map[string]interface{}{"keys": keys, "count": len(keys)}, "timestamp": time.Now().UnixMilli()})
logFile.Write(append(logEntry, '\n'))
logFile.Close()
}
// #endregion
that.mutex.Lock()
if that.Map == nil {
that.getWithoutLock()
}
// 批量删除所有字段
for _, key := range keys {
delete(that.Map, key)
}
that.mutex.Unlock()
// 只触发一次数据库写入
that.setWithCopy()
}
// SessionsGet 批量获取session字段
// 用法result := that.SessionsGet("key1", "key2", ...)
// 返回 Mapkey 为字段名value 为字段值(不存在的 key 不包含在结果中)
func (that *SessionIns) SessionsGet(keys ...string) Map {
if len(keys) == 0 {
return Map{}
}
that.mutex.Lock()
if that.Map == nil {
that.getWithoutLock()
}
that.mutex.Unlock()
result := make(Map, len(keys))
that.mutex.RLock()
for _, key := range keys {
if value, exists := that.Map[key]; exists {
result[key] = value
}
}
that.mutex.RUnlock()
return result
}
// getWithoutLock 内部使用,调用前需要已持有锁
func (that *SessionIns) getWithoutLock() {
that.Map = that.HoTimeCache.Session(HEAD_SESSION_ADD + that.SessionId).ToMap()
if that.Map != nil {
return
}
that.Map = Map{}
// 保存时也需要深拷贝
copyMap := make(Map, len(that.Map))
for k, v := range that.Map {
copyMap[k] = v
}
that.HoTimeCache.Session(HEAD_SESSION_ADD+that.SessionId, copyMap)
}
func (that *SessionIns) get() {
that.mutex.Lock()
defer that.mutex.Unlock()
that.getWithoutLock()
}
func (that *SessionIns) Init(cache *HoTimeCache) {
that.mutex = sync.RWMutex{}
that.HoTimeCache = cache
}