sharetable特点
1.不同虚拟机共享
2.不可更改
3.脱落gc
4.不可以设置元表
适用场景
不同虚拟机都需要用到的不在代码内更改的配置表
API
sharetable.loadfile(filename,...)
通过文件加载一个lua表,云风大佬推荐使用api
sharetable.loadstring(str)
类似loadfile,loadfile多了一步读取文件
sharetable.loadtable(tbl)
直接共享一张表,云风大佬不推荐,因为此接口会经过一次序列化和拷贝
sharetable.query(filename)
查询共享table
sharetable.update(...)
更新一个或多个key
sharetable.queryall()
查询多个共享表
sharetable更新
sharetable多次load同一张表时会生成多份表数据,只不过query查询永远指向以filename为key的最新加载的数据表地址,所以当你重新loadfile的时候,之前query过的虚拟机指向的是老的filename地址,需要调用sharetable.update更新一下。
sharetable释放
当一个filename被加载多次,老的数据表应该释放,那么何时释放?
sharetable对于每一个数据表都标记了引用计数,当一个虚拟机查询拿到了这个数据表,会使引用计数加1,只有引用计数为0并且不是最新的数据表,才会被释放掉。
local function query_file(source, filename)
local m = files[filename]
local ptr = m:getptr()
local ref = matrix[ptr]
if ref == nil then
ref = {
filename = filename,
count = 0,
matrix = m,
refs = {},
}
matrix[ptr] = ref
end
if ref.refs[source] == nil then
ref.refs[source] = true
local list = clients[source]
if not list then
clients[source] = { ptr }
else
table.insert(list, ptr)
end
ref.count = ref.count + 1
end
return ptr
end
function sharetable.close(source)
local list = clients[source]
if list then
for _, ptr in ipairs(list) do
local ref = matrix[ptr]
if ref and ref.refs[source] then
ref.refs[source] = nil
ref.count = ref.count - 1
if ref.count == 0 then
if files[ref.filename] ~= ref.matrix then
-- It's a history version
skynet.error(string.format("Delete a version (%s) of %s", ptr, ref.filename))
ref.matrix:close()
matrix[ptr] = nil
end
end
end
end
clients[source] = nil
end
-- no return
end
何时才能释放引用,需要虚拟机退出,也就是引用过数据表的虚拟机调用skynet.exit()退出了,才能释放引用计数。
local function report_close(t)
local addr = rawget(t, "address")
if addr then
skynet.send(addr, "lua", "close")
end
end
local sharetable = setmetatable ( {} , {
__index = load_service,
__gc = report_close,
})
云风大佬是妙用的__gc原方法的方式调用发送close消息给sharetable,释放掉改虚拟机所以的引用。