Skip to content

Commit

Permalink
New files
Browse files Browse the repository at this point in the history
  • Loading branch information
cmdcolin committed Feb 25, 2025
1 parent 15e9f29 commit c3fac37
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 138 deletions.
21 changes: 8 additions & 13 deletions packages/core/data_adapters/dataAdapterCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,44 +73,39 @@ export async function getAdapter(
}

/**
* this is a callback that is passed to adapters that
* allows them to get any sub-adapters that they need
* internally, staying with the same worker session ID
* this is a callback that is passed to adapters that allows them to get any
* sub-adapters that they need internally, staying with the same worker session
* ID
*/
export type getSubAdapterType = (
adapterConfigSnap: ConfigSnap,
) => ReturnType<typeof getAdapter>

export function freeAdapterResources(specification: Record<string, any>) {
let deleteCount = 0
const specKeys = Object.keys(specification)
export function freeAdapterResources(args: Record<string, any>) {
const specKeys = Object.keys(args)

// TODO: little hacky...should make it an explicit command but:
// if we don't specify a range, delete any adapters that are only associated
// with that session
if (specKeys.length === 1 && specKeys[0] === 'sessionId') {
const { sessionId } = specification
const { sessionId } = args
Object.entries(adapterCache).forEach(([cacheKey, cacheEntry]) => {
cacheEntry.sessionIds.delete(sessionId)
if (cacheEntry.sessionIds.size === 0) {
deleteCount += 1
delete adapterCache[cacheKey]
}
})
} else {
// otherwise call freeResources on all the cached data adapters
Object.values(adapterCache).forEach(cacheEntry => {
const regions =
specification.regions ||
(specification.region ? [specification.region] : [])
const regions = args.regions || (args.region ? [args.region] : [])
for (const region of regions) {
if (region.refName !== undefined) {
cacheEntry.dataAdapter.freeResources(region)
}
}
})
}

return deleteCount
}

export function clearAdapterCache() {
Expand Down
138 changes: 43 additions & 95 deletions packages/core/pluggableElementTypes/renderers/BoxRendererType.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import deepEqual from 'fast-deep-equal'

// layouts
import FeatureRendererType from './FeatureRendererType'
import { LayoutSession } from './LayoutSession'
import { readConfObject } from '../../configuration'
import { getLayoutId } from '../../util'
import GranularRectLayout from '../../util/layouts/GranularRectLayout'
import MultiLayout from '../../util/layouts/MultiLayout'
import PrecomputedLayout from '../../util/layouts/PrecomputedLayout'

// other
Expand All @@ -17,81 +14,18 @@ import type {
ResultsDeserialized as FeatureResultsDeserialized,
ResultsSerialized as FeatureResultsSerialized,
} from './FeatureRendererType'
import type { AnyConfigurationModel } from '../../configuration'
import type { Feature, Region } from '../../util'
import type SerializableFilterChain from './util/serializableFilterChain'
import type { LayoutSessionProps } from './LayoutSession'
import type RpcManager from '../../rpc/RpcManager'
import type { Feature, Region } from '../../util'
import type {
BaseLayout,
SerializedLayout,
} from '../../util/layouts/BaseLayout'

export interface LayoutSessionProps {
config: AnyConfigurationModel
bpPerPx: number
filters?: SerializableFilterChain
}
import type GranularRectLayout from '../../util/layouts/GranularRectLayout'
import type MultiLayout from '../../util/layouts/MultiLayout'

export type MyMultiLayout = MultiLayout<GranularRectLayout<unknown>, unknown>

export interface CachedLayout {
layout: MyMultiLayout
config: AnyConfigurationModel
filters?: SerializableFilterChain
}

export class LayoutSession implements LayoutSessionProps {
config: AnyConfigurationModel

bpPerPx: number

filters?: SerializableFilterChain

constructor(args: LayoutSessionProps) {
this.config = args.config
this.bpPerPx = args.bpPerPx
this.filters = args.filters
this.update(args)
}

update(props: LayoutSessionProps) {
Object.assign(this, props)
}

makeLayout() {
return new MultiLayout(GranularRectLayout, {
maxHeight: readConfObject(this.config, 'maxHeight'),
displayMode: readConfObject(this.config, 'displayMode'),
pitchX: this.bpPerPx,
pitchY: readConfObject(this.config, 'noSpacing') ? 1 : 3,
})
}

/**
* @param layout -
* @returns true if the given layout is a valid one to use for this session
*/
cachedLayoutIsValid(cachedLayout: CachedLayout) {
return (
cachedLayout.layout.subLayoutConstructorArgs.pitchX === this.bpPerPx &&
deepEqual(readConfObject(this.config), cachedLayout.config) &&
deepEqual(this.filters, cachedLayout.filters)
)
}

cachedLayout: CachedLayout | undefined

get layout(): MyMultiLayout {
if (!this.cachedLayout || !this.cachedLayoutIsValid(this.cachedLayout)) {
this.cachedLayout = {
layout: this.makeLayout(),
config: readConfObject(this.config),
filters: this.filters,
}
}
return this.cachedLayout.layout
}
}
export interface RenderArgs extends FeatureRenderArgs {
bpPerPx: number
layoutId: string
Expand Down Expand Up @@ -128,11 +62,9 @@ export default class BoxRendererType extends FeatureRendererType {
) {
const key = getLayoutId(props)
if (!this.sessions[key]) {
this.sessions[key] = this.createSession(props)
this.sessions[key] = new LayoutSession(props)
}
const session = this.sessions[key]
session.update(props)
return session
return this.sessions[key].update(props)
}

getExpandedRegion(region: Region, renderArgs: RenderArgsDeserialized) {
Expand All @@ -147,19 +79,34 @@ export default class BoxRendererType extends FeatureRendererType {
}
}

createSession(props: LayoutSessionProps) {
return new LayoutSession(props)
freeResources(args: Record<string, any>) {
// renaming function to make clear it runs in worker
this.freeResourcesInWorker(args)
}

freeResourcesInWorker(args: Record<string, any>) {
const { regions } = args

// @ts-expect-error
const key = getLayoutId(args)
const session = this.sessions[key]

if (session) {
const region = regions[0]!
session.layout.discardRange(region.refName, region.start, region.end)
}
}

async freeResourcesInClient(rpcManager: RpcManager, args: RenderArgs) {
const { regions } = args
const key = getLayoutId(args)
const session = this.sessions[key]

if (session) {
const region = regions[0]!
session.layout.discardRange(region.refName, region.start, region.end)
}
return await super.freeResourcesInClient(rpcManager, args)
return super.freeResourcesInClient(rpcManager, args)
}

deserializeLayoutInClient(json: SerializedLayout) {
Expand All @@ -176,41 +123,42 @@ export default class BoxRendererType extends FeatureRendererType {

createLayoutInWorker(args: RenderArgsDeserialized) {
const { regions } = args
const session = this.getWorkerSession(args)
return session.layout.getSublayout(regions[0]!.refName)
const { layout } = this.getWorkerSession(args)
return layout.getSublayout(regions[0]!.refName)
}

serializeResultsInWorker(
results: RenderResults,
args: RenderArgsDeserialized,
): ResultsSerialized {
const serialized = super.serializeResultsInWorker(
const { features, ...rest } = super.serializeResultsInWorker(
results,
args,
) as ResultsSerialized

const region = args.regions[0]!
serialized.layout = results.layout.serializeRegion(
const layout = results.layout.serializeRegion(
this.getExpandedRegion(region, args),
)
serialized.features = serialized.features.filter(f => {
return Boolean(serialized.layout.rectangles[f.uniqueId])
})

serialized.maxHeightReached = serialized.layout.maxHeightReached
return serialized
return {
...rest,
layout,
maxHeightReached: layout.maxHeightReached,
features: features.filter(f => !!layout.rectangles[f.uniqueId]),
}
}

/**
* gets layout and renders
*
* @param props - render args
*/
async render(props: RenderArgsDeserialized): Promise<RenderResults> {
const layout =
(props.layout as undefined | BaseLayout<unknown>) ||
this.createLayoutInWorker(props)
const result = await super.render({ ...props, layout })
return { ...result, layout }
const result = await super.render({
...props,
layout,
})
return {
...result,
layout,
}
}
}
77 changes: 77 additions & 0 deletions packages/core/pluggableElementTypes/renderers/LayoutSession.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import deepEqual from 'fast-deep-equal'

import { readConfObject } from '../../configuration'
import GranularRectLayout from '../../util/layouts/GranularRectLayout'
import MultiLayout from '../../util/layouts/MultiLayout'

import type { AnyConfigurationModel } from '../../configuration'
import type SerializableFilterChain from './util/serializableFilterChain'

export interface LayoutSessionProps {
config: AnyConfigurationModel
bpPerPx: number
filters?: SerializableFilterChain
}

export type MyMultiLayout = MultiLayout<GranularRectLayout<unknown>, unknown>

export interface CachedLayout {
layout: MyMultiLayout
config: AnyConfigurationModel
filters?: SerializableFilterChain
}

export class LayoutSession implements LayoutSessionProps {
config: AnyConfigurationModel

bpPerPx: number

filters?: SerializableFilterChain

constructor(args: LayoutSessionProps) {
this.config = args.config
this.bpPerPx = args.bpPerPx
this.filters = args.filters
}

update(args: LayoutSessionProps) {
this.config = args.config
this.bpPerPx = args.bpPerPx
this.filters = args.filters
return this
}

makeLayout() {
return new MultiLayout(GranularRectLayout, {
maxHeight: readConfObject(this.config, 'maxHeight'),
displayMode: readConfObject(this.config, 'displayMode'),
pitchX: this.bpPerPx,
pitchY: readConfObject(this.config, 'noSpacing') ? 1 : 3,
})
}

/**
* @param layout -
* @returns true if the given layout is a valid one to use for this session
*/
cachedLayoutIsValid(cachedLayout: CachedLayout) {
return (
cachedLayout.layout.subLayoutConstructorArgs.pitchX === this.bpPerPx &&
deepEqual(readConfObject(this.config), cachedLayout.config) &&
deepEqual(this.filters, cachedLayout.filters)
)
}

cachedLayout: CachedLayout | undefined

get layout(): MyMultiLayout {
if (!this.cachedLayout || !this.cachedLayoutIsValid(this.cachedLayout)) {
this.cachedLayout = {
layout: this.makeLayout(),
config: readConfObject(this.config),
filters: this.filters,
}
}
return this.cachedLayout.layout
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -202,14 +202,9 @@ export default class ServerSideRenderer extends RendererType {

async freeResourcesInClient(rpcManager: RpcManager, args: RenderArgs) {
const serializedArgs = this.serializeArgsInClient(args)
const { sessionId } = args

const freed = this.freeResources()
const freedRpc = (await rpcManager.call(
args.sessionId,
'CoreFreeResources',
serializedArgs,
)) as number
return freed + freedRpc
await rpcManager.call(sessionId, 'CoreFreeResources', serializedArgs)
}
}

Expand Down
16 changes: 4 additions & 12 deletions packages/core/rpc/methods/CoreFreeResources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,13 @@ import RpcMethodType from '../../pluggableElementTypes/RpcMethodType'
export default class CoreFreeResources extends RpcMethodType {
name = 'CoreFreeResources'

async execute(specification: Record<string, unknown>) {
let deleteCount = 0

deleteCount += freeAdapterResources(specification)

// pass the freeResources hint along to all the renderers as well
async execute(args: Record<string, unknown>) {
freeAdapterResources(args)
this.pluginManager.getRendererTypes().forEach(renderer => {
const count = renderer.freeResources(/* specification */)
if (count) {
deleteCount += count
}
renderer.freeResources(args)
})

return deleteCount
}

async serializeArguments(args: Record<string, unknown>, _rpcDriver: string) {
return args
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { readConfObject } from '@jbrowse/core/configuration'
import { LayoutSession } from '@jbrowse/core/pluggableElementTypes/renderers/BoxRendererType'
import { LayoutSession } from '@jbrowse/core/pluggableElementTypes/renderers/LayoutSession'
import deepEqual from 'fast-deep-equal'

import type { FilterBy, SortedBy } from '../shared/types'
Expand Down
Loading

0 comments on commit c3fac37

Please sign in to comment.