为了缓解数据库压力,数据会缓存在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的博客,感觉大佬的理解对于新人很有启发
已加