mirror of
https://github.com/neondatabase/neon.git
synced 2026-01-13 08:22:55 +00:00
Updates storage components to edition 2024. We like to stay on the latest edition if possible. There is no functional changes, however some code changes had to be done to accommodate the edition's breaking changes. The PR has two commits: * the first commit updates storage crates to edition 2024 and appeases `cargo clippy` by changing code. i have accidentially ran the formatter on some files that had other edits. * the second commit performs a `cargo fmt` I would recommend a closer review of the first commit and a less close review of the second one (as it just runs `cargo fmt`). part of https://github.com/neondatabase/neon/issues/10918
87 lines
2.5 KiB
Rust
87 lines
2.5 KiB
Rust
use std::sync::Arc;
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
use serde_json::Value;
|
|
use tracing::info;
|
|
|
|
use crate::state::TimelinePersistentState;
|
|
use crate::timeline::Timeline;
|
|
|
|
#[derive(Deserialize, Debug, Clone)]
|
|
pub struct Request {
|
|
/// JSON object with fields to update
|
|
pub updates: serde_json::Value,
|
|
/// List of fields to apply
|
|
pub apply_fields: Vec<String>,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub struct Response {
|
|
pub old_control_file: TimelinePersistentState,
|
|
pub new_control_file: TimelinePersistentState,
|
|
}
|
|
|
|
/// Patch control file with given request. Will update the persistent state using
|
|
/// fields from the request and persist the new state on disk.
|
|
pub async fn handle_request(tli: Arc<Timeline>, request: Request) -> anyhow::Result<Response> {
|
|
let response = tli
|
|
.map_control_file(|state| {
|
|
let old_control_file = state.clone();
|
|
let new_control_file = state_apply_diff(&old_control_file, &request)?;
|
|
|
|
info!(
|
|
"patching control file, old: {:?}, new: {:?}, patch: {:?}",
|
|
old_control_file, new_control_file, request
|
|
);
|
|
*state = new_control_file.clone();
|
|
|
|
Ok(Response {
|
|
old_control_file,
|
|
new_control_file,
|
|
})
|
|
})
|
|
.await?;
|
|
|
|
Ok(response)
|
|
}
|
|
|
|
fn state_apply_diff(
|
|
state: &TimelinePersistentState,
|
|
request: &Request,
|
|
) -> anyhow::Result<TimelinePersistentState> {
|
|
let mut json_value = serde_json::to_value(state)?;
|
|
|
|
if let Value::Object(a) = &mut json_value {
|
|
if let Value::Object(b) = &request.updates {
|
|
json_apply_diff(a, b, &request.apply_fields)?;
|
|
} else {
|
|
anyhow::bail!("request.updates is not a json object")
|
|
}
|
|
} else {
|
|
anyhow::bail!("TimelinePersistentState is not a json object")
|
|
}
|
|
|
|
let new_state: TimelinePersistentState = serde_json::from_value(json_value)?;
|
|
Ok(new_state)
|
|
}
|
|
|
|
fn json_apply_diff(
|
|
object: &mut serde_json::Map<String, Value>,
|
|
updates: &serde_json::Map<String, Value>,
|
|
apply_keys: &Vec<String>,
|
|
) -> anyhow::Result<()> {
|
|
for key in apply_keys {
|
|
if let Some(new_value) = updates.get(key) {
|
|
if let Some(existing_value) = object.get_mut(key) {
|
|
*existing_value = new_value.clone();
|
|
} else {
|
|
anyhow::bail!("key not found in original object: {}", key);
|
|
}
|
|
} else {
|
|
anyhow::bail!("key not found in request.updates: {}", key);
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|