Skip to content

Commit

Permalink
app_persistency: new implementation
Browse files Browse the repository at this point in the history
This commit aims to improve the internal bmcd persistency:
* Its more lean, no sqlite implementation anymore
* Implemented a writeback mechanism that tries to reduce the amount of
  writes to the filesystem
* read cache

The implementation is based on the following assumptions:
* This store will only be used for internal application state.
* We expect that it will contain a maximum of approximately 10 settings.
* Settings are not updated frequently. Users will setup their system
  once and no changes can occur in weeks .

The solution aims to reduce the amount of writes to the filesystem.
Secondly, no additional database driver is used. the key/value store
gets written as raw bytes. All to make sure the actual space on the
filesystem stays as small as possible.

Since the key/value store is not expected to go over 1 LEB, the whole
key/value store gets written on a update, even when only one value
changed.

furthermore the api of the persistency store got extended,
differentiating between try_* and get/set. Non-try functions will panic
on serialization errors, or when the given key is not registered.

A persistency component gets initialized using the `PersistencyBuilder`.
It enforces users to declare all the keys that are used by the
application. This is to make sure to limit the possibilities of
trans-encoding types and other pitfalls.

There is no migration implemented from the old sqlite implementation.
This means that users will lose their settings when upgrading to this
version. At the moment of writing, there are only 2 low impact key/value
pairs, which does not justify writing migration code.
  • Loading branch information
svenrademakers committed Sep 7, 2023
1 parent 8e6c5a4 commit 74b63b5
Show file tree
Hide file tree
Showing 9 changed files with 345 additions and 888 deletions.
756 changes: 15 additions & 741 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 1 addition & 4 deletions bmcd/src/legacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,10 +308,7 @@ async fn set_usb_mode(bmc: &BmcApplication, query: Query) -> LegacyResult<()> {
}

async fn get_usb_mode(bmc: &BmcApplication) -> anyhow::Result<impl IntoLegacyResponse> {
let config = bmc
.get_usb_mode()
.await
.context("Failed to get current USB mode")?;
let config = bmc.get_usb_mode().await;

let (node, mode) = match config {
UsbConfig::UsbA(node, _) | UsbConfig::Bmc(node, _) => (node, UsbMode::Device),
Expand Down
5 changes: 1 addition & 4 deletions tpi_rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,11 @@ rockusb = { git = "https://github.com/svenrademakers/rockchiprs.git", branch="ma
rusb = "0.9.2"
rustpiboot = { git = "https://github.com/ruslashev/rustpiboot.git", rev="89e6497"}
serde = { version = "1.0.183", features = ["derive"] }
sqlx = { version = "0.7.1", features = [
"runtime-tokio-rustls",
"sqlite"
] }

anyhow.workspace = true
log.workspace = true
simple_logger.workspace = true
tokio.workspace = true
tokio-util.workspace = true
futures.workspace = true
futures-concurrency = "7.4.2"
47 changes: 17 additions & 30 deletions tpi_rs/src/app/bmc_application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ use crate::middleware::firmware_update::transport::FwUpdateTransport;
use crate::middleware::firmware_update::{
fw_update_transport, FlashProgress, FlashStatus, SUPPORTED_MSD_DEVICES,
};
use crate::middleware::persistency::app_persistency::ApplicationPersistency;
use crate::middleware::persistency::app_persistency::PersistencyBuilder;
use crate::middleware::power_controller::PowerController;
use crate::middleware::usbboot;
use crate::middleware::{
app_persistency::ApplicationPersistency, pin_controller::PinController, NodeId, UsbMode,
UsbRoute,
};
use crate::middleware::{pin_controller::PinController, NodeId, UsbMode, UsbRoute};
use anyhow::{ensure, Context};
use log::{debug, info, trace};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -49,9 +48,10 @@ impl BmcApplication {
pub async fn new() -> anyhow::Result<Self> {
let pin_controller = PinController::new().context("pin_controller")?;
let power_controller = PowerController::new().context("power_controller")?;
let app_db = ApplicationPersistency::new()
.await
.context("application persistency")?;
let app_db = PersistencyBuilder::default()
.register_key(ACTIVATED_NODES_KEY, 0u8)
.register_key(USB_CONFIG, UsbConfig::UsbA(NodeId::Node1, false))
.build()?;

let instance = Self {
pin_controller,
Expand All @@ -65,16 +65,12 @@ impl BmcApplication {
}

pub async fn toggle_power_states(&self, reset_activation: bool) -> anyhow::Result<()> {
let mut node_values = self
.app_db
.get::<u8>(ACTIVATED_NODES_KEY)
.await
.unwrap_or_default();
let mut node_values = self.app_db.get::<u8>(ACTIVATED_NODES_KEY).await;

// assume that on the first time, the users want to activate the slots
if node_values == 0 || reset_activation {
node_values = if node_values < 15 { 0b1111 } else { 0b0000 };
self.app_db.set(ACTIVATED_NODES_KEY, node_values).await?;
self.app_db.set(ACTIVATED_NODES_KEY, node_values).await;
}

let current = self.nodes_on.load(Ordering::Relaxed);
Expand All @@ -99,32 +95,25 @@ impl BmcApplication {
}

async fn initialize_power(&self) -> anyhow::Result<()> {
if self.app_db.get::<u8>(ACTIVATED_NODES_KEY).await.is_err() {
// default, given a new app persistency
self.app_db.set::<u8>(ACTIVATED_NODES_KEY, 0).await?;
} else {
if self.app_db.get::<u8>(ACTIVATED_NODES_KEY).await != 0 {
self.power_on().await?;
}
Ok(())
}

async fn initialize_usb_mode(&self) -> anyhow::Result<()> {
let config = self
.app_db
.get::<UsbConfig>(USB_CONFIG)
.await
.unwrap_or(UsbConfig::UsbA(NodeId::Node1, false));
let config = self.app_db.get::<UsbConfig>(USB_CONFIG).await;
self.configure_usb(config).await.context("USB configure")
}

pub async fn get_usb_mode(&self) -> anyhow::Result<UsbConfig> {
pub async fn get_usb_mode(&self) -> UsbConfig {
self.app_db.get::<UsbConfig>(USB_CONFIG).await
}

/// routine to support legacy API
pub async fn get_node_power(&self, node: NodeId) -> anyhow::Result<bool> {
if self.nodes_on.load(Ordering::Relaxed) {
let state = self.app_db.get::<u8>(ACTIVATED_NODES_KEY).await?;
let state = self.app_db.try_get::<u8>(ACTIVATED_NODES_KEY).await?;
Ok(state & node.to_bitfield() != 0)
} else {
Ok(false)
Expand All @@ -142,13 +131,11 @@ impl BmcApplication {
);
ensure!(mask != 0);

let state = self.app_db.get::<u8>(ACTIVATED_NODES_KEY).await?;
let state = self.app_db.get::<u8>(ACTIVATED_NODES_KEY).await;
let new_state = (state & !mask) | (node_states & mask);

if new_state != state {
self.app_db
.set::<u8>(ACTIVATED_NODES_KEY, new_state)
.await?;
self.app_db.set::<u8>(ACTIVATED_NODES_KEY, new_state).await;
debug!("node activated bits updated:{:#06b}.", new_state);
}

Expand All @@ -165,7 +152,7 @@ impl BmcApplication {
}

pub async fn power_on(&self) -> anyhow::Result<()> {
let activated = self.app_db.get::<u8>(ACTIVATED_NODES_KEY).await?;
let activated = self.app_db.get::<u8>(ACTIVATED_NODES_KEY).await;
self.nodes_on.store(true, Ordering::Relaxed);
self.power_controller
.set_power_node(activated, activated)
Expand Down Expand Up @@ -194,7 +181,7 @@ impl BmcApplication {
if let Some(true) = usbboot {
self.pin_controller.set_usb_boot(dest)?;
}
self.app_db.set(USB_CONFIG, config).await?;
self.app_db.set(USB_CONFIG, config).await;
Ok(())
}

Expand Down
108 changes: 0 additions & 108 deletions tpi_rs/src/middleware/app_persistency.rs

This file was deleted.

2 changes: 1 addition & 1 deletion tpi_rs/src/middleware/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pub mod app_persistency;
pub mod firmware_update;
mod gpio_definitions;
mod helpers;
pub mod persistency;
pub mod pin_controller;
pub mod power_controller;
pub mod usbboot;
Expand Down
Loading

0 comments on commit 74b63b5

Please sign in to comment.