- 在 HoTimeCache 中新增 SessionsGet、SessionsSet 和 SessionsDelete 方法,支持批量获取、设置和删除 Session 缓存 - 优化缓存逻辑,减少数据库写入次数,提升性能 - 更新文档,详细说明批量操作的使用方法和性能对比 - 添加调试日志记录,便于追踪批量操作的执行情况
488 lines
15 KiB
Go
488 lines
15 KiB
Go
package main
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"os"
|
||
"time"
|
||
|
||
"code.hoteas.com/golang/hotime"
|
||
"code.hoteas.com/golang/hotime/cache"
|
||
. "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{}) {
|
||
logFile, _ := os.OpenFile(debugLogPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||
if logFile != nil {
|
||
logEntry, _ := json.Marshal(map[string]interface{}{
|
||
"sessionId": "batch-cache-test",
|
||
"runId": "test-run",
|
||
"hypothesisId": hypothesisId,
|
||
"location": location,
|
||
"message": message,
|
||
"data": data,
|
||
"timestamp": time.Now().UnixMilli(),
|
||
})
|
||
logFile.Write(append(logEntry, '\n'))
|
||
logFile.Close()
|
||
}
|
||
}
|
||
|
||
// TestBatchCacheOperations 测试所有批量缓存操作
|
||
func TestBatchCacheOperations(app *hotime.Application) {
|
||
fmt.Println("\n========== 批量缓存操作测试开始 ==========")
|
||
|
||
// 测试1: 测试 CacheMemory 批量操作
|
||
fmt.Println("\n--- 测试1: CacheMemory 批量操作 ---")
|
||
testCacheMemoryBatch(app)
|
||
|
||
// 测试2: 测试 CacheDb 批量操作
|
||
fmt.Println("\n--- 测试2: CacheDb 批量操作 ---")
|
||
testCacheDbBatch(app)
|
||
|
||
// 测试3: 测试 HoTimeCache 三级缓存批量操作
|
||
fmt.Println("\n--- 测试3: HoTimeCache 三级缓存批量操作 ---")
|
||
testHoTimeCacheBatch(app)
|
||
|
||
// 测试4: 测试 SessionIns 批量操作
|
||
fmt.Println("\n--- 测试4: SessionIns 批量操作 ---")
|
||
testSessionInsBatch(app)
|
||
|
||
// 测试5: 测试缓存反哺机制
|
||
fmt.Println("\n--- 测试5: 缓存反哺机制测试 ---")
|
||
testCacheBackfill(app)
|
||
|
||
// 测试6: 测试批量操作效率(一次性写入验证)
|
||
fmt.Println("\n--- 测试6: 批量操作效率测试 ---")
|
||
testBatchEfficiency(app)
|
||
|
||
fmt.Println("\n========== 批量缓存操作测试完成 ==========")
|
||
}
|
||
|
||
// testCacheMemoryBatch 测试内存缓存批量操作
|
||
func testCacheMemoryBatch(app *hotime.Application) {
|
||
// #region agent log
|
||
debugLog("E", "batch_cache_test.go:testCacheMemoryBatch:start", "开始测试CacheMemory批量操作", nil)
|
||
// #endregion
|
||
|
||
memCache := &cache.CacheMemory{TimeOut: 3600, DbSet: true, SessionSet: true}
|
||
memCache.SetError(&Error{})
|
||
|
||
// 测试 CachesSet
|
||
testData := Map{
|
||
"mem_key1": "value1",
|
||
"mem_key2": "value2",
|
||
"mem_key3": "value3",
|
||
}
|
||
memCache.CachesSet(testData)
|
||
|
||
// #region agent log
|
||
debugLog("E", "batch_cache_test.go:testCacheMemoryBatch:afterSet", "CacheMemory.CachesSet完成", map[string]interface{}{"count": len(testData)})
|
||
// #endregion
|
||
|
||
// 测试 CachesGet
|
||
keys := []string{"mem_key1", "mem_key2", "mem_key3", "mem_key_not_exist"}
|
||
result := memCache.CachesGet(keys)
|
||
|
||
// #region agent log
|
||
debugLog("E", "batch_cache_test.go:testCacheMemoryBatch:afterGet", "CacheMemory.CachesGet完成", map[string]interface{}{
|
||
"requested_keys": keys,
|
||
"result_count": len(result),
|
||
"result_keys": getMapKeys(result),
|
||
})
|
||
// #endregion
|
||
|
||
if len(result) != 3 {
|
||
fmt.Printf(" [FAIL] CacheMemory.CachesGet: 期望3个结果,实际%d个\n", len(result))
|
||
} else {
|
||
fmt.Println(" [PASS] CacheMemory.CachesGet: 批量获取正确")
|
||
}
|
||
|
||
// 测试 CachesDelete
|
||
memCache.CachesDelete([]string{"mem_key1", "mem_key2"})
|
||
result2 := memCache.CachesGet(keys)
|
||
|
||
// #region agent log
|
||
debugLog("E", "batch_cache_test.go:testCacheMemoryBatch:afterDelete", "CacheMemory.CachesDelete完成", map[string]interface{}{
|
||
"deleted_keys": []string{"mem_key1", "mem_key2"},
|
||
"remaining_count": len(result2),
|
||
"remaining_keys": getMapKeys(result2),
|
||
})
|
||
// #endregion
|
||
|
||
if len(result2) != 1 || result2["mem_key3"] == nil {
|
||
fmt.Printf(" [FAIL] CacheMemory.CachesDelete: 删除后期望1个结果,实际%d个\n", len(result2))
|
||
} else {
|
||
fmt.Println(" [PASS] CacheMemory.CachesDelete: 批量删除正确")
|
||
}
|
||
}
|
||
|
||
// testCacheDbBatch 测试数据库缓存批量操作
|
||
func testCacheDbBatch(app *hotime.Application) {
|
||
// #region agent log
|
||
debugLog("E", "batch_cache_test.go:testCacheDbBatch:start", "开始测试CacheDb批量操作", nil)
|
||
// #endregion
|
||
|
||
// 使用应用的数据库连接
|
||
dbCache := &cache.CacheDb{
|
||
TimeOut: 3600,
|
||
DbSet: true,
|
||
SessionSet: true,
|
||
Mode: cache.CacheModeNew,
|
||
Db: &app.Db,
|
||
}
|
||
dbCache.SetError(&Error{})
|
||
|
||
// 清理测试数据
|
||
dbCache.CachesDelete([]string{"db_batch_key1", "db_batch_key2", "db_batch_key3"})
|
||
|
||
// 测试 CachesSet
|
||
testData := Map{
|
||
"db_batch_key1": "db_value1",
|
||
"db_batch_key2": "db_value2",
|
||
"db_batch_key3": "db_value3",
|
||
}
|
||
dbCache.CachesSet(testData)
|
||
|
||
// #region agent log
|
||
debugLog("E", "batch_cache_test.go:testCacheDbBatch:afterSet", "CacheDb.CachesSet完成", map[string]interface{}{"count": len(testData)})
|
||
// #endregion
|
||
|
||
// 测试 CachesGet
|
||
keys := []string{"db_batch_key1", "db_batch_key2", "db_batch_key3", "db_not_exist"}
|
||
result := dbCache.CachesGet(keys)
|
||
|
||
// #region agent log
|
||
debugLog("E", "batch_cache_test.go:testCacheDbBatch:afterGet", "CacheDb.CachesGet完成", map[string]interface{}{
|
||
"requested_keys": keys,
|
||
"result_count": len(result),
|
||
"result_keys": getMapKeys(result),
|
||
"result_values": result,
|
||
})
|
||
// #endregion
|
||
|
||
if len(result) != 3 {
|
||
fmt.Printf(" [FAIL] CacheDb.CachesGet: 期望3个结果,实际%d个\n", len(result))
|
||
} else {
|
||
fmt.Println(" [PASS] CacheDb.CachesGet: 批量获取正确")
|
||
}
|
||
|
||
// 验证值正确性
|
||
if result["db_batch_key1"] != "db_value1" {
|
||
fmt.Printf(" [FAIL] CacheDb.CachesGet: db_batch_key1 值不正确,期望 db_value1,实际 %v\n", result["db_batch_key1"])
|
||
} else {
|
||
fmt.Println(" [PASS] CacheDb.CachesGet: 值内容正确")
|
||
}
|
||
|
||
// 测试 CachesDelete
|
||
dbCache.CachesDelete([]string{"db_batch_key1", "db_batch_key2"})
|
||
result2 := dbCache.CachesGet(keys)
|
||
|
||
// #region agent log
|
||
debugLog("E", "batch_cache_test.go:testCacheDbBatch:afterDelete", "CacheDb.CachesDelete完成", map[string]interface{}{
|
||
"deleted_keys": []string{"db_batch_key1", "db_batch_key2"},
|
||
"remaining_count": len(result2),
|
||
"remaining_keys": getMapKeys(result2),
|
||
})
|
||
// #endregion
|
||
|
||
if len(result2) != 1 {
|
||
fmt.Printf(" [FAIL] CacheDb.CachesDelete: 删除后期望1个结果,实际%d个\n", len(result2))
|
||
} else {
|
||
fmt.Println(" [PASS] CacheDb.CachesDelete: 批量删除正确")
|
||
}
|
||
|
||
// 清理
|
||
dbCache.CachesDelete([]string{"db_batch_key3"})
|
||
}
|
||
|
||
// testHoTimeCacheBatch 测试 HoTimeCache 三级缓存批量操作
|
||
func testHoTimeCacheBatch(app *hotime.Application) {
|
||
// #region agent log
|
||
debugLog("D", "batch_cache_test.go:testHoTimeCacheBatch:start", "开始测试HoTimeCache三级缓存批量操作", nil)
|
||
// #endregion
|
||
|
||
htCache := app.HoTimeCache
|
||
|
||
// 清理测试数据
|
||
htCache.SessionsDelete([]string{
|
||
hotime.HEAD_SESSION_ADD + "ht_batch_key1",
|
||
hotime.HEAD_SESSION_ADD + "ht_batch_key2",
|
||
hotime.HEAD_SESSION_ADD + "ht_batch_key3",
|
||
})
|
||
|
||
// 测试 SessionsSet
|
||
testData := Map{
|
||
hotime.HEAD_SESSION_ADD + "ht_batch_key1": Map{"user": "test1", "role": "admin"},
|
||
hotime.HEAD_SESSION_ADD + "ht_batch_key2": Map{"user": "test2", "role": "user"},
|
||
hotime.HEAD_SESSION_ADD + "ht_batch_key3": Map{"user": "test3", "role": "guest"},
|
||
}
|
||
htCache.SessionsSet(testData)
|
||
|
||
// #region agent log
|
||
debugLog("D", "batch_cache_test.go:testHoTimeCacheBatch:afterSet", "HoTimeCache.SessionsSet完成", map[string]interface{}{"count": len(testData)})
|
||
// #endregion
|
||
|
||
// 测试 SessionsGet
|
||
keys := []string{
|
||
hotime.HEAD_SESSION_ADD + "ht_batch_key1",
|
||
hotime.HEAD_SESSION_ADD + "ht_batch_key2",
|
||
hotime.HEAD_SESSION_ADD + "ht_batch_key3",
|
||
hotime.HEAD_SESSION_ADD + "ht_not_exist",
|
||
}
|
||
result := htCache.SessionsGet(keys)
|
||
|
||
// #region agent log
|
||
debugLog("D", "batch_cache_test.go:testHoTimeCacheBatch:afterGet", "HoTimeCache.SessionsGet完成", map[string]interface{}{
|
||
"requested_keys": len(keys),
|
||
"result_count": len(result),
|
||
"result_keys": getMapKeys(result),
|
||
})
|
||
// #endregion
|
||
|
||
if len(result) != 3 {
|
||
fmt.Printf(" [FAIL] HoTimeCache.SessionsGet: 期望3个结果,实际%d个\n", len(result))
|
||
} else {
|
||
fmt.Println(" [PASS] HoTimeCache.SessionsGet: 批量获取正确")
|
||
}
|
||
|
||
// 测试 SessionsDelete
|
||
htCache.SessionsDelete([]string{
|
||
hotime.HEAD_SESSION_ADD + "ht_batch_key1",
|
||
hotime.HEAD_SESSION_ADD + "ht_batch_key2",
|
||
})
|
||
result2 := htCache.SessionsGet(keys)
|
||
|
||
// #region agent log
|
||
debugLog("D", "batch_cache_test.go:testHoTimeCacheBatch:afterDelete", "HoTimeCache.SessionsDelete完成", map[string]interface{}{
|
||
"remaining_count": len(result2),
|
||
})
|
||
// #endregion
|
||
|
||
if len(result2) != 1 {
|
||
fmt.Printf(" [FAIL] HoTimeCache.SessionsDelete: 删除后期望1个结果,实际%d个\n", len(result2))
|
||
} else {
|
||
fmt.Println(" [PASS] HoTimeCache.SessionsDelete: 批量删除正确")
|
||
}
|
||
|
||
// 清理
|
||
htCache.SessionsDelete([]string{hotime.HEAD_SESSION_ADD + "ht_batch_key3"})
|
||
}
|
||
|
||
// testSessionInsBatch 测试 SessionIns 批量操作
|
||
func testSessionInsBatch(app *hotime.Application) {
|
||
// #region agent log
|
||
debugLog("B", "batch_cache_test.go:testSessionInsBatch:start", "开始测试SessionIns批量操作", nil)
|
||
// #endregion
|
||
|
||
// 创建一个模拟的 SessionIns
|
||
session := &hotime.SessionIns{
|
||
SessionId: "test_batch_session_" + ObjToStr(time.Now().UnixNano()),
|
||
}
|
||
session.Init(app.HoTimeCache)
|
||
|
||
// 测试 SessionsSet
|
||
testData := Map{
|
||
"field1": "value1",
|
||
"field2": 123,
|
||
"field3": Map{"nested": "data"},
|
||
}
|
||
session.SessionsSet(testData)
|
||
|
||
// #region agent log
|
||
debugLog("B", "batch_cache_test.go:testSessionInsBatch:afterSet", "SessionIns.SessionsSet完成", map[string]interface{}{
|
||
"session_id": session.SessionId,
|
||
"count": len(testData),
|
||
})
|
||
// #endregion
|
||
|
||
// 测试 SessionsGet
|
||
result := session.SessionsGet("field1", "field2", "field3", "not_exist")
|
||
|
||
// #region agent log
|
||
debugLog("B", "batch_cache_test.go:testSessionInsBatch:afterGet", "SessionIns.SessionsGet完成", map[string]interface{}{
|
||
"result_count": len(result),
|
||
"result_keys": getMapKeys(result),
|
||
"result": result,
|
||
})
|
||
// #endregion
|
||
|
||
if len(result) != 3 {
|
||
fmt.Printf(" [FAIL] SessionIns.SessionsGet: 期望3个结果,实际%d个\n", len(result))
|
||
} else {
|
||
fmt.Println(" [PASS] SessionIns.SessionsGet: 批量获取正确")
|
||
}
|
||
|
||
// 验证值类型
|
||
if result["field1"] != "value1" {
|
||
fmt.Printf(" [FAIL] SessionIns.SessionsGet: field1 值不正确\n")
|
||
} else {
|
||
fmt.Println(" [PASS] SessionIns.SessionsGet: 字符串值正确")
|
||
}
|
||
|
||
var convErr Error
|
||
if ObjToInt(result["field2"], &convErr) != 123 {
|
||
fmt.Printf(" [FAIL] SessionIns.SessionsGet: field2 值不正确\n")
|
||
} else {
|
||
fmt.Println(" [PASS] SessionIns.SessionsGet: 数值类型正确")
|
||
}
|
||
|
||
// 测试 SessionsDelete
|
||
session.SessionsDelete("field1", "field2")
|
||
result2 := session.SessionsGet("field1", "field2", "field3")
|
||
|
||
// #region agent log
|
||
debugLog("B", "batch_cache_test.go:testSessionInsBatch:afterDelete", "SessionIns.SessionsDelete完成", map[string]interface{}{
|
||
"remaining_count": len(result2),
|
||
"remaining_keys": getMapKeys(result2),
|
||
})
|
||
// #endregion
|
||
|
||
if len(result2) != 1 {
|
||
fmt.Printf(" [FAIL] SessionIns.SessionsDelete: 删除后期望1个结果,实际%d个\n", len(result2))
|
||
} else {
|
||
fmt.Println(" [PASS] SessionIns.SessionsDelete: 批量删除正确")
|
||
}
|
||
}
|
||
|
||
// testCacheBackfill 测试缓存反哺机制
|
||
func testCacheBackfill(app *hotime.Application) {
|
||
// #region agent log
|
||
debugLog("D", "batch_cache_test.go:testCacheBackfill:start", "开始测试缓存反哺机制", nil)
|
||
// #endregion
|
||
|
||
htCache := app.HoTimeCache
|
||
|
||
// 直接写入数据库缓存(绕过 memory)模拟只有 db 有数据的情况
|
||
dbCache := &cache.CacheDb{
|
||
TimeOut: 3600,
|
||
DbSet: true,
|
||
SessionSet: true,
|
||
Mode: cache.CacheModeNew,
|
||
Db: &app.Db,
|
||
}
|
||
dbCache.SetError(&Error{})
|
||
|
||
testKey := "backfill_test_key_" + ObjToStr(time.Now().UnixNano())
|
||
testValue := Map{"backfill": "test_data"}
|
||
|
||
// 直接写入 db
|
||
dbCache.Cache(testKey, testValue)
|
||
|
||
// #region agent log
|
||
debugLog("D", "batch_cache_test.go:testCacheBackfill:dbWritten", "数据直接写入DB", map[string]interface{}{
|
||
"key": testKey,
|
||
"value": testValue,
|
||
})
|
||
// #endregion
|
||
|
||
// 通过 HoTimeCache 批量获取,应该触发反哺到 memory
|
||
keys := []string{testKey}
|
||
result := htCache.CachesGet(keys)
|
||
|
||
// #region agent log
|
||
debugLog("D", "batch_cache_test.go:testCacheBackfill:afterGet", "HoTimeCache.CachesGet完成", map[string]interface{}{
|
||
"result_count": len(result),
|
||
"has_key": result[testKey] != nil,
|
||
})
|
||
// #endregion
|
||
|
||
if len(result) != 1 || result[testKey] == nil {
|
||
fmt.Println(" [FAIL] 缓存反哺: 从 DB 读取失败")
|
||
} else {
|
||
fmt.Println(" [PASS] 缓存反哺: 从 DB 读取成功")
|
||
}
|
||
|
||
// 清理
|
||
htCache.CachesDelete(keys)
|
||
}
|
||
|
||
// testBatchEfficiency 测试批量操作效率
|
||
func testBatchEfficiency(app *hotime.Application) {
|
||
// #region agent log
|
||
debugLog("A", "batch_cache_test.go:testBatchEfficiency:start", "开始测试批量操作效率", nil)
|
||
// #endregion
|
||
|
||
session := &hotime.SessionIns{
|
||
SessionId: "efficiency_test_" + ObjToStr(time.Now().UnixNano()),
|
||
}
|
||
session.Init(app.HoTimeCache)
|
||
|
||
// 记录批量设置开始时间
|
||
startTime := time.Now()
|
||
|
||
// 设置10个字段
|
||
testData := Map{}
|
||
for i := 0; i < 10; i++ {
|
||
testData[fmt.Sprintf("eff_field_%d", i)] = fmt.Sprintf("value_%d", i)
|
||
}
|
||
session.SessionsSet(testData)
|
||
|
||
batchDuration := time.Since(startTime)
|
||
|
||
// #region agent log
|
||
debugLog("A", "batch_cache_test.go:testBatchEfficiency:batchSet", "批量设置完成", map[string]interface{}{
|
||
"count": len(testData),
|
||
"duration_ms": batchDuration.Milliseconds(),
|
||
})
|
||
// #endregion
|
||
|
||
// 对比单个设置
|
||
session2 := &hotime.SessionIns{
|
||
SessionId: "efficiency_test_single_" + ObjToStr(time.Now().UnixNano()),
|
||
}
|
||
session2.Init(app.HoTimeCache)
|
||
|
||
startTime2 := time.Now()
|
||
for i := 0; i < 10; i++ {
|
||
session2.Session(fmt.Sprintf("single_field_%d", i), fmt.Sprintf("value_%d", i))
|
||
}
|
||
singleDuration := time.Since(startTime2)
|
||
|
||
// #region agent log
|
||
debugLog("A", "batch_cache_test.go:testBatchEfficiency:singleSet", "单个设置完成", map[string]interface{}{
|
||
"count": 10,
|
||
"duration_ms": singleDuration.Milliseconds(),
|
||
})
|
||
// #endregion
|
||
|
||
fmt.Printf(" 批量设置10个字段耗时: %v\n", batchDuration)
|
||
fmt.Printf(" 单个设置10个字段耗时: %v\n", singleDuration)
|
||
|
||
if batchDuration < singleDuration {
|
||
fmt.Println(" [PASS] 批量操作效率: 批量操作更快")
|
||
} else {
|
||
fmt.Println(" [WARN] 批量操作效率: 批量操作未体现优势(可能数据量太小)")
|
||
}
|
||
|
||
// 批量获取测试
|
||
startTime3 := time.Now()
|
||
keys := make([]string, 10)
|
||
for i := 0; i < 10; i++ {
|
||
keys[i] = fmt.Sprintf("eff_field_%d", i)
|
||
}
|
||
session.SessionsGet(keys...)
|
||
batchGetDuration := time.Since(startTime3)
|
||
|
||
// #region agent log
|
||
debugLog("A", "batch_cache_test.go:testBatchEfficiency:batchGet", "批量获取完成", map[string]interface{}{
|
||
"count": 10,
|
||
"duration_ms": batchGetDuration.Milliseconds(),
|
||
})
|
||
// #endregion
|
||
|
||
fmt.Printf(" 批量获取10个字段耗时: %v\n", batchGetDuration)
|
||
}
|
||
|
||
// getMapKeys 获取 Map 的所有键
|
||
func getMapKeys(m Map) []string {
|
||
keys := make([]string, 0, len(m))
|
||
for k := range m {
|
||
keys = append(keys, k)
|
||
}
|
||
return keys
|
||
}
|