Add upgrade system

This commit is contained in:
Mubelotix
2025-08-26 12:02:18 +02:00
parent baa4c75af8
commit c839b804fb
6 changed files with 134 additions and 48 deletions

View File

@ -16,7 +16,7 @@ use super::BenchDeriveArgs;
use crate::common::assets::{self, Asset};
use crate::common::client::Client;
use crate::common::command::{run_commands, Command};
use crate::common::meili_process;
use crate::common::process::{self, delete_db, start_meili};
/// A bench workload.
/// Not to be confused with [a test workload](crate::test::workload::Workload).
@ -128,7 +128,9 @@ async fn execute_run(
binary_path: Option<&Path>,
run_number: u16,
) -> anyhow::Result<tokio::task::JoinHandle<anyhow::Result<std::fs::File>>> {
let meilisearch = meili_process::start(
delete_db().await;
let meilisearch = start_meili(
meili_client,
master_key,
&workload.extra_cli_args,
@ -148,7 +150,7 @@ async fn execute_run(
)
.await?;
meili_process::kill(meilisearch).await;
process::kill_meili(meilisearch).await;
tracing::info!(run_number, "Successful run");

View File

@ -3,5 +3,5 @@ pub mod assets;
pub mod client;
pub mod command;
pub mod logs;
pub mod meili_process;
pub mod process;
pub mod workload;

View File

@ -9,7 +9,7 @@ use tokio::time;
use crate::common::client::Client;
use crate::common::command::{health_command, run as run_command};
pub async fn kill(mut meilisearch: tokio::process::Child) {
pub async fn kill_meili(mut meilisearch: tokio::process::Child) {
let Some(id) = meilisearch.id() else { return };
match TokioCommand::new("kill").args(["--signal=TERM", &id.to_string()]).spawn() {
@ -65,15 +65,13 @@ async fn build() -> anyhow::Result<()> {
}
#[tracing::instrument(skip(client, master_key), fields(workload = _workload))]
pub async fn start(
pub async fn start_meili(
client: &Client,
master_key: Option<&str>,
extra_cli_args: &[String],
_workload: &str,
binary_path: Option<&Path>,
) -> anyhow::Result<tokio::process::Child> {
delete_db();
let mut command = match binary_path {
Some(binary_path) => tokio::process::Command::new(binary_path),
None => {
@ -103,6 +101,21 @@ pub async fn start(
command.kill_on_drop(true);
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
if let Some(binary_path) = binary_path {
let mut perms = tokio::fs::metadata(binary_path)
.await
.with_context(|| format!("could not get metadata for {binary_path:?}"))?
.permissions();
perms.set_mode(perms.mode() | 0o111);
tokio::fs::set_permissions(binary_path, perms)
.await
.with_context(|| format!("could not set permissions for {binary_path:?}"))?;
}
}
let mut meilisearch = command.spawn().context("Error starting Meilisearch")?;
wait_for_health(client, &mut meilisearch).await?;
@ -139,6 +152,6 @@ async fn wait_for_health(
bail!("meilisearch is not responding")
}
async fn delete_db() {
pub async fn delete_db() {
let _ = tokio::fs::remove_dir_all("./_xtask_benchmark.ms").await;
}

View File

@ -1,9 +1,67 @@
use std::collections::BTreeMap;
use std::{collections::BTreeMap, fmt::Display, path::PathBuf};
use crate::common::assets::{Asset, AssetFormat};
use anyhow::Context;
use cargo_metadata::semver::Version;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
#[derive(Clone)]
pub enum VersionOrLatest {
Version(Version),
Latest,
}
impl<'a> Deserialize<'a> for VersionOrLatest {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'a>,
{
let s: &str = Deserialize::deserialize(deserializer)?;
if s.eq_ignore_ascii_case("latest") {
Ok(VersionOrLatest::Latest)
} else {
let version = Version::parse(s).map_err(serde::de::Error::custom)?;
Ok(VersionOrLatest::Version(version))
}
}
}
impl Serialize for VersionOrLatest {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
VersionOrLatest::Version(v) => serializer.serialize_str(&v.to_string()),
VersionOrLatest::Latest => serializer.serialize_str("latest"),
}
}
}
impl VersionOrLatest {
pub fn binary_path(&self, asset_folder: &str) -> anyhow::Result<Option<PathBuf>> {
match self {
VersionOrLatest::Version(version) => {
let mut asset_folder: PathBuf = asset_folder.parse().context("parsing asset folder")?;
let arch = get_arch()?;
let local_filename = format!("meilisearch-{version}-{arch}");
asset_folder.push(local_filename);
Ok(Some(asset_folder))
}
VersionOrLatest::Latest => Ok(None),
}
}
}
impl Display for VersionOrLatest {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
VersionOrLatest::Version(v) => v.fmt(f),
VersionOrLatest::Latest => write!(f, "latest"),
}
}
}
async fn get_sha256(version: &Version, asset_name: &str) -> anyhow::Result<String> {
// If version is lower than 1.15 there is no point in trying to get the sha256, GitHub didn't support it
@ -45,7 +103,7 @@ async fn get_sha256(version: &Version, asset_name: &str) -> anyhow::Result<Strin
Ok(sha256)
}
async fn add_asset(assets: &mut BTreeMap<String, Asset>, version: &Version) -> anyhow::Result<()> {
pub fn get_arch() -> anyhow::Result<&'static str> {
let arch;
// linux-aarch64
@ -82,6 +140,11 @@ async fn add_asset(assets: &mut BTreeMap<String, Asset>, version: &Version) -> a
anyhow::bail!("unsupported platform");
}
Ok(arch)
}
async fn add_asset(assets: &mut BTreeMap<String, Asset>, version: &Version) -> anyhow::Result<()> {
let arch = get_arch()?;
let local_filename = format!("meilisearch-{version}-{arch}");
if assets.contains_key(&local_filename) {
return Ok(());

View File

@ -8,45 +8,15 @@ use crate::{
assets::{fetch_assets, Asset},
client::Client,
command::{run_commands, Command},
process::{self, delete_db, kill_meili},
workload::Workload,
},
test::{versions::expand_assets_with_versions, TestDeriveArgs},
test::{
versions::{expand_assets_with_versions, VersionOrLatest},
TestDeriveArgs,
},
};
#[derive(Clone)]
pub enum VersionOrLatest {
Version(Version),
Latest,
}
impl<'a> Deserialize<'a> for VersionOrLatest {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'a>,
{
let s: &str = Deserialize::deserialize(deserializer)?;
if s.eq_ignore_ascii_case("latest") {
Ok(VersionOrLatest::Latest)
} else {
let version = Version::parse(s).map_err(serde::de::Error::custom)?;
Ok(VersionOrLatest::Version(version))
}
}
}
impl Serialize for VersionOrLatest {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
VersionOrLatest::Version(v) => serializer.serialize_str(&v.to_string()),
VersionOrLatest::Latest => serializer.serialize_str("latest"),
}
}
}
#[derive(Serialize, Deserialize)]
#[serde(untagged)]
pub enum CommandOrUpgrade {
@ -105,6 +75,19 @@ impl TestWorkload {
expand_assets_with_versions(&mut self.assets, &all_versions).await?;
fetch_assets(assets_client, &self.assets, &args.common.asset_folder).await?;
// Run server
delete_db().await;
let binary_path = VersionOrLatest::Version(self.initial_version.clone())
.binary_path(&args.common.asset_folder)?;
let mut process = process::start_meili(
meili_client,
args.common.master_key.as_deref(),
&[],
&self.name,
binary_path.as_deref(),
)
.await?;
let assets = Arc::new(self.assets.clone());
let return_responses = dbg!(args.add_missing_responses || args.update_responses);
for command_or_upgrade in commands_or_upgrade {
@ -133,7 +116,16 @@ impl TestWorkload {
}
}
CommandOrUpgradeVec::Upgrade(version) => {
todo!()
kill_meili(process).await;
let binary_path = version.binary_path(&args.common.asset_folder)?;
process = process::start_meili(
meili_client,
args.common.master_key.as_deref(),
&[String::from("--experimental-dumpless-upgrade")],
&self.name,
binary_path.as_deref(),
).await?;
tracing::info!("Upgraded to {version}");
}
}
}

View File

@ -28,6 +28,14 @@
]
}
},
"expectedStatus": 202,
"expectedResponse": {
"enqueuedAt": "2025-08-26T09:31:44.665991Z",
"indexUid": "movies",
"status": "enqueued",
"taskUid": 0,
"type": "settingsUpdate"
},
"synchronous": "DontWait"
},
{
@ -36,6 +44,14 @@
"body": {
"asset": "movies.json"
},
"expectedStatus": 202,
"expectedResponse": {
"enqueuedAt": "2025-08-26T09:31:44.732206Z",
"indexUid": "movies",
"status": "enqueued",
"taskUid": 1,
"type": "documentAdditionOrUpdate"
},
"synchronous": "WaitForTask"
}
]