Skip to content

Commit

Permalink
Revive unsynced sessions 1/n
Browse files Browse the repository at this point in the history
  • Loading branch information
AriaMinaei committed Nov 14, 2023
1 parent d20d24a commit 23f9f91
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 75 deletions.
24 changes: 21 additions & 3 deletions packages/saaz/src/front/FrontIdbAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,13 @@ export class FrontIDBAdapter implements FrontStorageAdapter {
keyPath: 'sessionAndKey',
})

singularValueStore.createIndex('session', 'session')

const listsStore = db.createObjectStore('lists', {
keyPath: 'sessionAndKeyAndId',
})

listsStore.createIndex('session', 'session')
listsStore.createIndex('sessionAndKey', 'sessionAndKey')
},
})
Expand Down Expand Up @@ -79,6 +82,19 @@ class IDBTransaction implements FrontStorageAdapterTransaction {
return v?.value
}

async getAll<T>(key: string): Promise<Record<string, T>> {
const index = this._tx.objectStore('singularValues').index('session')
const all: Array<SingularValue<T>> = await index.getAll()

const record: Record<string, T> = {}

for (const row of all) {
record[row.session] = row.value
}

return record
}

async set<T>(key: string, value: T, session: string): Promise<void> {
const sessionAndKey = `${session}/${key}`
const store = this._tx.objectStore('singularValues')
Expand Down Expand Up @@ -125,9 +141,11 @@ class IDBTransaction implements FrontStorageAdapterTransaction {
session: string,
): Promise<T[]> {
const store = this._tx.objectStore('lists')
const keyIndex = store.index('keyAndSession')
const keyAndSession = `${session}/${key}`
return (await keyIndex.getAll(keyAndSession)) as T[]
const keyIndex = store.index('sessionAndKey')
const sessionAndKey = `${session}/${key}`
const all = await keyIndex.getAll(sessionAndKey)

return all.map((s) => s.value)
}

async pluckFromList<T extends {id: string}>(
Expand Down
15 changes: 15 additions & 0 deletions packages/saaz/src/front/FrontMemoryAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,21 @@ class Transaction implements FrontStorageAdapterTransaction {
s.keyval[key] = value
}

async getAll<T>(key: string): Promise<Record<string, T>> {
const vals: Record<string, T> = {}

for (const [sessionId, v] of Object.entries(this._draft.sessions)) {
if (!v) continue
if (Object.hasOwn(v.keyval, key)) {
const value: T | undefined = v.keyval[key] as $IntentionalAny
if (value === undefined) continue
vals[sessionId] = value
}
}

return vals
}

async pushToList<T extends {id: string}>(
key: string,
rows: T[],
Expand Down
75 changes: 53 additions & 22 deletions packages/saaz/src/front/FrontStorage.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type {
$IntentionalAny,
BackState,
SessionState,
FrontStorageAdapterTransaction,
Transaction,
} from '../types'
Expand All @@ -14,53 +14,84 @@ export class FrontStorage {

async transaction<T>(fn: (opts: FrontStorageTransaction) => Promise<T>) {
return await this._adapter.transaction(async (adapterOpts) => {
const t = new FrontStorageTransactionImpl(adapterOpts, this.dbName)
const t = new FrontStorageTransactionImpl(adapterOpts)
return await fn(t)
})
}
}

class FrontStorageTransactionImpl {
constructor(
private _adapterTransaction: FrontStorageAdapterTransaction,
private _session: string,
) {}
constructor(private _adapterTransaction: FrontStorageAdapterTransaction) {}

async setLastBackendState(s: BackState<unknown>) {
async setSessionState(s: SessionState<unknown>, session: string) {
// TODO: serializing the state every time this changes probably wastes IO.
// better to create a writeahead log and compact it every once in a while
await this._adapterTransaction.set('lastBackendState', s, this._session)
await this._adapterTransaction.set('sessionState', s, session)
}

async getLastBackendState(): Promise<BackState<unknown> | undefined> {
const v = this._adapterTransaction.get('lastBackendState', this._session)
async getSessionState(
session: string,
): Promise<SessionState<unknown> | undefined> {
const v = this._adapterTransaction.get('sessionState', session)
return v as $IntentionalAny
}

async getOptimisticUpdates(): Promise<Transaction[]> {
return (
await this._adapterTransaction.getList('optimisticUpdates', this._session)
).map((t: $IntentionalAny) => t.transaction)
async getMostRecentlySyncedSessionState(): Promise<
SessionState<unknown> | undefined
> {
const allSessionStates =
this._adapterTransaction.getAll<SessionState<unknown>>('sessionState')
let latest: SessionState<unknown> | undefined
for (const [peerId, sessionState] of Object.entries(allSessionStates)) {
if (
typeof sessionState.backendClock === 'number' &&
sessionState.backendClock > (latest?.backendClock ?? -1)
) {
latest = sessionState
}
}

return latest
}

async getOptimisticUpdates(session: string): Promise<Transaction[]> {
const s = await this._adapterTransaction.getList<{
id: string
transaction: Transaction
}>('optimisticUpdates', session)
return s.map((t) => t.transaction)
}

async pluckOptimisticUpdates(
transactions: Pick<Transaction, 'peerClock' | 'peerId'>[],
transactions: Pick<Transaction, 'peerClock'>[],
session: string,
): Promise<void> {
await this._adapterTransaction.pluckFromList(
'optimisticUpdates',
transactions.map(({peerId, peerClock}) => peerId + '#' + peerClock),
this._session,
transactions.map(({peerClock}) => '#' + peerClock),
session,
)
}

async pushOptimisticUpdates(transactions: Transaction[]): Promise<void> {
await this._adapterTransaction.pushToList(
async getAllExistingSessionIds(): Promise<string[]> {
const all = await this._adapterTransaction.getAll('session')
return Object.keys(all)
}

async pushOptimisticUpdates(
transactions: Transaction[],
session: string,
): Promise<void> {
await this._adapterTransaction.pushToList<{
id: string
transaction: Transaction
}>(
'optimisticUpdates',
transactions.map((t) => ({
id: t.peerId + '#' + t.peerClock,
transacion: t,
id: '#' + t.peerClock,
transaction: t,
})),
this._session,
session,
)
}
}
Expand Down
Loading

0 comments on commit 23f9f91

Please sign in to comment.