-
Notifications
You must be signed in to change notification settings - Fork 0
Retain bounded live liveness materializations #773
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
179 changes: 179 additions & 0 deletions
179
src/domain/services/controllers/BoundedLiveMaterialization.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,179 @@ | ||
| import type MaterializationCoordinate from '../../materialization/MaterializationCoordinate.ts'; | ||
| import LiveMaterializationResolution from '../../materialization/LiveMaterializationResolution.ts'; | ||
| import type MaterializationHandle from '../../materialization/MaterializationHandle.ts'; | ||
| import MaterializationRoot from '../../materialization/MaterializationRoot.ts'; | ||
| import MaterializationRoots from '../../materialization/MaterializationRoots.ts'; | ||
| import BundleHandle from '../../storage/BundleHandle.ts'; | ||
| import WarpError from '../../errors/WarpError.ts'; | ||
| import type StateSession from '../../orset/session/StateSession.ts'; | ||
| import type MaterializationWorkspacePort from '../../../ports/MaterializationWorkspacePort.ts'; | ||
| import { applyLivenessInSession } from '../JoinReducerSession.ts'; | ||
| import type { MaterializeDeps } from './MaterializeDeps.ts'; | ||
| import type { MaterializeSessionOpener } from './MaterializeSessionBridge.ts'; | ||
| import { | ||
| releaseAcquisitionAfterFailure, | ||
| releaseWorkspaceAfterFailure, | ||
| } from './MaterializationWorkspaceCleanup.ts'; | ||
|
|
||
| export type BoundedLiveMaterializationResult = Readonly<{ | ||
| materialization: Awaited< | ||
| ReturnType<MaterializeDeps['materializations']['retain']> | ||
| >; | ||
| patchCount: number; | ||
| }>; | ||
|
|
||
| export async function resolveBoundedLiveMaterialization(args: { | ||
| readonly deps: MaterializeDeps; | ||
| readonly coordinate: MaterializationCoordinate; | ||
| }): Promise<LiveMaterializationResolution | null> { | ||
| const bounded = await retainBoundedLiveMaterialization(args); | ||
| if (bounded === null) { | ||
| return null; | ||
| } | ||
| const acquired = await args.deps.materializations.acquireExact(args.coordinate); | ||
| if (acquired === null) { | ||
| throw resolutionError('newly retained bounded handle could not be acquired'); | ||
| } | ||
| try { | ||
| requireSameHandle(bounded.materialization, acquired.materialization); | ||
| return new LiveMaterializationResolution({ | ||
| materialization: acquired.materialization, | ||
| source: 'materialized', | ||
| replayedPatchCount: bounded.patchCount, | ||
| release: async () => await acquired.release(), | ||
| }); | ||
| } catch (raw) { | ||
| await releaseAcquisitionAfterFailure(acquired, args.deps.logger); | ||
| throw raw; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Replays only node/edge OR-Set state into bounded CAS pages and retains those | ||
| * roots as a partial materialization. No WarpState or whole-graph adjacency is | ||
| * constructed. | ||
| */ | ||
| export async function retainBoundedLiveMaterialization(args: { | ||
| readonly deps: MaterializeDeps; | ||
| readonly coordinate: MaterializationCoordinate; | ||
| }): Promise<BoundedLiveMaterializationResult | null> { | ||
| const { deps, coordinate } = args; | ||
| const { openStateSession } = deps; | ||
| if (openStateSession === undefined) { | ||
| return null; | ||
| } | ||
| const workspace = await deps.materializations.openWorkspace(coordinate); | ||
| try { | ||
| return await buildBoundedMaterialization({ | ||
| deps, | ||
| coordinate, | ||
| workspace, | ||
| openStateSession, | ||
| }); | ||
| } catch (raw) { | ||
| await releaseWorkspaceAfterFailure(workspace, deps.logger); | ||
| throw raw; | ||
| } | ||
| } | ||
|
|
||
| async function buildBoundedMaterialization(args: { | ||
| readonly deps: MaterializeDeps; | ||
| readonly coordinate: MaterializationCoordinate; | ||
| readonly workspace: MaterializationWorkspacePort; | ||
| readonly openStateSession: MaterializeSessionOpener; | ||
| }): Promise<BoundedLiveMaterializationResult | null> { | ||
| const { deps, coordinate, workspace, openStateSession } = args; | ||
| const session = await openStateSession( | ||
| { nodeAliveRootOid: null, edgeAliveRootOid: null }, | ||
| { workspace }, | ||
| ); | ||
| const patchCount = await replayLiveness(session, deps, coordinate); | ||
| if (patchCount === 0) { | ||
| await session.close(); | ||
| await workspace.release(); | ||
| return null; | ||
| } | ||
| return await retainPreparedLiveness({ | ||
| session, | ||
| coordinate, | ||
| workspace, | ||
| patchCount, | ||
| }); | ||
| } | ||
|
|
||
| async function replayLiveness( | ||
| session: StateSession, | ||
| deps: MaterializeDeps, | ||
| coordinate: MaterializationCoordinate, | ||
| ): Promise<number> { | ||
| let patchCount = 0; | ||
| for await (const entry of deps.patches.streamForFrontier( | ||
| coordinate.frontier(), | ||
| coordinate.ceiling, | ||
| )) { | ||
| patchCount += 1; | ||
| await applyLivenessInSession(session, entry.patch); | ||
| } | ||
| return patchCount; | ||
| } | ||
|
|
||
| async function retainPreparedLiveness(args: { | ||
| readonly session: StateSession; | ||
| readonly coordinate: MaterializationCoordinate; | ||
| readonly workspace: MaterializationWorkspacePort; | ||
| readonly patchCount: number; | ||
| }): Promise<BoundedLiveMaterializationResult> { | ||
| const { session, coordinate, workspace, patchCount } = args; | ||
| const prepared = await session.prepareClose(); | ||
| const materialization = await workspace.promote({ | ||
| coordinate, | ||
| roots: livenessRoots(prepared.roots), | ||
| stateHash: null, | ||
| }); | ||
| prepared.accept(materialization.retention); | ||
| await workspace.release(); | ||
| return Object.freeze({ materialization, patchCount }); | ||
| } | ||
|
|
||
| function livenessRoots(roots: { | ||
| readonly nodeAliveRootOid: string | null; | ||
| readonly edgeAliveRootOid: string | null; | ||
| }): MaterializationRoots { | ||
| return new MaterializationRoots({ | ||
| adjacency: MaterializationRoot.unavailable(), | ||
| edgeAlive: sessionRoot(roots.edgeAliveRootOid), | ||
| edgeBirths: MaterializationRoot.unavailable(), | ||
| frontier: MaterializationRoot.unavailable(), | ||
| nodeAlive: sessionRoot(roots.nodeAliveRootOid), | ||
| properties: MaterializationRoot.unavailable(), | ||
| provenanceSupport: MaterializationRoot.unavailable(), | ||
| replayBasis: MaterializationRoot.unavailable(), | ||
| roaringIndexes: MaterializationRoot.unavailable(), | ||
| }); | ||
| } | ||
|
|
||
| function sessionRoot(token: string | null): MaterializationRoot { | ||
| return token === null | ||
| ? MaterializationRoot.empty() | ||
| : MaterializationRoot.retained(new BundleHandle(token)); | ||
| } | ||
|
|
||
| function requireSameHandle( | ||
| expected: MaterializationHandle, | ||
| acquired: MaterializationHandle, | ||
| ): void { | ||
| if ( | ||
| !acquired.coordinate.equals(expected.coordinate) | ||
| || acquired.stateHash !== expected.stateHash | ||
| || !acquired.bundle.equals(expected.bundle) | ||
| ) { | ||
| throw resolutionError('newly retained handle changed before it could be acquired'); | ||
| } | ||
| } | ||
|
|
||
| function resolutionError(message: string): WarpError { | ||
| return new WarpError( | ||
| `Materialization resolution ${message}`, | ||
| 'E_MATERIALIZATION_RESUME', | ||
| ); | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.