From 3b09c9e21709c61a01e0067e56e09522c916350e Mon Sep 17 00:00:00 2001 From: dtfiedler Date: Mon, 9 Sep 2024 16:40:55 -0600 Subject: [PATCH] chore(kv): create abstract `KvArnsStore` to handle the hashing keys for arns in cache This is to avoid doing it in the composite resolver --- src/init/resolvers.ts | 3 +- src/resolution/composite-arns-resolver.ts | 13 ++---- src/store/kv-arns-store.ts | 51 +++++++++++++++++++++++ src/system.ts | 15 ++++--- 4 files changed, 66 insertions(+), 16 deletions(-) create mode 100644 src/store/kv-arns-store.ts diff --git a/src/init/resolvers.ts b/src/init/resolvers.ts index 79771745..0045c1f5 100644 --- a/src/init/resolvers.ts +++ b/src/init/resolvers.ts @@ -23,6 +23,7 @@ import { AoIORead } from '@ar.io/sdk'; import { CompositeArNSResolver } from '../resolution/composite-arns-resolver.js'; import { RedisKvStore } from '../store/redis-kv-store.js'; import { NodeKvStore } from '../store/node-kv-store.js'; +import { KvArnsStore } from '../store/kv-arns-store.js'; const supportedResolvers = ['on-demand', 'gateway'] as const; export type ArNSResolverType = (typeof supportedResolvers)[number]; @@ -68,7 +69,7 @@ export const createArNSResolver = ({ networkProcess, }: { log: Logger; - cache: KVBufferStore; + cache: KvArnsStore; resolutionOrder: (ArNSResolverType | string)[]; trustedGatewayUrl?: string; networkProcess?: AoIORead; diff --git a/src/resolution/composite-arns-resolver.ts b/src/resolution/composite-arns-resolver.ts index a37d12c9..b9235f19 100644 --- a/src/resolution/composite-arns-resolver.ts +++ b/src/resolution/composite-arns-resolver.ts @@ -18,6 +18,7 @@ import winston from 'winston'; import { KVBufferStore, NameResolution, NameResolver } from '../types.js'; import * as metrics from '../metrics.js'; +import { KvArnsStore } from '../store/kv-arns-store.js'; export class CompositeArNSResolver implements NameResolver { private log: winston.Logger; @@ -31,22 +32,18 @@ export class CompositeArNSResolver implements NameResolver { }: { log: winston.Logger; resolvers: NameResolver[]; - cache: KVBufferStore; + cache: KvArnsStore; }) { this.log = log.child({ class: this.constructor.name }); this.resolvers = resolvers; this.cache = cache; } - private hashKey(key: string): string { - return `arns|${key}`; - } - async resolve(name: string): Promise { this.log.info('Resolving name...', { name }); try { - const cachedResolutionBuffer = await this.cache.get(this.hashKey(name)); + const cachedResolutionBuffer = await this.cache.get(name); if (cachedResolutionBuffer) { const cachedResolution: NameResolution = JSON.parse( cachedResolutionBuffer.toString(), @@ -73,9 +70,7 @@ export class CompositeArNSResolver implements NameResolver { }); const resolution = await resolver.resolve(name); if (resolution.resolvedId !== undefined) { - const hashKey = this.hashKey(name); - const resolutionBuffer = Buffer.from(JSON.stringify(resolution)); - await this.cache.set(hashKey, resolutionBuffer); + await this.cache.set(name, Buffer.from(JSON.stringify(resolution))); this.log.info('Resolved name', { name, resolution }); return resolution; } diff --git a/src/store/kv-arns-store.ts b/src/store/kv-arns-store.ts new file mode 100644 index 00000000..286f4a3a --- /dev/null +++ b/src/store/kv-arns-store.ts @@ -0,0 +1,51 @@ +/** + * AR.IO Gateway + * Copyright (C) 2022-2023 Permanent Data Solutions, Inc. All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { KVBufferStore } from '../types.js'; + +export class KvArnsStore implements KVBufferStore { + private kvBufferStore: KVBufferStore; + + constructor({ kvBufferStore }: { kvBufferStore: KVBufferStore }) { + this.kvBufferStore = kvBufferStore; + } + + private hashKey(key: string): string { + return `arns|${key}`; + } + + async get(key: string): Promise { + return this.kvBufferStore.get(this.hashKey(key)); + } + + async set(key: string, value: Buffer): Promise { + return this.kvBufferStore.set(this.hashKey(key), value); + } + + async has(key: string): Promise { + return this.kvBufferStore.has(this.hashKey(key)); + } + + async del(key: string): Promise { + return this.kvBufferStore.del(this.hashKey(key)); + } + + async close(): Promise { + return this.kvBufferStore.close(); + } +} diff --git a/src/system.ts b/src/system.ts index 9abfb4d6..fba134e5 100644 --- a/src/system.ts +++ b/src/system.ts @@ -81,6 +81,7 @@ import { connect } from '@permaweb/aoconnect'; import { DataContentAttributeImporter } from './workers/data-content-attribute-importer.js'; import { SignatureFetcher } from './data/signature-fetcher.js'; import { SQLiteWalCleanupWorker } from './workers/sqlite-wal-cleanup-worker.js'; +import { KvArnsStore } from './store/kv-arns-store.js'; process.on('uncaughtException', (error) => { metrics.uncaughtExceptionCounter.inc(); @@ -550,12 +551,14 @@ export const manifestPathResolver = new StreamingManifestPathResolver({ log, }); -export const arnsResolverCache = createArNSKvStore({ - log, - type: config.ARNS_CACHE_TYPE, - redisUrl: config.REDIS_CACHE_URL, - ttlSeconds: config.ARNS_CACHE_TTL_SECONDS, - maxKeys: config.ARNS_CACHE_MAX_KEYS, +export const arnsResolverCache = new KvArnsStore({ + kvBufferStore: createArNSKvStore({ + log, + type: config.ARNS_CACHE_TYPE, + redisUrl: config.REDIS_CACHE_URL, + ttlSeconds: config.ARNS_CACHE_TTL_SECONDS, + maxKeys: config.ARNS_CACHE_MAX_KEYS, + }), }); export const nameResolver = createArNSResolver({