# Asterhold integration contract v1 Use `ratdb-core` with `default-features = false` and a platform allocator. This gives a service exclusive ownership of a database through ordinary Rust methods. Allocation failure can terminate the program. Budget heap for temporary record buffers, stack for the adapter and space for two complete banks. A small initial configuration is 4096 bytes per bank, 48 bytes per key and 640 bytes per value. Measure with the target allocator before choosing limits. ## Storage capability | Method | Successful return | Error and host obligation | |---|---|---| | `len` | Current logical length in bytes. Zero lets core initialize a fresh extent. | Propagate I/O failure. Returning zero for a failed lookup can trigger initialization. | | `resize` | New logical length visible, newly exposed bytes read as zero. Core requests two banks during initialization. | Return Full on insufficient capacity or Io on uncertain state. Failed allocation may leave a partial extent. | | `read` | Exactly the requested bytes starting at the supplied offset. Subsequent reads see earlier writes. | Handle short positive reads, reject premature EOF, overflow, invalid ranges and device errors. | | `write` | All supplied bytes visible through the handle. | Handle short writes. On failure any part may already be visible or durable. Preserve bytes outside the requested range. | | `sync` | All preceding writes and length changes survive restart in the device's stated failure model. A later failure must preserve those bytes unless subsequently overwritten. | Propagate filesystem, controller and media errors. A failed flush leaves persistence uncertain. Close and reopen after a failed commit, then reconcile the intended operation. | Acquire exclusive ownership before reading length and hold it through the final access. The host supplies hard capacity through its allocation policy. The trait has no free-space query. Distinguish a missing instance from permission and lookup errors before handing over storage. Keep creation separate from opening an existing instance in the host service. Make its directory entry and ancestor directories durable when provisioning files. MemoryStorage has volatile lifetime and a no-op sync. Devices without an enforceable persistence barrier can serve volatile workloads only. ## Executable example The example implements `Storage` for two representative OS interfaces. `BlockExtent` translates byte ranges into 512-byte sector requests with one scratch sector. Its volume manager supplies persistent logical length, zeroed allocation, exclusive use and flush. `OsFile` adapts a native inode capability with positioned short transfers and a file flush. Each opens a database, writes an OS setting, an application preference, service metadata and an event, then reopens and checks the values. The test executable uses mock backends. [Source](../crates/ratdb-core/examples/asterhold.rs) ```rust fn store_state(storage: S) -> Result { let mut db = Database::open(storage, CONFIG)?; for (key, value) in STATE { db.put(key, value)?; } Ok(db.into_storage()) } ``` ```sh cargo run --locked -p ratdb-core --no-default-features --example asterhold cargo test --locked -p ratdb-core --no-default-features --example asterhold cargo check --locked -p ratdb-core --no-default-features --lib --target thumbv7em-none-eabi ``` Use an extent and bank size aligned to physical write units. Read/modify/write alone cannot guarantee protection of neighboring durable bytes on defective hardware. The real driver must establish sector failure semantics or add independent protection before enabling durable storage. Measure flush propagation through every caching layer. The example's 8192-byte capacity is enforced by its mock allocator. ## Service startup and recovery 1. Bring up physical memory, the allocator, controller, partition/volume manager and any filesystem RatDB uses. Keep filesystem discovery, initial mount and the recovery console independent of database configuration. 2. Obtain the file capability or reserved extent exclusively. Validate geometry, capacity and flush capability. Use separate operator-authorized provisioning for missing storage. 3. Open the database and wait for validation of the current snapshot before serving requests. Treat corrupt, ambiguous or unsupported images as unavailable. Preserve the original bytes for diagnosis or restore a verified backup on separate storage. 4. For private service configuration, keep one embedded handle and serialize access in that service. For shared settings or application data, have one resident service own the handle. Bound request sizes, queue length and result counts, and identify each caller through native IPC. The dispatcher in ratdb-server has no TCP dependency in its function signature. Porting its current std-based document and protocol crates requires additional platform support. The core's binary interface works independently. 5. Deliver successful mutations to clients only after the core returns success. Reconcile requests interrupted by disconnect or reboot. A stable application record ID helps detect a request whose reply was lost. The Windows GNU host ran the example and its four adapter tests with core default features disabled. The portable library compiled for thumbv7em-none-eabi. Asterhold still needs real ownership and allocation services, a driver with tested barriers, IPC policy and restart behavior, and power-cut tests on the intended media. ## Indexed storage on a custom adapter The development checkout supports persistent field indexes and atomic per-den uniqueness on v3 instances. See the [index guide](SECONDARY_INDEXES.md) for initialization, migration, value semantics, protocol and adapter requirements.