From 7ecbcaaf68d152851591dbb5931a6eb15d155019 Mon Sep 17 00:00:00 2001 From: Hans Hagen Date: Mon, 25 Nov 2019 23:15:50 +0100 Subject: 2019-11-25 17:37:00 --- tex/context/base/mkiv/data-tmp.lua | 300 +++++++++++++++++++------------------ 1 file changed, 152 insertions(+), 148 deletions(-) (limited to 'tex/context/base/mkiv/data-tmp.lua') diff --git a/tex/context/base/mkiv/data-tmp.lua b/tex/context/base/mkiv/data-tmp.lua index ae7f65149..bfced1e64 100644 --- a/tex/context/base/mkiv/data-tmp.lua +++ b/tex/context/base/mkiv/data-tmp.lua @@ -7,29 +7,32 @@ if not modules then modules = { } end modules ['data-tmp'] = { } --[[ldx-- -

This module deals with caching data. It sets up the paths and -implements loaders and savers for tables. Best is to set the -following variable. When not set, the usual paths will be -checked. Personally I prefer the (users) temporary path.

+

This module deals with caching data. It sets up the paths and implements +loaders and savers for tables. Best is to set the following variable. When not +set, the usual paths will be checked. Personally I prefer the (users) temporary +path.

TEXMFCACHE=$TMP;$TEMP;$TMPDIR;$TEMPDIR;$HOME;$TEXMFVAR;$VARTEXMF;. -

Currently we do no locking when we write files. This is no real -problem because most caching involves fonts and the chance of them -being written at the same time is small. We also need to extend -luatools with a recache feature.

+

Currently we do no locking when we write files. This is no real problem +because most caching involves fonts and the chance of them being written at the +same time is small. We also need to extend luatools with a recache feature.

--ldx]]-- -local format, lower, gsub, concat = string.format, string.lower, string.gsub, table.concat ------ serialize, serializetofile = table.serialize, table.tofile -- overloaded so no local -local concat = table.concat -local mkdirs, isdir, isfile = dir.mkdirs, lfs.isdir, lfs.isfile -local addsuffix, is_writable, is_readable = file.addsuffix, file.is_writable, file.is_readable -local formatters = string.formatters local next, type = next, type ------ pcall, loadfile = pcall, loadfile +local pcall, loadfile, collectgarbage = pcall, loadfile, collectgarbage +local format, lower, gsub = string.format, string.lower, string.gsub +local concat, serialize, fastserialize, serializetofile = table.concat, table.serialize, table.fastserialize, table.tofile +local mkdirs, expanddirname, isdir, isfile = dir.mkdirs, dir.expandname, lfs.isdir, lfs.isfile +local is_writable, is_readable = file.is_writable, file.is_readable +local collapsepath, joinfile, addsuffix, dirname = file.collapsepath, file.join, file.addsuffix, file.dirname +local savedata = file.savedata +local formatters = string.formatters +local osexit, osdate, osuuid = os.exit, os.date, os.uuid +local removefile = os.remove +local md5hex = md5.hex local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end) local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end) @@ -37,45 +40,80 @@ local trace_cache = false trackers.register("resolvers.cache", function(v local report_caches = logs.reporter("resolvers","caches") local report_resolvers = logs.reporter("resolvers","caching") -local resolvers = resolvers -local cleanpath = resolvers.cleanpath +local resolvers = resolvers +local cleanpath = resolvers.cleanpath +local resolvepath = resolvers.resolve + +local luautilities = utilities.lua -- intermezzo -local directive_cleanup = false directives.register("system.compile.cleanup", function(v) directive_cleanup = v end) -local directive_strip = false directives.register("system.compile.strip", function(v) directive_strip = v end) +do + + local directive_cleanup = false directives.register("system.compile.cleanup", function(v) directive_cleanup = v end) + local directive_strip = false directives.register("system.compile.strip", function(v) directive_strip = v end) -local compile = utilities.lua.compile + local compilelua = luautilities.compile + + function luautilities.compile(luafile,lucfile,cleanup,strip) + if cleanup == nil then cleanup = directive_cleanup end + if strip == nil then strip = directive_strip end + return compilelua(luafile,lucfile,cleanup,strip) + end -function utilities.lua.compile(luafile,lucfile,cleanup,strip) - if cleanup == nil then cleanup = directive_cleanup end - if strip == nil then strip = directive_strip end - return compile(luafile,lucfile,cleanup,strip) end -- end of intermezzo -caches = caches or { } -local caches = caches +caches = caches or { } +local caches = caches +local writable = nil +local readables = { } +local usedreadables = { } -local luasuffixes = utilities.lua.suffixes +local compilelua = luautilities.compile +local luasuffixes = luautilities.suffixes -caches.base = caches.base or "luatex-cache" -caches.more = caches.more or "context" -caches.direct = false -- true is faster but may need huge amounts of memory -caches.tree = false -caches.force = true -caches.ask = false -caches.relocate = false -caches.defaults = { "TMPDIR", "TEMPDIR", "TMP", "TEMP", "HOME", "HOMEPATH" } +caches.base = caches.base or "luatex-cache" -- can be local +caches.more = caches.more or "context" -- can be local +caches.defaults = { "TMPDIR", "TEMPDIR", "TMP", "TEMP", "HOME", "HOMEPATH" } -directives.register("system.caches.fast", function(v) caches.fast = true end) -directives.register("system.caches.direct",function(v) caches.direct = true end) +local direct_cache = false -- true is faster but may need huge amounts of memory +local fast_cache = false +local cache_tree = false -local writable, readables, usedreadables = nil, { }, { } +directives.register("system.caches.direct",function(v) direct_cache = true end) +directives.register("system.caches.fast", function(v) fast_cache = true end) -- we could use a metatable for writable and readable but not yet +local function configfiles() + return concat(resolvers.configurationfiles(),";") +end + +local function hashed(tree) + tree = gsub(tree,"[\\/]+$","") + tree = lower(tree) + local hash = md5hex(tree) + if trace_cache or trace_locating then + report_caches("hashing tree %a, hash %a",tree,hash) + end + return hash +end + +local function treehash() + local tree = configfiles() + if not tree or tree == "" then + return false + else + return hashed(tree) + end +end + +caches.hashed = hashed +caches.treehash = treehash +caches.configfiles = configfiles + local function identify() -- Combining the loops makes it messy. First we check the format cache path -- and when the last component is not present we try to create it. @@ -84,9 +122,9 @@ local function identify() for k=1,#texmfcaches do local cachepath = texmfcaches[k] if cachepath ~= "" then - cachepath = resolvers.resolve(cachepath) - cachepath = resolvers.cleanpath(cachepath) - cachepath = file.collapsepath(cachepath) + cachepath = resolvepath(cachepath) + cachepath = cleanpath(cachepath) + cachepath = collapsepath(cachepath) local valid = isdir(cachepath) if valid then if is_readable(cachepath) then @@ -95,16 +133,14 @@ local function identify() writable = cachepath end end - elseif not writable and caches.force then - local cacheparent = file.dirname(cachepath) - if is_writable(cacheparent) and true then -- we go on anyway (needed for mojca's kind of paths) - if not caches.ask or io.ask(format("\nShould I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then - mkdirs(cachepath) - if isdir(cachepath) and is_writable(cachepath) then - report_caches("path %a created",cachepath) - writable = cachepath - readables[#readables+1] = cachepath - end + elseif not writable then + local cacheparent = dirname(cachepath) + if is_writable(cacheparent) then -- we go on anyway (needed for mojca's kind of paths) + mkdirs(cachepath) + if isdir(cachepath) and is_writable(cachepath) then + report_caches("path %a created",cachepath) + writable = cachepath + readables[#readables+1] = cachepath end end end @@ -119,8 +155,8 @@ local function identify() local cachepath = texmfcaches[k] cachepath = resolvers.expansion(cachepath) -- was getenv if cachepath ~= "" then - cachepath = resolvers.resolve(cachepath) - cachepath = resolvers.cleanpath(cachepath) + cachepath = resolvepath(cachepath) + cachepath = cleanpath(cachepath) local valid = isdir(cachepath) if valid and is_readable(cachepath) then if not writable and is_writable(cachepath) then @@ -136,25 +172,27 @@ local function identify() -- quit. if not writable then report_caches("fatal error: there is no valid writable cache path defined") - os.exit() + osexit() elseif #readables == 0 then report_caches("fatal error: there is no valid readable cache path defined") - os.exit() + osexit() end -- why here - writable = dir.expandname(resolvers.cleanpath(writable)) -- just in case - -- moved here - local base, more, tree = caches.base, caches.more, caches.tree or caches.treehash() -- we have only one writable tree + writable = expanddirname(cleanpath(writable)) -- just in case + -- moved here ( we have only one writable tree) + local base = caches.base + local more = caches.more + local tree = cache_tree or treehash() -- we have only one writable tree if tree then - caches.tree = tree + cache_tree = tree writable = mkdirs(writable,base,more,tree) for i=1,#readables do - readables[i] = file.join(readables[i],base,more,tree) + readables[i] = joinfile(readables[i],base,more,tree) end else writable = mkdirs(writable,base,more) for i=1,#readables do - readables[i] = file.join(readables[i],base,more) + readables[i] = joinfile(readables[i],base,more) end end -- end @@ -194,30 +232,8 @@ function caches.usedpaths(separator) end end -function caches.configfiles() - return concat(resolvers.configurationfiles(),";") -end - -function caches.hashed(tree) - tree = gsub(tree,"[\\/]+$","") - tree = lower(tree) - local hash = md5.hex(tree) - if trace_cache or trace_locating then - report_caches("hashing tree %a, hash %a",tree,hash) - end - return hash -end - -function caches.treehash() - local tree = caches.configfiles() - if not tree or tree == "" then - return false - else - return caches.hashed(tree) - end -end - -local r_cache, w_cache = { }, { } -- normally w in in r but who cares +local r_cache = { } +local w_cache = { } local function getreadablepaths(...) local tags = { ... } @@ -228,7 +244,7 @@ local function getreadablepaths(...) if #tags > 0 then done = { } for i=1,#readables do - done[i] = file.join(readables[i],...) + done[i] = joinfile(readables[i],...) end else done = readables @@ -254,31 +270,21 @@ local function getwritablepath(...) return done end -caches.getreadablepaths = getreadablepaths -caches.getwritablepath = getwritablepath - --- this can be tricky as we can have a pre-generated format while at the same time --- use e.g. a home path where we have updated file databases and so maybe we need --- to check first if we do have a writable one - --- function caches.getfirstreadablefile(filename,...) --- local rd = getreadablepaths(...) --- for i=1,#rd do --- local path = rd[i] --- local fullname = file.join(path,filename) --- if is_readable(fullname) then --- usedreadables[i] = true --- return fullname, path --- end --- end --- return caches.setfirstwritablefile(filename,...) --- end +local function setfirstwritablefile(filename,...) + local wr = getwritablepath(...) + local fullname = joinfile(wr,filename) + return fullname, wr +end --- next time we have an issue, we can test this instead: +local function setluanames(path,name) + return + format("%s/%s.%s",path,name,luasuffixes.tma), + format("%s/%s.%s",path,name,luasuffixes.tmc) +end -function caches.getfirstreadablefile(filename,...) +local function getfirstreadablefile(filename,...) -- check if we have already written once - local fullname, path = caches.setfirstwritablefile(filename,...) + local fullname, path = setfirstwritablefile(filename,...) if is_readable(fullname) then return fullname, path -- , true end @@ -286,7 +292,7 @@ function caches.getfirstreadablefile(filename,...) local rd = getreadablepaths(...) for i=1,#rd do local path = rd[i] - local fullname = file.join(path,filename) + local fullname = joinfile(path,filename) if is_readable(fullname) then usedreadables[i] = true return fullname, path -- , false @@ -296,21 +302,19 @@ function caches.getfirstreadablefile(filename,...) return fullname, path -- , true end -function caches.setfirstwritablefile(filename,...) - local wr = getwritablepath(...) - local fullname = file.join(wr,filename) - return fullname, wr -end - -function caches.define(category,subcategory) -- not used - return function() - return getwritablepath(category,subcategory) - end -end +caches.getreadablepaths = getreadablepaths +caches.getwritablepath = getwritablepath +caches.setfirstwritablefile = setfirstwritablefile +caches.getfirstreadablefile = getfirstreadablefile +caches.setluanames = setluanames -function caches.setluanames(path,name) - return format("%s/%s.%s",path,name,luasuffixes.tma), format("%s/%s.%s",path,name,luasuffixes.tmc) -end +-- -- not used: +-- +-- function caches.define(category,subcategory) +-- return function() +-- return getwritablepath(category,subcategory) +-- end +-- end -- This works best if the first writable is the first readable too. In practice -- we can have these situations for file databases: @@ -328,17 +332,17 @@ function caches.loaddata(readables,name,writable) local path = readables[i] local loader = false local state = false - local tmaname, tmcname = caches.setluanames(path,name) + local tmaname, tmcname = setluanames(path,name) if isfile(tmcname) then state, loader = pcall(loadfile,tmcname) end if not loader and isfile(tmaname) then -- can be different paths when we read a file database from disk - local tmacrap, tmcname = caches.setluanames(writable,name) + local tmacrap, tmcname = setluanames(writable,name) if isfile(tmcname) then state, loader = pcall(loadfile,tmcname) end - utilities.lua.compile(tmaname,tmcname) + compilelua(tmaname,tmcname) if isfile(tmcname) then state, loader = pcall(loadfile,tmcname) end @@ -356,23 +360,23 @@ function caches.loaddata(readables,name,writable) end function caches.is_writable(filepath,filename) - local tmaname, tmcname = caches.setluanames(filepath,filename) + local tmaname, tmcname = setluanames(filepath,filename) return is_writable(tmaname) end local saveoptions = { compact = true } -function caches.savedata(filepath,filename,data) - local tmaname, tmcname = caches.setluanames(filepath,filename) - data.cache_uuid = os.uuid() - if caches.fast then - file.savedata(tmaname,table.fastserialize(data,true)) - elseif caches.direct then - file.savedata(tmaname,table.serialize(data,true,saveoptions)) +function caches.savedata(filepath,filename,data,fast) + local tmaname, tmcname = setluanames(filepath,filename) + data.cache_uuid = osuuid() + if fast or fast_cache then + savedata(tmaname,fastserialize(data,true)) + elseif direct_cache then + savedata(tmaname,serialize(data,true,saveoptions)) else - table.tofile(tmaname,data,true,saveoptions) + serializetofile(tmaname,data,true,saveoptions) end - utilities.lua.compile(tmaname,tmcname) + compilelua(tmaname,tmcname) end -- moved from data-res: @@ -385,9 +389,9 @@ end function caches.loadcontent(cachename,dataname,filename) if not filename then - local name = caches.hashed(cachename) - local full, path = caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") - filename = file.join(path,name) + local name = hashed(cachename) + local full, path = getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") + filename = joinfile(path,name) end local state, blob = pcall(loadfile,addsuffix(filename,luasuffixes.luc)) if not blob then @@ -427,9 +431,9 @@ end function caches.savecontent(cachename,dataname,content,filename) if not filename then - local name = caches.hashed(cachename) - local full, path = caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") - filename = file.join(path,name) -- is full + local name = hashed(cachename) + local full, path = setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") + filename = joinfile(path,name) -- is full end local luaname = addsuffix(filename,luasuffixes.lua) local lucname = addsuffix(filename,luasuffixes.luc) @@ -440,17 +444,17 @@ function caches.savecontent(cachename,dataname,content,filename) type = dataname, root = cachename, version = resolvers.cacheversion, - date = os.date("%Y-%m-%d"), - time = os.date("%H:%M:%S"), + date = osdate("%Y-%m-%d"), + time = osdate("%H:%M:%S"), content = content, - uuid = os.uuid(), + uuid = osuuid(), } - local ok = io.savedata(luaname,table.serialize(data,true)) + local ok = savedata(luaname,serialize(data,true)) if ok then if trace_locating then report_resolvers("category %a, cachename %a saved in %a",dataname,cachename,luaname) end - if utilities.lua.compile(luaname,lucname) then + if compilelua(luaname,lucname) then if trace_locating then report_resolvers("%a compiled to %a",dataname,lucname) end @@ -459,7 +463,7 @@ function caches.savecontent(cachename,dataname,content,filename) if trace_locating then report_resolvers("compiling failed for %a, deleting file %a",dataname,lucname) end - os.remove(lucname) + removefile(lucname) end elseif trace_locating then report_resolvers("unable to save %a in %a (access error)",dataname,luaname) -- cgit v1.2.3