Memorelay: do some premature optimizations

This commit is contained in:
Alex Gleason 2024-01-03 18:48:11 -06:00
parent c235fa6123
commit 48ce1ba6c9
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
1 changed files with 44 additions and 16 deletions

View File

@ -1,4 +1,4 @@
import { Debug, type Event, type Filter, LRUCache, matchFilter, matchFilters } from '@/deps.ts'; import { Debug, type Event, type Filter, LRUCache, matchFilter } from '@/deps.ts';
import { normalizeFilters } from '@/filter.ts'; import { normalizeFilters } from '@/filter.ts';
import { type EventStore, type GetEventsOpts } from '@/store.ts'; import { type EventStore, type GetEventsOpts } from '@/store.ts';
@ -27,32 +27,62 @@ class Memorelay implements EventStore {
/** Get events from memory. */ /** Get events from memory. */
getEvents<K extends number>(filters: Filter<K>[], opts: GetEventsOpts = {}): Promise<Event<K>[]> { getEvents<K extends number>(filters: Filter<K>[], opts: GetEventsOpts = {}): Promise<Event<K>[]> {
if (opts.signal?.aborted) return Promise.resolve([]);
filters = normalizeFilters(filters); filters = normalizeFilters(filters);
if (opts.signal?.aborted) return Promise.resolve([]);
if (!filters.length) return Promise.resolve([]); if (!filters.length) return Promise.resolve([]);
this.#debug('REQ', JSON.stringify(filters)); this.#debug('REQ', JSON.stringify(filters));
/** Event results to return. */
const results: Event<K>[] = []; const results: Event<K>[] = [];
const usages: number[] = [];
/** Number of times an event has been added to results for each filter. */
const filterUsages: number[] = [];
/** Check if all filters have been satisfied. */
function checkSatisfied() {
return results.length >= (opts.limit ?? Infinity) ||
filters.every((filter, index) => filter.limit && (filterUsages[index] >= filter.limit));
}
// Optimize for filters with IDs.
filters.forEach((filter, index) => {
if (filter.ids) {
for (const id of filter.ids) {
const event = this.#cache.get(id);
if (event && matchFilter(filter, event)) {
results.push(event as Event<K>);
}
}
filterUsages[index] = Infinity;
}
});
// Return early if all filters are satisfied.
if (checkSatisfied()) {
return Promise.resolve(results);
}
// Seek through all events in memory.
for (const event of this.#events()) { for (const event of this.#events()) {
let index = 0; filters.forEach((filter, index) => {
for (const filter of filters) {
const limit = filter.limit ?? Infinity; const limit = filter.limit ?? Infinity;
const usage = usages[index] ?? 0; const usage = filterUsages[index] ?? 0;
if (usage >= limit) { if (usage >= limit) {
continue; return;
} else if (matchFilter(filter, event)) { } else if (matchFilter(filter, event)) {
results.push(event as Event<K>); results.push(event as Event<K>);
usages[index] = usage + 1; this.#cache.get(event.id);
filterUsages[index] = usage + 1;
} }
index++; index++;
} });
if (filters.every((filter, index) => filter.limit && (usages[index] >= filter.limit))) { // Check after each event if we can return.
if (checkSatisfied()) {
break; break;
} }
} }
@ -73,11 +103,9 @@ class Memorelay implements EventStore {
} }
/** Delete events from memory. */ /** Delete events from memory. */
deleteEvents(filters: Filter[]): Promise<void> { async deleteEvents(filters: Filter[]): Promise<void> {
for (const event of this.#events()) { for (const event of await this.getEvents(filters)) {
if (matchFilters(filters, event)) { this.#cache.delete(event.id);
this.#cache.delete(event.id);
}
} }
return Promise.resolve(); return Promise.resolve();
} }