Which program blocks the TV guide (Schedule) should hold, fetch next, and drop.
The guide loads every channel row but programs only near the viewport: every channel's programs at once do not fit a large lineup on a 512 MB device. Programs are fetched in BLOCKS of BLOCK_SIZE consecutive channel rows (one request per block), and at most CAP blocks hold programs at once. They hold them only for a TIME WINDOW around the grid's left edge (timeWindow), not from the guide's start: a block holding every program up to a horizon that only grows ran a 512 MB device out of memory once the user looked a few days ahead. So program memory is bounded by CAP blocks x the window, whatever the lineup size and the day.
Pure decisions only: the component does the fetching and the node writes. A block's state is in held (an AA keyed by the block index as a string), absent when it holds nothing, else { from, until, stale }: it holds every program airing in [from, until] (seconds since the epoch): those ending at or after from and starting at or before until, as one /LiveTv/Programs query with MinEndDate and MaxStartDate returns them. stale marks programs that must be replaced (a series was recorded). A block whose last fetch failed also has an entry in failures (same keys): its backoff state (source/utils/backoff.bs), so it is not fetched again until its retryAt. Times in failures are on the component's own millisecond clock, not the epoch.
Members
(static, constant) BLOCK_SIZE
Channels per program request. 25 channels x 24 h is ~460 programs on the fixture server.
- Default Value
- 25
(static, constant) BUFFER_ROWS
Rows kept near either side of the visible rows: one whole block, so the next block is already loading by the time the user reaches it.
- Default Value
- 25
(static, constant) CAP
Blocks that may hold programs at once. At most four are ever wanted (the visible rows plus BUFFER_ROWS either side can touch four blocks), so this keeps a couple of recently visited blocks for scrolling back without refetching.
- Default Value
- 6
(static, constant) NEED_AFTER
3 h
- Default Value
- 43200
(static, constant) NEED_BEFORE
A block is fetched again only once it covers less than NEED_BEFORE / NEED_AFTER around the left edge, so pressing Left or Right does not start a fetch each time.
- Default Value
- 10800
(static, constant) TRIM_SLACK
Programs more than this outside the window are trimmed.
- Default Value
- 43200
(static, constant) WINDOW_AFTER
6 h
- Default Value
- 108000
(static, constant) WINDOW_BEFORE
The time window blocks load programs for: WINDOW_BEFORE before the left edge to WINDOW_AFTER after it (seconds).
- Default Value
- 21600
Methods
(static) blockOf(row) → {integer}
The block a row belongs to.
| Name | Type | Description |
|---|---|---|
row | integer |
- Type:
- integer
(static) blockRows(block, rowCount) → {object}
The rows of block present in the grid, as [first, last] inclusive.
| Name | Type | Description |
|---|---|---|
block | integer | a block index |
rowCount | integer | channel rows in the grid |
- Type:
- object
(static) evictions(held, wanted, focusedRow, cap) → {object}
Blocks to drop so at most cap hold programs: never a wanted one, farthest from the focused block first. The guide passes CAP.
| Name | Type | Description |
|---|---|---|
held | object | block states |
wanted | object | from wantedBlocks |
focusedRow | integer | the focused channel row |
cap | integer | blocks that may hold programs at once |
block indices to drop
- Type:
- object
(static) fetchFor(block, state, window) → {object}
The fetch that brings a block holding state up to the window: only the side it is missing when what it holds overlaps the window, else the whole window in place of what it holds.
| Name | Type | Description |
|---|---|---|
block | integer | a block index |
state | dynamic | the block's entry in |
window | object | from timeWindow |
- Type:
- object
(static) isBlockReady(block, rowCount, rowsComplete) → {boolean}
Whether every row of block has arrived.
| Name | Type | Description |
|---|---|---|
block | integer | |
rowCount | integer | |
rowsComplete | boolean |
- Type:
- boolean
(static) isCurrent(key, held, window) → {boolean}
Whether key's block covers enough of the window to need no fetch. A stale block never does.
| Name | Type | Description |
|---|---|---|
key | string | |
held | object | |
window | object |
- Type:
- boolean
(static) isWanted(block, wanted) → {boolean}
Whether block is one of wanted.
| Name | Type | Description |
|---|---|---|
block | integer | |
wanted | object |
- Type:
- boolean
(static) nextFetch(wanted, held, window, failures, nowMs) → {dynamic}
The next fetch to make, or invalid when every wanted block covers the window or is waiting to retry. Fetches are made one at a time; call again after each lands.
| Name | Type | Description |
|---|---|---|
wanted | object | from wantedBlocks |
held | object | block states (see the namespace comment) |
window | object | from timeWindow |
failures | object | backoff states of blocks whose last fetch failed |
nowMs | integer | the clock |
an AA with block, kind (a GuideFetchKind) and the from / until to request
- Type:
- dynamic
(static) nextRetryAt(wanted, held, window, failures) → {dynamic}
When the earliest wanted block waiting to retry may be fetched, or invalid when none is waiting: the time to come back if nextFetch has nothing to do now.
| Name | Type | Description |
|---|---|---|
wanted | object | from wantedBlocks |
held | object | block states |
window | object | from timeWindow |
failures | object | backoff states of blocks whose last fetch failed |
a time on the failures clock, or invalid
- Type:
- dynamic
(static) pruneFailures(failures, wanted) → {object}
failures with only the wanted blocks' entries, so a block the focus comes back to later starts again from the first, shortest delay.
| Name | Type | Description |
|---|---|---|
failures | object | backoff states of blocks whose last fetch failed |
wanted | object | from wantedBlocks |
a new AA; failures is left untouched
- Type:
- object
(static) spanState(firstRow, lastRow, held, failures, window) → {string}
What rows in [firstRow, lastRow] without programs should say. TimeGrid has one text for every such row. FAILED wins over LOADING: a block waiting up to 30 s to retry must not read as loading, while a block still loading next to it reads as unavailable only until it lands.
| Name | Type | Description |
|---|---|---|
firstRow | integer | first row, inclusive |
lastRow | integer | last row, inclusive |
held | object | block states |
failures | object | backoff states of blocks whose last fetch failed |
window | object | from timeWindow |
- Type:
- string
(static) timeWindow(leftEdge, guideStart) → {object}
The time window blocks should hold programs for, from the grid's left edge.
need no fetch; keepFrom / keepUntil, outside which what a block holds is trimmed
| Name | Type | Description |
|---|---|---|
leftEdge | integer | the time at the grid's left edge (seconds since the epoch) |
guideStart | integer | the earliest time the guide shows programs for |
an AA: from / until to fetch; needFrom / needUntil, what a block must cover to
- Type:
- object
(static) trims(held, wanted, window, focusedRow) → {object}
What to cut back so blocks hold programs only near the window, farthest from the focus first: a block no longer wanted that holds anything outside [keepFrom, keepUntil] is dropped whole (coming back to it loads its own window anyway), as is a wanted one that no longer overlaps the window at all; any other wanted one is cut back to the window on the side that ran past it. The drops come before the cuts.
until to keep
| Name | Type | Description |
|---|---|---|
held | object | block states |
wanted | object | from wantedBlocks |
window | object | from timeWindow |
focusedRow | integer | the focused channel row |
AAs with block and drop: true to drop the block, else false with the from /
- Type:
- object
(static) wantedBlocks(focusedRow, visibleRows, rowCount, rowsComplete) → {object}
Blocks to hold programs for, nearest the focused row first: the focused block, then alternately below and above it. Only blocks whose rows have all arrived are listed: a block fetched while its channels are still paging in would miss the late ones.
| Name | Type | Description |
|---|---|---|
focusedRow | dynamic | the focused channel row |
visibleRows | integer | rows the grid shows at once |
rowCount | integer | channel rows in the grid |
rowsComplete | boolean | whether every channel row has arrived |
block indices, in the order to fetch them
- Type:
- object