source_constants_apiPool.bs
' @fileoverview Width of the API request pool (how many ApiTask slots the queue
' coordinator can dispatch to at once), chosen per device class at startup.
'
' Two widths, because the measured best differs by device class. On a 512 MB
' device a wider pool gains nothing past 4 on a slow connection, and at 6 or more
' makes Home's first rows appear later on a moderate one; on 1 GB and 2 GB devices
' widths up to 6 keep cutting Home's full-load time on slow connections and cost
' nothing on fast ones. 6 is also how many connections a browser opens to one
' server over plain HTTP, so it matches the load Jellyfin's own web client already
' generates. See docs/architecture/api.md ("Pool width") for the measurements.
'
' The slots themselves are separately named globals (apiPool0, apiPool1, ...)
' created in setGlobalNodes() (source/utils/globals.bs), one guarded block per
' slot because `no-task-fanout` rejects launching fresh Task nodes in a loop.
' Those blocks go up to 6: raising either width above that means adding blocks
' there too. components/api/ApiQueueTask.bs checks the created slots against the
' chosen width at startup and logs an error if they disagree.
namespace apiPool
' Width for devices not on the low-memory list. Do not change without
' measuring on device (npm run measure). See the doc above.
const DEFAULT_WIDTH = 6
' Width for 512 MB devices (m.global.device.isLowMemoryDevice).
const LOW_MEMORY_WIDTH = 4
' The pool width for a device class. Called once, in setGlobalNodes().
function widthFor(isLowMemoryDevice as boolean) as integer
if isLowMemoryDevice then return apiPool.LOW_MEMORY_WIDTH
return apiPool.DEFAULT_WIDTH
end function
' The width this session's pool was created with (m.global.apiPoolWidth).
' Falls back to LOW_MEMORY_WIDTH when the field is absent (before
' setGlobalNodes() has run, or in a unit test), because asking for fewer slots
' than exist only queues requests, while asking for more would count slots
' that were never created. On a Task thread each call is a cross-thread read:
' call it once per run, not once per request.
function currentWidth() as integer
width = m.global.apiPoolWidth
' A node integer field reads back as "roInt"; the other two spellings are
' what a boxed or literal integer reports.
widthType = type(width)
if (widthType = "roInt" or widthType = "roInteger" or widthType = "Integer") and width > 0 then return width
return apiPool.LOW_MEMORY_WIDTH
end function
end namespace