Skip to main content

Persistent cell state

Availability: Linux and embedded runtimes

Persistent state keeps one typed value under one key in the runtime database. The value stays available from one handler to the next, and across restarts of the cell.

When to use

Use persistent state for a single value that has to survive the cell restarting, such as a counter or a setting.

Use a key-value store or a table when the data holds many entries. Use transient state for values that should not survive a restart.

Operations

  • Declare a handle for a key, fixed at compile time or built while running.
  • Declare which scope the value belongs to. Without one, it is the cell's private scope.
  • Read, write, modify, or borrow the value, at the handle's key or another.

Example

use myrmic_sdk::db::state::State;
use myrmic_sdk::db::Scope;
use myrmic_sdk::Metadata;

// No scope, so this value is private to the cell.
const COUNT: State<u64> = State::new_const("count");

// The same type in a public scope, shared with other cells.
const TOTAL: State<u64> = State::new_const_in("total", Scope::public("application-data"));

#[myrmic_sdk::cmd]
fn record(_md: Metadata) -> myrmic_sdk::Result {
// Reads, changes, and writes in one step, starting from zero if unset.
let count = COUNT.upsert_with(|count| *count += 1)?;

// Borrowed, then written back explicitly, so a failure is not lost.
let mut total = TOTAL.guard_or_default()?;
*total += 1;
total.save()?;

// The same handle, a different key.
COUNT.save_to("last-count", &count)?;

Ok(())
}

#[myrmic_sdk::cmd]
fn report(_md: Metadata) -> myrmic_sdk::Result {
// An absent key reads as nothing, not as an error.
let count = COUNT.load()?.unwrap_or_default();

myrmic_sdk::info!("counted {count}")?;

Ok(())
}

Behavior

Normal

A handle fixes the value's type and its scope. Its key is the one every operation uses unless given another.

The value is encoded and decoded whole, every time it crosses into the runtime. Changing a value in place is therefore a read, a change, and a write, not an in-database update.

Every storage call a handler makes joins one transaction, which commits when the handler returns successfully and rolls back when it returns an error or traps.

Errors

Encoding, decoding, storage access, and communication with the runtime can all fail.

Limits

Reading uses a fixed buffer of 8 KiB, so a value larger than that cannot be read back. Writing has no such limit, so a cell can store a value it can no longer read.

API documentation

See the API documentation for myrmic_sdk::db::state, which covers every operation on a state handle, and its guard.

Cookie Policy