Skip to content

Instantly share code, notes, and snippets.

@eliassjogreen
Created May 16, 2023 22:16
Show Gist options
  • Save eliassjogreen/33d3473fae0d6e437a3b4aef14e5a540 to your computer and use it in GitHub Desktop.
Save eliassjogreen/33d3473fae0d6e437a3b4aef14e5a540 to your computer and use it in GitHub Desktop.
Deno.Kv deque
// Copyright 2023 denosaurs. All rights reserved. MIT license.
async function getEdgeEntry(kv: Deno.Kv, queue: string, back: boolean) {
return (
await kv.list({ prefix: [queue] }, { limit: 1, reverse: back }).next()
).value;
}
async function atomicRetry(op: Deno.AtomicOperation) {
let success = false;
while (!success) {
try {
success = (await op.commit()).ok;
} catch {
success = false;
}
}
}
export async function pushBack(kv: Deno.Kv, queue: string, value: unknown) {
const neighbour = await getEdgeEntry(kv, queue, true);
await atomicRetry(
kv
.atomic()
.set(
[queue, ((neighbour?.key?.[1] as bigint | undefined) ?? 0n) + 1n],
value,
),
);
}
export async function pushFront(kv: Deno.Kv, queue: string, value: unknown) {
const neighbour = await getEdgeEntry(kv, queue, false);
await atomicRetry(
kv
.atomic()
.set(
[queue, ((neighbour?.key?.[1] as bigint | undefined) ?? 0n) - 1n],
value,
),
);
}
export async function popBack(
kv: Deno.Kv,
queue: string,
): Promise<unknown | undefined> {
const entry = await getEdgeEntry(kv, queue, true);
if (entry?.key) {
await atomicRetry(kv.atomic().check(entry).delete(entry.key));
}
return entry?.value;
}
export async function popFront(
kv: Deno.Kv,
queue: string,
): Promise<unknown | undefined> {
const entry = await getEdgeEntry(kv, queue, false);
if (entry?.key) {
await atomicRetry(kv.atomic().check(entry).delete(entry.key));
}
return entry?.value;
}
export async function peekBack(
kv: Deno.Kv,
queue: string,
): Promise<unknown | undefined> {
return (await getEdgeEntry(kv, queue, true))?.value;
}
export async function peekFront(
kv: Deno.Kv,
queue: string,
): Promise<unknown | undefined> {
return (await getEdgeEntry(kv, queue, false))?.value;
}
export class KvDeque<T> {
#kv: Deno.Kv;
#name: string;
get name() {
return this.#name;
}
constructor(kv: Deno.Kv, name: string) {
this.#kv = kv;
this.#name = name;
}
async pushBack(value: T) {
return await pushBack(this.#kv, this.#name, value);
}
async pushFront(value: T) {
return await pushFront(this.#kv, this.#name, value);
}
async popBack(): Promise<T | undefined> {
return (await popBack(this.#kv, this.#name)) as T | undefined;
}
async popFront(): Promise<T | undefined> {
return (await popFront(this.#kv, this.#name)) as T | undefined;
}
async peekBack(): Promise<T | undefined> {
return (await peekBack(this.#kv, this.#name)) as T | undefined;
}
async peekFront(): Promise<T | undefined> {
return (await peekFront(this.#kv, this.#name)) as T | undefined;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment