mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-22 11:03:12 +00:00
crash occr analise: 1.sharedated.update call many times in a short time(eg:3 times) to change a same name conf value to a->b->c->d. 2.sharedated sending 3 response to monitoring clients。a->b and b->c and c->d. 3.if b is destroyed and it's memory is reallocated and rewrited when client process the first message a->b, client's call lbox will crash. solution: conf b must be keeped before message(a->b) is processed by inc it's ref. Any return value from host to client must use incref before send to client.
169 lines
3.3 KiB
Lua
169 lines
3.3 KiB
Lua
local skynet = require "skynet"
|
|
local sharedata = require "skynet.sharedata.corelib"
|
|
local table = table
|
|
local cache = require "skynet.codecache"
|
|
cache.mode "OFF" -- turn off codecache, because CMD.new may load data file
|
|
|
|
local NORET = {}
|
|
local pool = {}
|
|
local pool_count = {}
|
|
local objmap = {}
|
|
local collect_tick = 10
|
|
|
|
local function newobj(name, tbl)
|
|
assert(pool[name] == nil)
|
|
local cobj = sharedata.host.new(tbl)
|
|
sharedata.host.incref(cobj)
|
|
local v = { value = tbl , obj = cobj, watch = {} }
|
|
objmap[cobj] = v
|
|
pool[name] = v
|
|
pool_count[name] = { n = 0, threshold = 16 }
|
|
end
|
|
|
|
local function collect1min()
|
|
if collect_tick > 1 then
|
|
collect_tick = 1
|
|
end
|
|
end
|
|
|
|
local function collectobj()
|
|
while true do
|
|
skynet.sleep(60*100) -- sleep 1min
|
|
if collect_tick <= 0 then
|
|
collect_tick = 10 -- reset tick count to 10 min
|
|
collectgarbage()
|
|
for obj, v in pairs(objmap) do
|
|
if v == true then
|
|
if sharedata.host.getref(obj) <= 0 then
|
|
objmap[obj] = nil
|
|
sharedata.host.delete(obj)
|
|
end
|
|
end
|
|
end
|
|
else
|
|
collect_tick = collect_tick - 1
|
|
end
|
|
end
|
|
end
|
|
|
|
local CMD = {}
|
|
|
|
local env_mt = { __index = _ENV }
|
|
|
|
function CMD.new(name, t, ...)
|
|
local dt = type(t)
|
|
local value
|
|
if dt == "table" then
|
|
value = t
|
|
elseif dt == "string" then
|
|
value = setmetatable({}, env_mt)
|
|
local f
|
|
if t:sub(1,1) == "@" then
|
|
f = assert(loadfile(t:sub(2),"bt",value))
|
|
else
|
|
f = assert(load(t, "=" .. name, "bt", value))
|
|
end
|
|
local _, ret = assert(skynet.pcall(f, ...))
|
|
setmetatable(value, nil)
|
|
if type(ret) == "table" then
|
|
value = ret
|
|
end
|
|
elseif dt == "nil" then
|
|
value = {}
|
|
else
|
|
error ("Unknown data type " .. dt)
|
|
end
|
|
newobj(name, value)
|
|
end
|
|
|
|
function CMD.delete(name)
|
|
local v = assert(pool[name])
|
|
pool[name] = nil
|
|
pool_count[name] = nil
|
|
assert(objmap[v.obj])
|
|
objmap[v.obj] = true
|
|
sharedata.host.decref(v.obj)
|
|
for _,response in pairs(v.watch) do
|
|
response(true)
|
|
end
|
|
end
|
|
|
|
function CMD.query(name)
|
|
local v = assert(pool[name])
|
|
local obj = v.obj
|
|
sharedata.host.incref(obj)
|
|
return v.obj
|
|
end
|
|
|
|
function CMD.confirm(cobj)
|
|
if objmap[cobj] then
|
|
sharedata.host.decref(cobj)
|
|
end
|
|
return NORET
|
|
end
|
|
|
|
function CMD.update(name, t, ...)
|
|
local v = pool[name]
|
|
local watch, oldcobj
|
|
if v then
|
|
watch = v.watch
|
|
oldcobj = v.obj
|
|
objmap[oldcobj] = true
|
|
sharedata.host.decref(oldcobj)
|
|
pool[name] = nil
|
|
pool_count[name] = nil
|
|
end
|
|
CMD.new(name, t, ...)
|
|
local newobj = pool[name].obj
|
|
if watch then
|
|
sharedata.host.markdirty(oldcobj)
|
|
for _,response in pairs(watch) do
|
|
sharedata.host.incref(newobj)
|
|
response(true, newobj)
|
|
end
|
|
end
|
|
collect1min() -- collect in 1 min
|
|
end
|
|
|
|
local function check_watch(queue)
|
|
local n = 0
|
|
for k,response in pairs(queue) do
|
|
if not response "TEST" then
|
|
queue[k] = nil
|
|
n = n + 1
|
|
end
|
|
end
|
|
return n
|
|
end
|
|
|
|
function CMD.monitor(name, obj)
|
|
local v = assert(pool[name])
|
|
if obj ~= v.obj then
|
|
sharedata.host.incref(v.obj)
|
|
return v.obj
|
|
end
|
|
|
|
local n = pool_count[name].n + 1
|
|
if n > pool_count[name].threshold then
|
|
n = n - check_watch(v.watch)
|
|
pool_count[name].threshold = n * 2
|
|
end
|
|
pool_count[name].n = n
|
|
|
|
table.insert(v.watch, skynet.response())
|
|
|
|
return NORET
|
|
end
|
|
|
|
skynet.start(function()
|
|
skynet.fork(collectobj)
|
|
skynet.dispatch("lua", function (session, source ,cmd, ...)
|
|
local f = assert(CMD[cmd])
|
|
local r = f(...)
|
|
if r ~= NORET then
|
|
skynet.ret(skynet.pack(r))
|
|
end
|
|
end)
|
|
end)
|
|
|