Cap each screen's Kitty placement table #113

Merged
natsukium merged 1 commit from fix/placement-cap into main 2026-10-12 16:22:03 +09:00
Owner

Closes #88.

A placement costs no pixel bytes, so the image store's byte cap never bounded the placement table: repeated puts grew the daemon and every attached client's mirror for the life of the session. Each screen now keeps at most 16384 placements, direct and Unicode-placeholder together; a put past that evicts the oldest, announced like a delete, and an id-less image left without placements is deleted with it.

The table is now keyed by (image_id, placement_id) with a per-image index and a shared sequence number, so a flood at the cap stays sublinear on the daemon. The sequence numbers survive an in-place upgrade dump, so restore evicts the same placement.

Closes #88. A placement costs no pixel bytes, so the image store's byte cap never bounded the placement table: repeated puts grew the daemon and every attached client's mirror for the life of the session. Each screen now keeps at most 16384 placements, direct and Unicode-placeholder together; a put past that evicts the oldest, announced like a delete, and an id-less image left without placements is deleted with it. The table is now keyed by `(image_id, placement_id)` with a per-image index and a shared sequence number, so a flood at the cap stays sublinear on the daemon. The sequence numbers survive an in-place upgrade dump, so restore evicts the same placement.
grid, daemon: cap each screen's Kitty placement table
All checks were successful
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
darwin / detect relevant changes (pull_request) Successful in 8s
darwin / darwin docs-only no-op (pull_request) Has been skipped
darwin / build felis (aarch64-darwin) (pull_request) Successful in 1m10s
windows / detect relevant changes (pull_request) Successful in 22s
windows / windows docs-only no-op (pull_request) Has been skipped
windows / cargo nextest (Windows) (pull_request) Successful in 5m49s
windows / frontend smoke (Windows) (pull_request) Successful in 57s
windows / package felis (x86_64-pc-windows-msvc) (pull_request) Has been skipped
bench / instruction-count regression gate (pull_request) Successful in 1m58s
fuzz / cargo fuzz smoke (per target) (pull_request) Successful in 2m30s
pr / frontend smoke (x86_64-linux) (pull_request) Successful in 42s
pr / nix flake check (pull_request) Successful in 45s
pr / cargo build / clippy / test / deny (pull_request) Successful in 3m9s
pr / wire schema is compatible with the base (pull_request) Successful in 3s
windows / cargo clippy (Windows cross) (pull_request) Successful in 17s
d7010b45a8
A placement costs no pixel bytes, so the image store's byte cap never
bounded the placement table: repeating `a=p,i=1` with a fresh `p=`, or
with none, added an entry per put to the daemon and to every attached
client's mirror, for as long as the session lived. kitty sets no limit,
but its table dies with the window and nothing mirrors it.

Each screen now keeps at most 16384 placements, direct and placeholder
together, and a put past that evicts the oldest, announced like a
delete; an id-less image left without placements goes with it. Evicting
rather than refusing keeps a long-running program able to show new
images, as the byte cap does.

At that size the table's linear scans (every put's upsert, every
anonymous id's collision check) would make a flood quadratic, so the
table is now keyed by `(image_id, placement_id)` and ordered by a
sequence number both kinds share, which is also what finds the oldest
placement of either kind.

Closes #88.

Assisted-by: Claude Code
Sign in to join this conversation.
No reviewers
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
felis-terminal/felis!113
No description provided.