为了缓解数据库压力,数据会缓存在lua table,满足频繁读写需求,再定时检查,发现数据变了则落地。
问题来了,lua table怎么检查数据变了?
table检查数据变了
答案很简单,使用 metatable,这里贴一个简单的例子。
-- db数据 db = {openid="openid_123", token="token_123"} -- 缓存 cache = {} setmetatable(cache, { __index = function(t, k) return db[k] end, __newindex = function(t, k, v) if k ~= "__dirty" then db.__dirty = true end db[k] = v end, __pairs = function(t, k) return next, db, k end, }) for k, v in pairs(cache) do print(k, v) end cache.__dirty = nil print("cache.__dirty", cache.__dirty) cache.token = "token_456" print("cache.__dirty", cache.__dirty)
执行结果如下:
> dofile("test.lua") token token_123 openid openid_123 cache.__dirty nil cache.__dirty true
问题到这里就结束了。
接下来,我们再提出一个问题,lua table如何检查子项为table的数据变了?
table检查子项为table的数据变了
先说思路,要遍历 table,找到所有子项的table,都设置 metatable
注意处理好两个问题:
1、值为table,table之间可能相互引用,就可能存在m对n的引用关系
2、子table下可能又有table,所有子table修改都要更新根table状态
为此,实现如下(非完整版本):
local function dirty_check(root) local dummy = {} local g_set = {} local function check_table(t) if type(t) ~= "table" then return end local mt = getmetatable(t) local tv = g_set[t] if not tv then local tv = {} for k, v in pairs(t) do check_table(v) tv[k] = v rawset(t, k, nil) -- 强制使 table 触发 newindex end g_set[t] = tv end if not mt then setmetatable(t, dummy) end end dummy.__newindex = function(t, k, v) if k ~= "__dirty" then g_set[root]["__dirty"] = true check_table(v) end g_set[t][k] = v -- 存在内存泄漏,v 为 table 需要清理 g_set end dummy.__index = function(t, k) return g_set[t][k] end dummy.__pairs = function(t, k) return next, g_set[t], k end dummy.__len = function(t) return #g_set[t] end check_table(root) end -- 例子 local tb = {1,2,3, {}} dirty_check(tb) for k,v in pairs(tb) do print(k,v) end print("table dirty 1", tb.__dirty) tb[3]=1 print("table dirty 2", tb.__dirty) tb.__dirty = nil tb[3]=2 print("table dirty 3", tb.__dirty) tb.__dirty = nil local t={{},{},{},{},{}} tb[4] = t print("table dirty 4", tb.__dirty) tb.__dirty = nil t[3][1] = 1 print("table dirty 5", tb.__dirty) tb.__dirty = nil t[3][1] = 2 print("table dirty 6", tb.__dirty) tb.__dirty = nil t[3][2] = {} print("table dirty 7", tb.__dirty)
执行结果如下:
> dofile("test.lua") 1 1 2 2 3 3 4 table: 0x7c6a20 table dirty 1 nil table dirty 2 true table dirty 3 true table dirty 4 true table dirty 5 true table dirty 6 true table dirty 7 true
文章最后,贴下完整版本,包含了内存泄漏的处理,有兴趣看看,有问题撩我 https://github.com/chenweiqi/lua_util
大佬,现在用的是skynet还是erlang框架
现在使用skynet了
大佬有空方便技术交流下嘛(联系方式,取取经),看了大佬大部分csdn的博客,感觉大佬的理解对于新人很有启发
已加