From 1b58a51e203d99cb8441c25044c8f8ed5bc63554 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Tue, 26 Nov 2024 12:10:12 +0100 Subject: [PATCH] perf: store data as blobs in sql cache (#3885) --- lib/cache/sqlite-cache-store.js | 41 +++---------------- .../cache-store-test-utils.js | 12 +++--- .../sqlite-cache-store-tests.js | 4 +- 3 files changed, 14 insertions(+), 43 deletions(-) diff --git a/lib/cache/sqlite-cache-store.js b/lib/cache/sqlite-cache-store.js index 964b118ee3d..3096f6da4d8 100644 --- a/lib/cache/sqlite-cache-store.js +++ b/lib/cache/sqlite-cache-store.js @@ -4,7 +4,7 @@ const { DatabaseSync } = require('node:sqlite') const { Writable } = require('stream') const { assertCacheKey, assertCacheValue } = require('../util/cache.js') -const VERSION = 2 +const VERSION = 3 /** * @typedef {import('../../types/cache-interceptor.d.ts').default.CacheStore} CacheStore @@ -17,7 +17,7 @@ const VERSION = 2 * body: string * } & import('../../types/cache-interceptor.d.ts').default.CacheValue} SqliteStoreValue */ -class SqliteCacheStore { +module.exports = class SqliteCacheStore { #maxEntrySize = Infinity #maxCount = Infinity @@ -103,7 +103,7 @@ class SqliteCacheStore { method TEXT NOT NULL, -- Data returned to the interceptor - body TEXT NULL, + body BUF NULL, deleteAt INTEGER NOT NULL, statusCode INTEGER NOT NULL, statusMessage TEXT NOT NULL, @@ -222,7 +222,7 @@ class SqliteCacheStore { * @type {import('../../types/cache-interceptor.d.ts').default.GetResult} */ const result = { - body: value.body ? parseBufferArray(JSON.parse(value.body)) : null, + body: Buffer.from(value.body), statusCode: value.statusCode, statusMessage: value.statusMessage, headers: value.headers ? JSON.parse(value.headers) : undefined, @@ -276,7 +276,7 @@ class SqliteCacheStore { if (existingValue) { // Updating an existing response, let's overwrite it store.#updateValueQuery.run( - JSON.stringify(stringifyBufferArray(body)), + Buffer.concat(body), value.deleteAt, value.statusCode, value.statusMessage, @@ -294,7 +294,7 @@ class SqliteCacheStore { store.#insertValueQuery.run( url, key.method, - JSON.stringify(stringifyBufferArray(body)), + Buffer.concat(body), value.deleteAt, value.statusCode, value.statusMessage, @@ -435,32 +435,3 @@ function headerValueEquals (lhs, rhs) { return lhs === rhs } - -/** - * @param {Buffer[]} buffers - * @returns {string[]} - */ -function stringifyBufferArray (buffers) { - const output = new Array(buffers.length) - for (let i = 0; i < buffers.length; i++) { - output[i] = buffers[i].toString() - } - - return output -} - -/** - * @param {string[]} strings - * @returns {Buffer[]} - */ -function parseBufferArray (strings) { - const output = new Array(strings.length) - - for (let i = 0; i < strings.length; i++) { - output[i] = Buffer.from(strings[i]) - } - - return output -} - -module.exports = SqliteCacheStore diff --git a/test/cache-interceptor/cache-store-test-utils.js b/test/cache-interceptor/cache-store-test-utils.js index 6ac6402980b..d56bedd4477 100644 --- a/test/cache-interceptor/cache-store-test-utils.js +++ b/test/cache-interceptor/cache-store-test-utils.js @@ -59,7 +59,7 @@ function cacheStoreTests (CacheStore) { ...requestValue, etag: undefined, cacheControlDirectives: {}, - body: requestBody + body: Buffer.concat(requestBody.map(x => Buffer.from(x))) }) // Now let's write another request to the store @@ -98,7 +98,7 @@ function cacheStoreTests (CacheStore) { ...anotherValue, etag: undefined, cacheControlDirectives: {}, - body: anotherBody + body: Buffer.concat(anotherBody.map(x => Buffer.from(x))) }) }) @@ -134,7 +134,7 @@ function cacheStoreTests (CacheStore) { ...requestValue, etag: undefined, cacheControlDirectives: {}, - body: requestBody + body: Buffer.concat(requestBody.map(x => Buffer.from(x))) }) }) @@ -209,7 +209,7 @@ function cacheStoreTests (CacheStore) { ...responseValue, etag: undefined, cacheControlDirectives: {}, - body: requestBody + body: Buffer.concat(requestBody.map(x => Buffer.from(x))) }) const nonMatchingRequest = { @@ -253,14 +253,14 @@ async function readResponse ({ body: src, ...response }) { */ const body = [] stream.on('data', chunk => { - body.push(chunk.toString()) + body.push(Buffer.from(chunk)) }) await once(stream, 'end') return { ...response, - body + body: Buffer.concat(body) } } diff --git a/test/cache-interceptor/sqlite-cache-store-tests.js b/test/cache-interceptor/sqlite-cache-store-tests.js index edbd62f72fe..308c8e3b8af 100644 --- a/test/cache-interceptor/sqlite-cache-store-tests.js +++ b/test/cache-interceptor/sqlite-cache-store-tests.js @@ -70,7 +70,7 @@ test('SqliteCacheStore works nicely with multiple stores', async (t) => { ...requestValue, etag: undefined, cacheControlDirectives: undefined, - body: requestBody + body: Buffer.concat(requestBody.map(x => Buffer.from(x))) }) // Make sure we got the expected response from store b @@ -80,7 +80,7 @@ test('SqliteCacheStore works nicely with multiple stores', async (t) => { ...requestValue, etag: undefined, cacheControlDirectives: undefined, - body: requestBody + body: Buffer.concat(requestBody.map(x => Buffer.from(x))) }) })