Use an aging system for caches

This commit is contained in:
be5invis 2021-04-21 20:28:24 -07:00
parent d312466556
commit 0930af652f
11 changed files with 61 additions and 37 deletions

View file

@ -2,46 +2,65 @@
const fs = require("fs-extra");
const zlib = require("zlib");
const { encode, decode } = require("@msgpack/msgpack");
const Edition = 2;
const Edition = 3;
const MAX_AGE = 5;
class GfEntry {
constructor(age, value) {
this.age = age;
this.value = value;
}
}
class Cache {
constructor() {
this.gfSource = {};
this.gfSink = {};
this.gf = new Map();
}
loadRep(version, rep) {
if (!rep || rep.version !== version + "@" + Edition) return;
this.gfSource = rep.gf || {};
for (const [k, e] of Object.entries(rep.gf)) {
this.gf.set(k, new GfEntry((e.age || 0) + 1, e.value));
}
}
toRep(version) {
return { version: version + "@" + Edition, gf: this.gfSink };
let gfRep = {};
for (const [k, e] of this.gf) {
if (e.age < MAX_AGE) gfRep[k] = { age: e.age, value: e.value };
}
return { version: version + "@" + Edition, gf: gfRep };
}
// Geometry flattening conversion cache
getGF(ck) {
return this.gfSource[ck];
getGF(k) {
const entry = this.gf.get(k);
if (!entry) return undefined;
else return entry.value;
}
saveGF(ck, val) {
this.gfSink[ck] = val;
refreshGF(k) {
const entry = this.gf.get(k);
if (!entry) return;
entry.age = 0;
}
saveGF(k, v) {
this.gf.set(k, new GfEntry(0, v));
}
}
exports.load = async function (argv) {
let cache = new Cache();
if (argv.oCache && fs.existsSync(argv.oCache)) {
cache.loadRep(argv.menu.version, unzip(await fs.readFile(argv.oCache)));
const buf = zlib.gunzipSync(await fs.readFile(argv.oCache));
cache.loadRep(argv.menu.version, decode(buf));
}
return cache;
};
exports.save = async function savePTCache(argv, cache) {
if (argv.oCache) await fs.writeFile(argv.oCache, zip(cache.toRep(argv.menu.version)));
if (argv.oCache) {
const buf = encode(cache.toRep(argv.menu.version));
const bufZip = zlib.gzipSync(Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength));
await fs.writeFile(argv.oCache, bufZip);
}
};
function unzip(buf) {
return JSON.parse(zlib.gunzipSync(buf));
}
function zip(obj) {
return zlib.gzipSync(Buffer.from(JSON.stringify(obj), "utf-8"));
}

View file

@ -41,7 +41,7 @@ function flattenSimpleGlyph(cache, skew, g) {
if (ck && cached) {
g.clearGeometry();
g.includeContours(CurveUtil.repToShape(cached), 0, 0);
cache.saveGF(ck, cached);
cache.refreshGF(ck);
} else {
const tfBack = new Transform(1, -skew, 0, 1, 0, 0);
const tfForward = new Transform(1, +skew, 0, 1, 0, 0);

View file

@ -3,6 +3,7 @@
const fs = require("fs-extra");
const path = require("path");
const zlib = require("zlib");
const { encode } = require("@msgpack/msgpack");
const { FontIo } = require("ot-builder");
const Toml = require("@iarna/toml");
@ -103,12 +104,5 @@ async function saveCharMap(argv, glyphStore) {
...createGrDisplaySheet(glyphStore, gn)
]);
}
await fs.writeFile(argv.oCharMap, zip(charMap));
}
function unzip(buf) {
return JSON.parse(zlib.gunzipSync(buf));
}
function zip(obj) {
return zlib.gzipSync(Buffer.from(JSON.stringify(obj), "utf-8"));
await fs.writeFile(argv.oCharMap, zlib.gzipSync(encode(charMap)));
}

View file

@ -310,7 +310,7 @@ class BooleanGeometry extends GeometryBase {
exports.hashGeometry = function (geom) {
const s = geom.toShapeStringOrNull();
if (!s) return null;
return crypto.createHash("sha256").update(s).digest();
return crypto.createHash("sha256").update(s).digest("hex");
};
function combineWith(a, b) {

View file

@ -9,6 +9,7 @@
},
"dependencies": {
"@iarna/toml": "^2.2.5",
"@msgpack/msgpack": "^2.6.0",
"@unicode/unicode-13.0.0": "^1.0.4",
"cldr": "^6.0.0",
"ejs": "^3.1.6",

View file

@ -1,3 +1,5 @@
"use strict";
const fs = require("fs-extra");
const path = require("path");
const toml = require("@iarna/toml");

View file

@ -1,6 +1,9 @@
"use strict";
const cldr = require("cldr");
const fs = require("fs-extra");
const zlib = require("zlib");
const { decode } = require("@msgpack/msgpack");
const gatherCov = require("./coverage-export/gather-coverage-data");
@ -8,9 +11,9 @@ const gatherCov = require("./coverage-export/gather-coverage-data");
const overrideSupportedLanguages = [];
module.exports = async function (charMapPath, charMapItalicPath, charMapObliquePath) {
const charMap = await readJsonGz(charMapPath);
const charMapItalic = await readJsonGz(charMapItalicPath);
const charMapOblique = await readJsonGz(charMapObliquePath);
const charMap = await readMpCharMap(charMapPath);
const charMapItalic = await readMpCharMap(charMapItalicPath);
const charMapOblique = await readMpCharMap(charMapObliquePath);
const rawCoverage = getRawCoverage(charMap);
const rawCoverageItalic = getRawCoverage(charMapItalic);
@ -26,9 +29,8 @@ module.exports = async function (charMapPath, charMapItalicPath, charMapObliqueP
};
};
async function readJsonGz(p) {
const buf = await fs.readFile(p);
return JSON.parse(zlib.gunzipSync(buf).toString("utf-8"));
async function readMpCharMap(p) {
return decode(zlib.gunzipSync(await fs.readFile(p)));
}
function getSupportedLanguageSet(rawCoverage) {

View file

@ -1,3 +1,5 @@
"use strict";
const fs = require("fs");
module.exports = function (output, family, hs, formats) {

View file

@ -1,3 +1,5 @@
"use strict";
module.exports = function (main) {
setTimeout(
() =>

View file

@ -1,4 +1,5 @@
"use strict";
const fs = require("fs-extra");
const wawoff = require("wawoff2");

View file

@ -276,8 +276,9 @@ const DistUnhintedTTF = file.make(
async (target, out, gr, fn) => {
await target.need(Scripts, Parameters, Dependencies);
const charMapDir = `${BUILD}/ttf/${gr}`;
const charMapPath = `${charMapDir}/${fn}.cm.gz`;
const cachePath = `${charMapDir}/${fn}.cache.gz`;
const charMapPath = `${charMapDir}/${fn}.charmap.mpz`;
const cachePath = `${charMapDir}/${fn}.cache.mpz`;
const [fi] = await target.need(FontInfoOf(fn), de(out.dir), de(charMapDir));
echo.action(echo.hl.command(`Create TTF`), fn, echo.hl.operator("->"), out.full);
await silently.node("font-src/index", {
@ -290,7 +291,7 @@ const DistUnhintedTTF = file.make(
);
const BuildCM = file.make(
(gr, f) => `${BUILD}/ttf/${gr}/${f}.cm.gz`,
(gr, f) => `${BUILD}/ttf/${gr}/${f}.charmap.mpz`,
async (target, output, gr, f) => {
await target.need(DistUnhintedTTF(gr, f));
}