Skip to main content
Glama
ssv445

Lorem Ipsum MCP Server

by ssv445
cache.ts22.1 kB
import type * as Cache from "../Cache.js" import type * as Clock from "../Clock.js" import * as Context from "../Context.js" import * as Deferred from "../Deferred.js" import * as Duration from "../Duration.js" import type * as Effect from "../Effect.js" import * as Either from "../Either.js" import * as Equal from "../Equal.js" import * as Exit from "../Exit.js" import type * as FiberId from "../FiberId.js" import { pipe } from "../Function.js" import * as Hash from "../Hash.js" import * as MutableHashMap from "../MutableHashMap.js" import * as MutableQueue from "../MutableQueue.js" import * as MutableRef from "../MutableRef.js" import * as Option from "../Option.js" import { hasProperty } from "../Predicate.js" import * as effect from "./core-effect.js" import * as core from "./core.js" import * as Data from "./data.js" import { none } from "./fiberId.js" import * as fiberRuntime from "./fiberRuntime.js" /** * A `MapValue` represents a value in the cache. A value may either be * `Pending` with a `Promise` that will contain the result of computing the * lookup function, when it is available, or `Complete` with an `Exit` value * that contains the result of computing the lookup function. * * @internal */ export type MapValue<Key, Value, Error> = | Complete<Key, Value, Error> | Pending<Key, Value, Error> | Refreshing<Key, Value, Error> /** @internal */ export interface Complete<out Key, out Value, out Error> { readonly _tag: "Complete" readonly key: MapKey<Key> readonly exit: Exit.Exit<Value, Error> readonly entryStats: Cache.EntryStats readonly timeToLiveMillis: number } /** @internal */ export interface Pending<out Key, in out Value, in out Error> { readonly _tag: "Pending" readonly key: MapKey<Key> readonly deferred: Deferred.Deferred<Value, Error> } /** @internal */ export interface Refreshing<out Key, in out Value, in out Error> { readonly _tag: "Refreshing" readonly deferred: Deferred.Deferred<Value, Error> readonly complete: Complete<Key, Value, Error> } /** @internal */ export const complete = <Key, Value, Error>( key: MapKey<Key>, exit: Exit.Exit<Value, Error>, entryStats: Cache.EntryStats, timeToLiveMillis: number ): MapValue<Key, Value, Error> => Data.struct({ _tag: "Complete" as const, key, exit, entryStats, timeToLiveMillis }) /** @internal */ export const pending = <Key, Value, Error>( key: MapKey<Key>, deferred: Deferred.Deferred<Value, Error> ): MapValue<Key, Value, Error> => Data.struct({ _tag: "Pending" as const, key, deferred }) /** @internal */ export const refreshing = <Key, Value, Error>( deferred: Deferred.Deferred<Value, Error>, complete: Complete<Key, Value, Error> ): MapValue<Key, Value, Error> => Data.struct({ _tag: "Refreshing" as const, deferred, complete }) /** @internal */ export const MapKeyTypeId = Symbol.for("effect/Cache/MapKey") /** @internal */ export type MapKeyTypeId = typeof MapKeyTypeId /** * A `MapKey` represents a key in the cache. It contains mutable references * to the previous key and next key in the `KeySet` to support an efficient * implementation of a sorted set of keys. * * @internal */ export interface MapKey<out K> extends Equal.Equal { readonly [MapKeyTypeId]: MapKeyTypeId readonly current: K previous: MapKey<K> | undefined // mutable by design next: MapKey<K> | undefined // mutable by design } class MapKeyImpl<out K> implements MapKey<K> { readonly [MapKeyTypeId]: MapKeyTypeId = MapKeyTypeId previous: MapKey<K> | undefined = undefined next: MapKey<K> | undefined = undefined constructor(readonly current: K) {} [Hash.symbol](): number { return pipe( Hash.hash(this.current), Hash.combine(Hash.hash(this.previous)), Hash.combine(Hash.hash(this.next)), Hash.cached(this) ) } [Equal.symbol](that: unknown): boolean { if (this === that) { return true } return isMapKey(that) && Equal.equals(this.current, that.current) && Equal.equals(this.previous, that.previous) && Equal.equals(this.next, that.next) } } /** @internal */ export const makeMapKey = <K>(current: K): MapKey<K> => new MapKeyImpl(current) /** @internal */ export const isMapKey = (u: unknown): u is MapKey<unknown> => hasProperty(u, MapKeyTypeId) /** * A `KeySet` is a sorted set of keys in the cache ordered by last access. * For efficiency, the set is implemented in terms of a doubly linked list * and is not safe for concurrent access. * * @internal */ export interface KeySet<in out K> { head: MapKey<K> | undefined // mutable by design tail: MapKey<K> | undefined // mutable by design /** * Adds the specified key to the set. */ add(key: MapKey<K>): void /** * Removes the lowest priority key from the set. */ remove(): MapKey<K> | undefined } class KeySetImpl<in out K> implements KeySet<K> { head: MapKey<K> | undefined = undefined tail: MapKey<K> | undefined = undefined add(key: MapKey<K>): void { if (key !== this.tail) { if (this.tail === undefined) { this.head = key this.tail = key } else { const previous = key.previous const next = key.next if (next !== undefined) { key.next = undefined if (previous !== undefined) { previous.next = next next.previous = previous } else { this.head = next this.head.previous = undefined } } this.tail.next = key key.previous = this.tail this.tail = key } } } remove(): MapKey<K> | undefined { const key = this.head if (key !== undefined) { const next = key.next if (next !== undefined) { key.next = undefined this.head = next this.head.previous = undefined } else { this.head = undefined this.tail = undefined } } return key } } /** @internal */ export const makeKeySet = <K>(): KeySet<K> => new KeySetImpl<K>() /** * The `CacheState` represents the mutable state underlying the cache. * * @internal */ export interface CacheState<in out Key, in out Value, in out Error> { map: MutableHashMap.MutableHashMap<Key, MapValue<Key, Value, Error>> // mutable by design keys: KeySet<Key> // mutable by design accesses: MutableQueue.MutableQueue<MapKey<Key>> // mutable by design updating: MutableRef.MutableRef<boolean> // mutable by design hits: number // mutable by design misses: number // mutable by design } /** * Constructs a new `CacheState` from the specified values. * * @internal */ export const makeCacheState = <Key, Value, Error>( map: MutableHashMap.MutableHashMap<Key, MapValue<Key, Value, Error>>, keys: KeySet<Key>, accesses: MutableQueue.MutableQueue<MapKey<Key>>, updating: MutableRef.MutableRef<boolean>, hits: number, misses: number ): CacheState<Key, Value, Error> => ({ map, keys, accesses, updating, hits, misses }) /** * Constructs an initial cache state. * * @internal */ export const initialCacheState = <Key, Value, Error>(): CacheState<Key, Value, Error> => makeCacheState( MutableHashMap.empty(), makeKeySet(), MutableQueue.unbounded(), MutableRef.make(false), 0, 0 ) /** @internal */ const CacheSymbolKey = "effect/Cache" /** @internal */ export const CacheTypeId: Cache.CacheTypeId = Symbol.for( CacheSymbolKey ) as Cache.CacheTypeId const cacheVariance = { /* c8 ignore next */ _Key: (_: any) => _, /* c8 ignore next */ _Error: (_: never) => _, /* c8 ignore next */ _Value: (_: any) => _ } /** @internal */ const ConsumerCacheSymbolKey = "effect/ConsumerCache" /** @internal */ export const ConsumerCacheTypeId: Cache.ConsumerCacheTypeId = Symbol.for( ConsumerCacheSymbolKey ) as Cache.ConsumerCacheTypeId const consumerCacheVariance = { /* c8 ignore next */ _Key: (_: any) => _, /* c8 ignore next */ _Error: (_: never) => _, /* c8 ignore next */ _Value: (_: never) => _ } /** @internal */ export const makeCacheStats = ( options: { readonly hits: number readonly misses: number readonly size: number } ): Cache.CacheStats => options /** @internal */ export const makeEntryStats = (loadedMillis: number): Cache.EntryStats => ({ loadedMillis }) class CacheImpl<in out Key, in out Value, in out Error> implements Cache.Cache<Key, Value, Error> { readonly [CacheTypeId] = cacheVariance readonly [ConsumerCacheTypeId] = consumerCacheVariance readonly cacheState: CacheState<Key, Value, Error> constructor( readonly capacity: number, readonly context: Context.Context<any>, readonly fiberId: FiberId.FiberId, readonly lookup: Cache.Lookup<Key, Value, Error, any>, readonly timeToLive: (exit: Exit.Exit<Value, Error>) => Duration.DurationInput ) { this.cacheState = initialCacheState() } get(key: Key): Effect.Effect<Value, Error> { return core.map(this.getEither(key), Either.merge) } get cacheStats(): Effect.Effect<Cache.CacheStats> { return core.sync(() => makeCacheStats({ hits: this.cacheState.hits, misses: this.cacheState.misses, size: MutableHashMap.size(this.cacheState.map) }) ) } getOption(key: Key): Effect.Effect<Option.Option<Value>, Error> { return core.suspend(() => Option.match(MutableHashMap.get(this.cacheState.map, key), { onNone: () => { const mapKey = makeMapKey(key) this.trackAccess(mapKey) this.trackMiss() return core.succeed(Option.none<Value>()) }, onSome: (value) => this.resolveMapValue(value) }) ) } getOptionComplete(key: Key): Effect.Effect<Option.Option<Value>> { return core.suspend(() => Option.match(MutableHashMap.get(this.cacheState.map, key), { onNone: () => { const mapKey = makeMapKey(key) this.trackAccess(mapKey) this.trackMiss() return core.succeed(Option.none<Value>()) }, onSome: (value) => this.resolveMapValue(value, true) as Effect.Effect<Option.Option<Value>> }) ) } contains(key: Key): Effect.Effect<boolean> { return core.sync(() => MutableHashMap.has(this.cacheState.map, key)) } entryStats(key: Key): Effect.Effect<Option.Option<Cache.EntryStats>> { return core.sync(() => { const option = MutableHashMap.get(this.cacheState.map, key) if (Option.isSome(option)) { switch (option.value._tag) { case "Complete": { const loaded = option.value.entryStats.loadedMillis return Option.some(makeEntryStats(loaded)) } case "Pending": { return Option.none() } case "Refreshing": { const loaded = option.value.complete.entryStats.loadedMillis return Option.some(makeEntryStats(loaded)) } } } return Option.none() }) } getEither(key: Key): Effect.Effect<Either.Either<Value, Value>, Error> { return core.suspend((): Effect.Effect<Either.Either<Value, Value>, Error> => { const k = key let mapKey: MapKey<Key> | undefined = undefined let deferred: Deferred.Deferred<Value, Error> | undefined = undefined let value = Option.getOrUndefined(MutableHashMap.get(this.cacheState.map, k)) if (value === undefined) { deferred = Deferred.unsafeMake<Value, Error>(this.fiberId) mapKey = makeMapKey(k) if (MutableHashMap.has(this.cacheState.map, k)) { value = Option.getOrUndefined(MutableHashMap.get(this.cacheState.map, k)) } else { MutableHashMap.set(this.cacheState.map, k, pending(mapKey, deferred)) } } if (value === undefined) { this.trackAccess(mapKey!) this.trackMiss() return core.map(this.lookupValueOf(key, deferred!), Either.right) } else { return core.flatMap( this.resolveMapValue(value), Option.match({ onNone: () => this.getEither(key), onSome: (value) => core.succeed(Either.left(value)) }) ) } }) } invalidate(key: Key): Effect.Effect<void> { return core.sync(() => { MutableHashMap.remove(this.cacheState.map, key) }) } invalidateWhen(key: Key, when: (value: Value) => boolean): Effect.Effect<void> { return core.sync(() => { const value = MutableHashMap.get(this.cacheState.map, key) if (Option.isSome(value) && value.value._tag === "Complete") { if (value.value.exit._tag === "Success") { if (when(value.value.exit.value)) { MutableHashMap.remove(this.cacheState.map, key) } } } }) } get invalidateAll(): Effect.Effect<void> { return core.sync(() => { this.cacheState.map = MutableHashMap.empty() }) } refresh(key: Key): Effect.Effect<void, Error> { return effect.clockWith((clock) => core.suspend(() => { const k = key const deferred: Deferred.Deferred<Value, Error> = Deferred.unsafeMake(this.fiberId) let value = Option.getOrUndefined(MutableHashMap.get(this.cacheState.map, k)) if (value === undefined) { if (MutableHashMap.has(this.cacheState.map, k)) { value = Option.getOrUndefined(MutableHashMap.get(this.cacheState.map, k)) } else { MutableHashMap.set(this.cacheState.map, k, pending(makeMapKey(k), deferred)) } } if (value === undefined) { return core.asVoid(this.lookupValueOf(key, deferred)) } else { switch (value._tag) { case "Complete": { if (this.hasExpired(clock, value.timeToLiveMillis)) { const found = Option.getOrUndefined(MutableHashMap.get(this.cacheState.map, k)) if (Equal.equals(found, value)) { MutableHashMap.remove(this.cacheState.map, k) } return core.asVoid(this.get(key)) } // Only trigger the lookup if we're still the current value, `completedResult` return pipe( this.lookupValueOf(key, deferred), effect.when(() => { const current = Option.getOrUndefined(MutableHashMap.get(this.cacheState.map, k)) if (Equal.equals(current, value)) { const mapValue = refreshing(deferred, value as Complete<Key, Value, Error>) MutableHashMap.set(this.cacheState.map, k, mapValue) return true } return false }), core.asVoid ) } case "Pending": { return Deferred.await(value.deferred) } case "Refreshing": { return Deferred.await(value.deferred) } } } }) ) } set(key: Key, value: Value): Effect.Effect<void> { return effect.clockWith((clock) => core.sync(() => { const now = clock.unsafeCurrentTimeMillis() const k = key const lookupResult = Exit.succeed(value) const mapValue = complete( makeMapKey(k), lookupResult, makeEntryStats(now), now + Duration.toMillis(Duration.decode(this.timeToLive(lookupResult))) ) MutableHashMap.set( this.cacheState.map, k, mapValue as Complete<Key, Value, Error> ) }) ) } get size(): Effect.Effect<number> { return core.sync(() => { return MutableHashMap.size(this.cacheState.map) }) } get values(): Effect.Effect<Array<Value>> { return core.sync(() => { const values: Array<Value> = [] for (const entry of this.cacheState.map) { if (entry[1]._tag === "Complete" && entry[1].exit._tag === "Success") { values.push(entry[1].exit.value) } } return values }) } get entries(): Effect.Effect<Array<[Key, Value]>> { return core.sync(() => { const values: Array<[Key, Value]> = [] for (const entry of this.cacheState.map) { if (entry[1]._tag === "Complete" && entry[1].exit._tag === "Success") { values.push([entry[0], entry[1].exit.value]) } } return values }) } get keys(): Effect.Effect<Array<Key>> { return core.sync(() => { const keys: Array<Key> = [] for (const entry of this.cacheState.map) { if (entry[1]._tag === "Complete" && entry[1].exit._tag === "Success") { keys.push(entry[0]) } } return keys }) } resolveMapValue( value: MapValue<Key, Value, Error>, ignorePending = false ): Effect.Effect<Option.Option<Value>, Error> { return effect.clockWith((clock) => { switch (value._tag) { case "Complete": { this.trackAccess(value.key) if (this.hasExpired(clock, value.timeToLiveMillis)) { MutableHashMap.remove(this.cacheState.map, value.key.current) return core.succeed(Option.none<Value>()) } this.trackHit() return core.map(value.exit, Option.some) } case "Pending": { this.trackAccess(value.key) this.trackHit() if (ignorePending) { return core.succeed(Option.none<Value>()) } return core.map(Deferred.await(value.deferred), Option.some) } case "Refreshing": { this.trackAccess(value.complete.key) this.trackHit() if (this.hasExpired(clock, value.complete.timeToLiveMillis)) { if (ignorePending) { return core.succeed(Option.none<Value>()) } return core.map(Deferred.await(value.deferred), Option.some) } return core.map(value.complete.exit, Option.some) } } }) } trackHit(): void { this.cacheState.hits = this.cacheState.hits + 1 } trackMiss(): void { this.cacheState.misses = this.cacheState.misses + 1 } trackAccess(key: MapKey<Key>): void { MutableQueue.offer(this.cacheState.accesses, key) if (MutableRef.compareAndSet(this.cacheState.updating, false, true)) { let loop = true while (loop) { const key = MutableQueue.poll(this.cacheState.accesses, MutableQueue.EmptyMutableQueue) if (key === MutableQueue.EmptyMutableQueue) { loop = false } else { this.cacheState.keys.add(key) } } let size = MutableHashMap.size(this.cacheState.map) loop = size > this.capacity while (loop) { const key = this.cacheState.keys.remove() if (key !== undefined) { if (MutableHashMap.has(this.cacheState.map, key.current)) { MutableHashMap.remove(this.cacheState.map, key.current) size = size - 1 loop = size > this.capacity } } else { loop = false } } MutableRef.set(this.cacheState.updating, false) } } hasExpired(clock: Clock.Clock, timeToLiveMillis: number): boolean { return clock.unsafeCurrentTimeMillis() > timeToLiveMillis } lookupValueOf( input: Key, deferred: Deferred.Deferred<Value, Error> ): Effect.Effect<Value, Error> { return effect.clockWith((clock) => core.suspend(() => { const key = input return pipe( this.lookup(input), core.provideContext(this.context), core.exit, core.flatMap((exit) => { const now = clock.unsafeCurrentTimeMillis() const stats = makeEntryStats(now) const value = complete( makeMapKey(key), exit, stats, now + Duration.toMillis(Duration.decode(this.timeToLive(exit))) ) MutableHashMap.set(this.cacheState.map, key, value) return core.zipRight( Deferred.done(deferred, exit), exit ) }), core.onInterrupt(() => core.zipRight( Deferred.interrupt(deferred), core.sync(() => { MutableHashMap.remove(this.cacheState.map, key) }) ) ) ) }) ) } } /** @internal */ export const make = <Key, Value, Error = never, Environment = never>( options: { readonly capacity: number readonly timeToLive: Duration.DurationInput readonly lookup: Cache.Lookup<Key, Value, Error, Environment> } ): Effect.Effect<Cache.Cache<Key, Value, Error>, never, Environment> => { const timeToLive = Duration.decode(options.timeToLive) return makeWith({ capacity: options.capacity, lookup: options.lookup, timeToLive: () => timeToLive }) } /** @internal */ export const makeWith = <Key, Value, Error = never, Environment = never>( options: { readonly capacity: number readonly lookup: Cache.Lookup<Key, Value, Error, Environment> readonly timeToLive: (exit: Exit.Exit<Value, Error>) => Duration.DurationInput } ): Effect.Effect<Cache.Cache<Key, Value, Error>, never, Environment> => core.map( fiberRuntime.all([core.context<Environment>(), core.fiberId]), ([context, fiberId]) => new CacheImpl( options.capacity, context, fiberId, options.lookup, (exit) => Duration.decode(options.timeToLive(exit)) ) ) /** @internal */ export const unsafeMakeWith = <Key, Value, Error = never>( capacity: number, lookup: Cache.Lookup<Key, Value, Error>, timeToLive: (exit: Exit.Exit<Value, Error>) => Duration.DurationInput ): Cache.Cache<Key, Value, Error> => new CacheImpl<Key, Value, Error>( capacity, Context.empty() as Context.Context<any>, none, lookup, (exit) => Duration.decode(timeToLive(exit)) )

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ssv445/lorem-ipsum-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server