summaryrefslogtreecommitdiff
path: root/server-beta/src/doctor.lua
diff options
context:
space:
mode:
Diffstat (limited to 'server-beta/src/doctor.lua')
-rw-r--r--server-beta/src/doctor.lua380
1 files changed, 0 insertions, 380 deletions
diff --git a/server-beta/src/doctor.lua b/server-beta/src/doctor.lua
deleted file mode 100644
index 08ec69cf..00000000
--- a/server-beta/src/doctor.lua
+++ /dev/null
@@ -1,380 +0,0 @@
-local type = type
-local next = next
-local ipairs = ipairs
-local rawget = rawget
-local pcall = pcall
-local getregistry = debug.getregistry
-local getmetatable = debug.getmetatable
-local getupvalue = debug.getupvalue
-local getuservalue = debug.getuservalue
-local getlocal = debug.getlocal
-local getinfo = debug.getinfo
-local maxinterger = math.maxinteger
-local mathType = math.type
-local tableConcat = table.concat
-local _G = _G
-local registry = getregistry()
-local tableSort = table.sort
-
-_ENV = nil
-
-local m = {}
-
-local function getTostring(obj)
- local mt = getmetatable(obj)
- if not mt then
- return nil
- end
- local toString = rawget(mt, '__tostring')
- if not toString then
- return nil
- end
- local suc, str = pcall(toString, obj)
- if not suc then
- return nil
- end
- if type(str) ~= 'string' then
- return nil
- end
- return str
-end
-
-local function formatName(obj)
- local tp = type(obj)
- if tp == 'nil' then
- return 'nil:nil'
- elseif tp == 'boolean' then
- if obj == true then
- return 'boolean:true'
- else
- return 'boolean:false'
- end
- elseif tp == 'number' then
- if mathType(obj) == 'integer' then
- return ('number:%d'):format(obj)
- else
- -- 如果浮点数可以完全表示为整数,那么就转换为整数
- local str = ('%.10f'):format(obj):gsub('%.?[0]+$', '')
- if str:find('.', 1, true) then
- -- 如果浮点数不能表示为整数,那么再加上它的精确表示法
- str = ('%s(%q)'):format(str, obj)
- end
- return 'number:' .. str
- end
- elseif tp == 'string' then
- local str = ('%q'):format(obj)
- if #str > 100 then
- local new = ('%s...(len=%d)'):format(str:sub(1, 100), #str)
- if #new < #str then
- str = new
- end
- end
- return 'string:' .. str
- elseif tp == 'function' then
- local info = getinfo(obj, 'S')
- if info.what == 'c' then
- return ('function:%p(C)'):format(obj)
- elseif info.what == 'main' then
- return ('function:%p(main)'):format(obj)
- else
- return ('function:%p(%s:%d-%d)'):format(obj, info.source, info.linedefined, info.lastlinedefined)
- end
- elseif tp == 'table' then
- local id = getTostring(obj)
- if not id then
- if obj == _G then
- id = '_G'
- elseif obj == registry then
- id = 'registry'
- end
- end
- if id then
- return ('table:%p(%s)'):format(obj, id)
- else
- return ('table:%p'):format(obj)
- end
- elseif tp == 'userdata' then
- local id = getTostring(obj)
- if id then
- return ('userdata:%p(%s)'):format(obj, id)
- else
- return ('userdata:%p'):format(obj)
- end
- else
- return ('%s:%p'):format(tp, obj)
- end
-end
-
---- 内存快照
----@return table
-function m.snapshot()
- local mark = {}
- local find
-
- local function findTable(t, result)
- result = result or {}
- local mt = getmetatable(t)
- local wk, wv
- if mt then
- local mode = rawget(mt, '__mode')
- if type(mode) == 'string' then
- if mode:find('k', 1, true) then
- wk = true
- end
- if mode:find('v', 1, true) then
- wv = true
- end
- end
- end
- for k, v in next, t do
- if not wk then
- local keyInfo = find(k)
- if keyInfo then
- result[#result+1] = {
- type = 'key',
- name = formatName(k),
- info = keyInfo,
- }
- end
- end
- if not wv then
- local valueInfo = find(v)
- if valueInfo then
- result[#result+1] = {
- type = 'field',
- name = formatName(k) .. '|' .. formatName(v),
- info = valueInfo,
- }
- end
- end
- end
- local MTInfo = find(getmetatable(t))
- if MTInfo then
- result[#result+1] = {
- type = 'metatable',
- name = '',
- info = MTInfo,
- }
- end
- if #result == 0 then
- return nil
- end
- return result
- end
-
- local function findFunction(f, result, trd, stack)
- result = result or {}
- for i = 1, maxinterger do
- local n, v = getupvalue(f, i)
- if not n then
- break
- end
- local valueInfo = find(v)
- if valueInfo then
- result[#result+1] = {
- type = 'upvalue',
- name = n,
- info = valueInfo,
- }
- end
- end
- if trd then
- for i = 1, maxinterger do
- local n, l = getlocal(trd, stack, i)
- if not n then
- break
- end
- local valueInfo = find(l)
- if valueInfo then
- result[#result+1] = {
- type = 'local',
- name = n,
- info = valueInfo,
- }
- end
- end
- end
- if #result == 0 then
- return nil
- end
- return result
- end
-
- local function findUserData(u, result)
- result = result or {}
- for i = 1, maxinterger do
- local v, b = getuservalue(u, i)
- if not b then
- break
- end
- local valueInfo = find(v)
- if valueInfo then
- result[#result+1] = {
- type = 'uservalue',
- name = formatName(i),
- info = valueInfo,
- }
- end
- end
- local MTInfo = find(getmetatable(u))
- if MTInfo then
- result[#result+1] = {
- type = 'metatable',
- name = '',
- info = MTInfo,
- }
- end
- if #result == 0 then
- return nil
- end
- return result
- end
-
- local function findThread(trd, result)
- -- 不查找主线程,主线程一定是临时的(视为弱引用)
- if trd == registry[1] then
- return nil
- end
- result = result or {}
-
- for i = 1, maxinterger do
- local info = getinfo(trd, i, 'Sf')
- if not info then
- break
- end
- local funcInfo = find(info.func, trd, i)
- if funcInfo then
- result[#result+1] = {
- type = 'stack',
- name = i .. '@' .. formatName(info.func),
- info = funcInfo,
- }
- end
- end
-
- if #result == 0 then
- return nil
- end
- return result
- end
-
- function find(obj, trd, stack)
- if mark[obj] then
- return mark[obj]
- end
- local tp = type(obj)
- if tp == 'table' then
- mark[obj] = {}
- mark[obj] = findTable(obj, mark[obj])
- elseif tp == 'function' then
- mark[obj] = {}
- mark[obj] = findFunction(obj, mark[obj], trd, stack)
- elseif tp == 'userdata' then
- mark[obj] = {}
- mark[obj] = findUserData(obj, mark[obj])
- elseif tp == 'thread' then
- mark[obj] = {}
- mark[obj] = findThread(obj, mark[obj])
- else
- return nil
- end
- if mark[obj] then
- mark[obj].object = obj
- end
- return mark[obj]
- end
-
- return {
- name = formatName(registry),
- type = 'root',
- info = find(registry),
- }
-end
-
---- 寻找对象的引用
----@return string
-function m.catch(...)
- local targets = {}
- for _, target in ipairs {...} do
- targets[target] = true
- end
- local report = m.snapshot()
- local path = {}
- local result = {}
- local mark = {}
-
- local function push()
- result[#result+1] = tableConcat(path, ' => ')
- end
-
- local function search(t)
- path[#path+1] = ('(%s)%s'):format(t.type, t.name)
- local addTarget
- if targets[t.info.object] then
- targets[t.info.object] = nil
- addTarget = t.info.object
- push(t)
- end
- if not mark[t.info] then
- mark[t.info] = true
- for _, obj in ipairs(t.info) do
- search(obj)
- end
- end
- path[#path] = nil
- if addTarget then
- targets[addTarget] = true
- end
- end
-
- search(report)
-
- return result
-end
-
---- 生成一个报告
----@return string
-function m.report()
- local snapshot = m.snapshot()
- local cache = {}
- local mark = {}
-
- local function scan(t)
- local obj = t.info.object
- local tp = type(obj)
- if tp == 'table'
- or tp == 'userdata'
- or tp == 'function'
- or tp == 'string'
- or tp == 'thread' then
- local point = ('%p'):format(obj)
- if not cache[point] then
- cache[point] = {
- point = point,
- count = 0,
- name = formatName(obj),
- }
- end
- cache[point].count = cache[point].count + 1
- end
- if not mark[t.info] then
- mark[t.info] = true
- for _, child in ipairs(t.info) do
- scan(child)
- end
- end
- end
-
- scan(snapshot)
-
- local list = {}
- for _, info in next, cache do
- list[#list+1] = info
- end
- tableSort(list, function (a, b)
- return a.name < b.name
- end)
- return list
-end
-
-return m