Skip to content

feat: [MR-142] Introduce hot/cold-partitioned CanisterStates#10280

Open
alin-at-dfinity wants to merge 1 commit into
masterfrom
alin/canister-states-foundations
Open

feat: [MR-142] Introduce hot/cold-partitioned CanisterStates#10280
alin-at-dfinity wants to merge 1 commit into
masterfrom
alin/canister-states-foundations

Conversation

@alin-at-dfinity
Copy link
Copy Markdown
Contributor

Lays the foundation for splitting ReplicatedState::canister_states into "hot" (potentially active) and "cold" (definitely idle) pools, so that per-round operations can completely ignore the long tail of idle canisters.

This PR is intentionally a no-op for the running replica: it only adds the new types and predicates. The integration into ReplicatedState and the migration of all consumers follow in subsequent PRs.

Specifically:

  • CanisterState::is_cold() — pure predicate that classifies a canister as "definitely idle": no input/output, no heartbeat, not Stopping, etc.
  • CallContextManager::has_unexpired_callbacks() and the matching SystemState::has_unexpired_callbacks() accessor, used by is_cold.
  • CanisterStates, a hot/cold-partitioned container with eager promotion (mutations land in hot) and lazy demotion (via try_cool/try_cool_all); plus the common map operations, per-pool and merged iterators and bulk mutation.
  • CanisterStates::validate_strict_split() for the canonical-partition invariant used in checkpoint validation.
  • debug_assert_invariants() runs on every mutating operation in debug builds.

Lays the foundation for splitting `ReplicatedState::canister_states` into
"hot" (potentially active) and "cold" (definitely idle) pools, so that
per-round operations can skip the long tail of idle canisters.

This PR is intentionally a no-op for the running replica: it only adds
the new types and predicates. The integration into `ReplicatedState` and
the migration of all consumers follow in subsequent PRs.

Specifically:

  * `CanisterState::is_cold()` — pure predicate that classifies a canister
    as "definitely idle": no input/output, no task queue entries, no
    heartbeat method, inactive global timer, not `Stopping`, no
    unexpired best-effort callbacks, and no scheduler debits.
  * `CallContextManager::has_unexpired_callbacks()` and the matching
    `SystemState::has_unexpired_callbacks()` accessor, used by `is_cold`.
  * `CanisterStates`, a hot/cold-partitioned container with eager
    promotion (mutations land in `hot`) and lazy demotion (via
    `try_cool`/`try_cool_all`), plus the common map operations
    (`get`/`get_mut`/`insert`/`remove`/`contains_key`/`len`/`is_empty`/
    `retain`), per-pool iterators (`hot_iter`/`hot_values`/
    `hot_values_mut`), merged iterators in `CanisterId` order
    (`all_iter`/`all_keys`/`all_values`), and bulk mutation
    (`for_each_mut`/`try_for_each_mut`).
  * `CanisterStates::validate_strict_split()` for the canonical-partition
    invariant used in checkpoint validation.
  * `debug_assert_invariants()` runs on every mutating operation in
    debug builds.

`ColdStats` and the aggregate accessors (`total_compute_allocation`,
`total_canister_memory_usage`, `memory_taken`, `callback_count`, ...)
are intentionally **not** part of this PR — they will be added once the
struct is in place.

Co-authored-by: Cursor <cursoragent@cursor.com>
@alin-at-dfinity alin-at-dfinity requested a review from a team as a code owner May 22, 2026 08:03
@github-actions github-actions Bot added the feat label May 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant