You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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 = {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], 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)