renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
121 lines • 4.53 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SqlitePackageCache = void 0;
const tslib_1 = require("tslib");
const node_util_1 = require("node:util");
const node_zlib_1 = tslib_1.__importStar(require("node:zlib"));
const fs_extra_1 = require("fs-extra");
const upath_1 = tslib_1.__importDefault(require("upath"));
const expose_cjs_1 = require("../../../expose.cjs");
const logger_1 = require("../../../logger");
const fs_1 = require("../../fs");
const brotliCompress = (0, node_util_1.promisify)(node_zlib_1.default.brotliCompress);
const brotliDecompress = (0, node_util_1.promisify)(node_zlib_1.default.brotliDecompress);
function compress(input) {
const jsonStr = JSON.stringify(input);
return brotliCompress(jsonStr, {
params: {
[node_zlib_1.constants.BROTLI_PARAM_MODE]: node_zlib_1.constants.BROTLI_MODE_TEXT,
[node_zlib_1.constants.BROTLI_PARAM_QUALITY]: 3,
},
});
}
async function decompress(input) {
const buf = await brotliDecompress(input);
const jsonStr = buf.toString('utf8');
return JSON.parse(jsonStr);
}
class SqlitePackageCache {
client;
upsertStatement;
getStatement;
deleteExpiredRows;
countStatement;
static async init(cacheDir) {
// simply let it throw if it fails, so no test coverage needed
const Sqlite = (0, expose_cjs_1.sqlite)();
const sqliteDir = upath_1.default.join(cacheDir, 'renovate/renovate-cache-sqlite');
await (0, fs_1.ensureDir)(sqliteDir);
const sqliteFile = upath_1.default.join(sqliteDir, 'db.sqlite');
if (await (0, fs_extra_1.exists)(sqliteFile)) {
logger_1.logger.debug(`Using SQLite package cache: ${sqliteFile}`);
}
else {
logger_1.logger.debug(`Creating SQLite package cache: ${sqliteFile}`);
}
const client = new Sqlite(sqliteFile);
const res = new SqlitePackageCache(client);
return res;
}
constructor(client) {
this.client = client;
client.pragma('journal_mode = WAL');
client.pragma("encoding = 'UTF-8'");
client
.prepare(`
CREATE TABLE IF NOT EXISTS package_cache (
namespace TEXT NOT NULL,
key TEXT NOT NULL,
expiry INTEGER NOT NULL,
data BLOB NOT NULL,
PRIMARY KEY (namespace, key)
)
`)
.run();
client
.prepare('CREATE INDEX IF NOT EXISTS expiry ON package_cache (expiry)')
.run();
client
.prepare('CREATE INDEX IF NOT EXISTS namespace_key ON package_cache (namespace, key)')
.run();
this.upsertStatement = client.prepare(`
INSERT INTO package_cache (namespace, key, data, expiry)
VALUES (@namespace, @key, @data, unixepoch() + @ttlSeconds)
ON CONFLICT (namespace, key) DO UPDATE SET
data = @data,
expiry = unixepoch() + @ttlSeconds
`);
this.getStatement = client
.prepare(`
SELECT data FROM package_cache
WHERE
namespace = @namespace AND key = @key AND expiry > unixepoch()
`)
.pluck(true);
this.deleteExpiredRows = client.prepare(`
DELETE FROM package_cache
WHERE expiry <= unixepoch()
`);
this.countStatement = client
.prepare('SELECT COUNT(*) FROM package_cache')
.pluck(true);
}
async set(namespace, key, value, ttlMinutes = 5) {
const data = await compress(value);
const ttlSeconds = ttlMinutes * 60;
this.upsertStatement.run({ namespace, key, data, ttlSeconds });
return Promise.resolve();
}
async get(namespace, key) {
const data = this.getStatement.get({ namespace, key });
if (!data) {
return undefined;
}
return await decompress(data);
}
cleanupExpired() {
const start = Date.now();
const totalCount = this.countStatement.get();
const { changes: deletedCount } = this.deleteExpiredRows.run();
const finish = Date.now();
const durationMs = finish - start;
logger_1.logger.debug(`SQLite package cache: deleted ${deletedCount} of ${totalCount} entries in ${durationMs}ms`);
}
cleanup() {
this.cleanupExpired();
this.client.close();
return Promise.resolve();
}
}
exports.SqlitePackageCache = SqlitePackageCache;
//# sourceMappingURL=sqlite.js.map