diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2022-08-20 03:08:43 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2022-08-20 03:08:43 +0800 |
commit | 4af8144d6641ed03d42ea61d2dcdb402f2f6afbf (patch) | |
tree | c2a4c6f184755dd0f165c05a801e22bcebfa2e7c /script/lazy-cacher.lua | |
parent | b487d37819a5942d6807d2e9c338dd45557a6739 (diff) | |
download | lua-language-server-4af8144d6641ed03d42ea61d2dcdb402f2f6afbf.zip |
update lazy
Diffstat (limited to 'script/lazy-cacher.lua')
-rw-r--r-- | script/lazy-cacher.lua | 212 |
1 files changed, 153 insertions, 59 deletions
diff --git a/script/lazy-cacher.lua b/script/lazy-cacher.lua index e39cceff..963516f1 100644 --- a/script/lazy-cacher.lua +++ b/script/lazy-cacher.lua @@ -1,70 +1,164 @@ -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 +---@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 = io.open(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 = io.open(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 = math.max(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 = setmetatable({ + _dir = dir, + _opening = linkedTable(), + _openingMap = {}, + errorHandler = errorHandle, + }, mt) + return self end |