diff options
Diffstat (limited to 'script')
-rw-r--r-- | script/files.lua | 32 | ||||
-rw-r--r-- | script/lazy-cacher.lua | 219 | ||||
-rw-r--r-- | script/lazytable.lua | 106 | ||||
-rw-r--r-- | script/provider/diagnostic.lua | 3 | ||||
-rw-r--r-- | script/workspace/loading.lua | 11 | ||||
-rw-r--r-- | script/workspace/workspace.lua | 4 |
6 files changed, 228 insertions, 147 deletions
diff --git a/script/files.lua b/script/files.lua index 7a13e06a..c759f038 100644 --- a/script/files.lua +++ b/script/files.lua @@ -33,6 +33,7 @@ local sp = require 'bee.subprocess' ---@field id integer ---@class files +---@field lazyCache? lazy-cacher local m = {} m.watchList = {} @@ -477,6 +478,17 @@ function m.eachDll() return pairs(map) end +function m.getLazyCache() + if not m.lazyCache then + local cachePath = string.format('%s/cache/%d' + , LOGPATH + , sp.get_id() + ) + m.lazyCache = cacher(cachePath, log.error) + end + return m.lazyCache +end + function m.compileState(uri, text) local ws = require 'workspace' local client = require 'client' @@ -534,20 +546,12 @@ function m.compileState(uri, text) local file = m.fileMap[uri] if LAZY and not file.trusted then - local clock = os.clock() - local myCacheDir = string.format('%s/cache/%d' - , LOGPATH - , sp.get_id() - ) - local cachePath = string.format('%s/%d' - , myCacheDir - , file.id - ) - local cache = cacher(cachePath, log.error) - if cache then - state = lazy.build(state, cache.writter, cache.reader):entry() - end - local passed = os.clock() - clock + state.pushError = nil + local cache = m.getLazyCache() + local id = ('%d'):format(file.id) + clock = os.clock() + state = lazy.build(state, cache:writterAndReader(id)):entry() + passed = os.clock() - clock if passed > 0.1 then log.warn(('Convert lazy-table for [%s] takes [%.3f] sec, size [%.3f] kb.'):format(uri, passed, #text / 1000)) end diff --git a/script/lazy-cacher.lua b/script/lazy-cacher.lua index e39cceff..d6b29ba9 100644 --- a/script/lazy-cacher.lua +++ b/script/lazy-cacher.lua @@ -1,70 +1,171 @@ -local fs = require 'bee.filesystem' +local fs = require 'bee.filesystem' +local linkedTable = require 'linked-table' ----@param path string ----@param errorHandle? fun(string) ----@return table? -return function (path, errorHandle) - fs.create_directories(fs.path(path):parent_path()) - local f, err = io.open(path, 'a+b') - if not f then - if errorHandle then - errorHandle(err) - end - return nil +local setmt = setmetatable +local pairs = pairs +local iopen = io.open +local mmax = math.max + +_ENV = nil + +---@class lazy-cacher +---@field _opening linked-table +---@field _openingMap table<string, file*> +---@field _dir string +local mt = {} +mt.__index = mt +mt.type = 'lazy-cacher' + +mt.maxOpendFiles = 50 +mt.maxFileSize = 100 * 1024 * 1024 -- 100MB +mt.openingFiles = {} + +mt.errorHandler = function (err) end + +---@param fileID string +function mt:_closeFile(fileID) + self._opening:pop(fileID) + self._openingMap[fileID]:close() + self._openingMap[fileID] = nil +end + +---@param fileID string +---@return file*? +---@return string? errorMessage +function mt:_getFile(fileID) + if self._openingMap[fileID] then + self._opening:pop(fileID) + self._opening:pushTail(fileID) + return self._openingMap[fileID] end - local size, err = f:seek('end') - if not size then - if errorHandle then - errorHandle(err) - end - return nil + local fullPath = self._dir .. '/' .. fileID + local file, err = iopen(fullPath, 'a+b') + if not file then + return nil, err + end + self._opening:pushTail(fileID) + self._openingMap[fileID] = file + if self._opening:getSize() > self.maxOpendFiles then + local oldest = self._opening:getHead() + self:_closeFile(oldest) end + return file +end + +---@param fileID string +---@return fun(id: integer, code: string): boolean +---@return fun(id: integer): string? +function mt:writterAndReader(fileID) + local maxFileSize = self.maxFileSize local map = {} - return { - writter = function(id, code) - local offset, err = f:seek('end') - if not offset then - if errorHandle then - errorHandle(err) - end - return false - end - if not code then - map[id] = nil - return true - end - if #code > 1000000 then - return false - end - local suc, err = f:write(code) + ---@param file file* + local function resize(file) + local codes = {} + for id, data in pairs(map) do + local offset = data // 1000000 + local len = data % 1000000 + local suc, err = file:seek('set', offset) if not suc then - if errorHandle then - errorHandle(err) - end - return false + self.errorHandler(err) + return end + local code = file:read(len) + codes[id] = code + end + + self:_closeFile(fileID) + local fullPath = self._dir .. '/' .. fileID + local file, err = iopen(fullPath, 'wb') + if not file then + self.errorHandler(err) + return + end + + local offset = 0 + for id, code in pairs(codes) do + file:write(code) map[id] = offset * 1000000 + #code + offset = offset + #code + end + file:close() + end + ---@param id integer + ---@param code string + ---@return boolean + local function writter(id, code) + if not code then + map[id] = nil return true - end, - reader = function(id) - if not map[id] then - return nil + end + if #code > 1000000 then + return false + end + local file, err = self:_getFile(fileID) + if not file then + self.errorHandler(err) + return false + end + local offset, err = file:seek('end') + if not offset then + self.errorHandler(err) + return false + end + if offset > maxFileSize then + resize(file) + file, err = self:_getFile(fileID) + if not file then + self.errorHandler(err) + return false end - local offset = map[id] // 1000000 - local len = map[id] % 1000000 - local _, err = f:seek('set', offset) - if err then - if errorHandle then - errorHandle(err) - end - return nil + offset, err = file:seek('end') + if not offset then + self.errorHandler(err) + return false end - local code = f:read(len) - return code - end, - dispose = function () - f:close() - fs.remove(fs.path(path)) - end, - } + maxFileSize = mmax(maxFileSize, (offset + #code) * 2) + end + local suc, err = file:write(code) + if not suc then + self.errorHandler(err) + return false + end + map[id] = offset * 1000000 + #code + return true + end + ---@param id integer + ---@return string? + local function reader(id) + if not map[id] then + return nil + end + local file, err = self:_getFile(fileID) + if not file then + self.errorHandler(err) + return nil + end + local offset = map[id] // 1000000 + local len = map[id] % 1000000 + local suc, err = file:seek('set', offset) + if not suc then + self.errorHandler(err) + return nil + end + local code = file:read(len) + return code + end + return writter, reader +end + +---@param dir string +---@param errorHandle? fun(string) +---@return lazy-cacher? +return function (dir, errorHandle) + fs.create_directories(fs.path(dir)) + local self = setmt({ + _dir = dir, + _opening = linkedTable(), + _openingMap = {}, + errorHandler = errorHandle, + }, mt) + return self end diff --git a/script/lazytable.lua b/script/lazytable.lua index 9ac9c468..d162b4c8 100644 --- a/script/lazytable.lua +++ b/script/lazytable.lua @@ -1,3 +1,18 @@ +local type = type +local pairs = pairs +local error = error +local next = next +local load = load +local setmt = setmetatable +local rawset = rawset +local sdump = string.dump +local sbyte = string.byte +local smatch = string.match +local sformat = string.format +local tconcat = table.concat + +_ENV = nil + ---@class lazytable.builder ---@field source table ---@field codeMap table<integer, string> @@ -41,59 +56,21 @@ local RESERVED = { ---@return string local function formatKey(k) if type(k) == 'string' then - if not RESERVED[k] and k:match '^[%a_][%w_]*$' then + if not RESERVED[k] and smatch(k, '^[%a_][%w_]*$') then return k else - return ('[%q]'):format(k) + return sformat('[%q]', k) end end if type(k) == 'number' then - if math.type(k) == 'integer' then - local n10 = ('%d'):format(k) - local n16 = ('0x%X'):format(k) - if #n10 <= #n16 then - return '[' .. n10 .. ']' - else - return '[' .. n16 .. ']' - end - else - local n10 = ('%.16f'):format(k):gsub('0+$', '') - local n16 = ('%q'):format(k) - if #n10 <= #n16 then - return '[' .. n10 .. ']' - else - return '[' .. n16 .. ']' - end - end + return sformat('[%q]', k) end error('invalid key type: ' .. type(k)) end ---@param v string|number|boolean local function formatValue(v) - if type(v) == 'string' then - return ('%q'):format(v) - end - if type(v) == 'number' then - if math.type(v) == 'integer' then - local n10 = ('%d'):format(v) - local n16 = ('0x%X'):format(v) - if #n10 <= #n16 then - return n10 - else - return n16 - end - else - local n10 = ('%.16f'):format(v):gsub('0+$', '') - local n16 = ('%q'):format(v) - if #n10 <= #n16 then - return n10 - else - return n16 - end - end - end - return ('%q'):format(v) + return sformat('%q', v) end ---@param info {[1]: table, [2]: integer, [3]: table?} @@ -109,14 +86,14 @@ local function dump(info) else hasFields = true end - codeBuf[#codeBuf+1] = string.format('%s=%s' + codeBuf[#codeBuf+1] = sformat('%s=%s' , formatKey(k) , formatValue(v) ) end codeBuf[#codeBuf+1] = '}' - codeBuf[#codeBuf+1] = string.format(',%d', formatValue(info[2])) + codeBuf[#codeBuf+1] = sformat(',%d', formatValue(info[2])) if info[3] then codeBuf[#codeBuf+1] = ',{' @@ -127,7 +104,7 @@ local function dump(info) else hasFields = true end - codeBuf[#codeBuf+1] = string.format('%s=%s' + codeBuf[#codeBuf+1] = sformat('%s=%s' , formatKey(k) , formatValue(v) ) @@ -137,7 +114,7 @@ local function dump(info) codeBuf[#codeBuf + 1] = '}' - return table.concat(codeBuf) + return tconcat(codeBuf) end ---@param obj table|function|userdata|thread @@ -183,7 +160,7 @@ end ---@param writter fun(id: integer, code: string): boolean ---@param reader fun(id: integer): string? function mt:bind(writter, reader) - setmetatable(self.codeMap, { + setmt(self.codeMap, { __newindex = function (t, id, code) local suc = writter(id, code) if not suc then @@ -209,11 +186,6 @@ function mt:entry() local codeMap = self.codeMap local refMap = self.refMap local instMap = self.instMap - local load = load - local setmt = setmetatable - local sdump = string.dump - local type = type - local sbyte = string.byte local tableID = self.tableID ---@type table<table, integer> local idMap = {} @@ -230,9 +202,9 @@ function mt:entry() if not f then return nil end - if sbyte(code, 1, 1) ~= 27 then - codeMap[id] = sdump(f, true) - end + --if sbyte(code, 1, 1) ~= 27 then + -- codeMap[id] = sdump(f, true) + --end local info = f() map[t] = info return info @@ -268,12 +240,10 @@ function mt:entry() return instMap[ref] end, __newindex = function(t, k, v) - local info = infoMap[t] - if not info then - return - end - local fields = info[1] - local objs = info[3] + local info = infoMap[t] + local fields = info and info[1] or {} + local len = info and info[2] or 0 + local objs = info and info[3] fields[k] = nil if objs then objs[k] = nil @@ -286,7 +256,7 @@ function mt:entry() if not objs then objs = {} end - local id = refMap[v] + local id = refMap[v] or idMap[v] if not id then id = tableID refMap[v] = id -- 新赋值的对象一定会被引用住 @@ -296,11 +266,12 @@ function mt:entry() objs[k] = id end end - info = { fields, info[2], objs } + info = { fields, len, objs } local id = idMap[t] local code = dump(info) - codeMap[id] = code infoMap[id] = nil + codeMap[id] = nil + codeMap[id] = code end, __len = function (t) local info = infoMap[t] @@ -334,9 +305,9 @@ function mt:entry() end, } - setmetatable(idMap, { __mode = 'k' }) + setmt(idMap, { __mode = 'k' }) - setmetatable(instMap, { + setmt(instMap, { __mode = 'v', __index = function (map, id) local inst = {} @@ -350,6 +321,7 @@ function mt:entry() local entry = instMap[entryID] --[[@as table]] self.source = nil + self.dumpMark = nil return entry end @@ -362,7 +334,7 @@ local m = {} ---@param reader? fun(id: integer): string? ---@return lazytable.builder function m.build(t, writter, reader) - local builder = setmetatable({ + local builder = setmt({ source = t, codeMap = {}, refMap = {}, diff --git a/script/provider/diagnostic.lua b/script/provider/diagnostic.lua index 46ea600f..22287698 100644 --- a/script/provider/diagnostic.lua +++ b/script/provider/diagnostic.lua @@ -511,6 +511,9 @@ function m.diagnosticsScope(uri, force) m.clearAll() return end + if not force and config.get(uri, 'Lua.diagnostics.workspaceDelay') < 0 then + return + end local scp = scope.getScope(uri) local id = 'diagnosticsScope:' .. scp:getName() await.close(id) diff --git a/script/workspace/loading.lua b/script/workspace/loading.lua index 468e1908..9344949c 100644 --- a/script/workspace/loading.lua +++ b/script/workspace/loading.lua @@ -99,6 +99,7 @@ function mt:loadFile(uri, libraryUri) -- self._sets[#self._sets+1] = waker --end) files.setText(uri, content, false) + files.getState(uri) if not self._cache[uri] then files.addRef(uri) end @@ -147,9 +148,9 @@ function mt:loadFile(uri, libraryUri) end ---@async -function mt:loadAll() +function mt:loadAll(fileName) local startClock = os.clock() - log.info('Load files from disk:', self.scp:getName()) + log.info('Load files from disk:', fileName) while self.read < self.max do self:update() local loader = table.remove(self._stash) @@ -161,7 +162,7 @@ function mt:loadAll() end end local loadedClock = os.clock() - log.info(('Loaded files takes [%.3f] sec: %s'):format(loadedClock - startClock, self.scp:getName())) + log.info(('Loaded files takes [%.3f] sec: %s'):format(loadedClock - startClock, fileName)) self._bar:remove() self._bar = progress.create(self.scp.uri, lang.script('WORKSPACE_LOADING', self.scp.uri), 0) for i, set in ipairs(self._sets) do @@ -170,8 +171,8 @@ function mt:loadAll() self.read = i self:update() end - log.info(('Compile files takes [%.3f] sec: %s'):format(os.clock() - loadedClock, self.scp:getName())) - log.info('Loaded finish:', self.scp:getName()) + log.info(('Compile files takes [%.3f] sec: %s'):format(os.clock() - loadedClock, fileName)) + log.info('Loaded finish:', fileName) end function mt:remove() diff --git a/script/workspace/workspace.lua b/script/workspace/workspace.lua index 9d2ad637..1b94f389 100644 --- a/script/workspace/workspace.lua +++ b/script/workspace/workspace.lua @@ -269,7 +269,7 @@ function m.awaitLoadFile(uri) scp:get('cachedUris')[uri] = true ld:loadFile(uri) end) - ld:loadAll() + ld:loadAll(uri) end function m.removeFile(uri) @@ -346,7 +346,7 @@ function m.awaitPreload(scp) await.sleep(0.1) log.info(('Found %d files at:'):format(ld.max), scp:getName()) - ld:loadAll() + ld:loadAll(scp:getName()) log.info('Preload finish at:', scp:getName()) end |