fix: memory issues when importing giant mrpack files (#6278)

* feat: dont load mrpacks into memory if they are local imports

* fix: frontend
This commit is contained in:
Calum H.
2026-06-02 12:59:41 +00:00
committed by GitHub
parent 6b0a0c1897
commit cfe45b368c
11 changed files with 333 additions and 92 deletions
+38 -27
View File
@@ -8,10 +8,9 @@ use crate::state::{
SideType,
};
use crate::util::fetch::{
DownloadMeta, DownloadReason, fetch, fetch_advanced, write_cached_icon,
DownloadMeta, DownloadReason, fetch, fetch_advanced, sha1_file_async,
write_cached_icon,
};
use crate::util::io;
use path_util::SafeRelativeUtf8UnixPathBuf;
use reqwest::Method;
use serde::{Deserialize, Serialize};
@@ -134,12 +133,22 @@ impl Default for CreatePackProfile {
}
}
#[derive(Clone)]
pub enum CreatePackFile {
Bytes(bytes::Bytes),
// Local packs can be larger than available memory, so keep them file-backed.
Path(PathBuf),
}
#[derive(Clone)]
pub struct CreatePack {
pub file: bytes::Bytes,
pub file: CreatePackFile,
pub description: CreatePackDescription,
}
// The hash lookup only gates the unknown-pack warning, so avoid a long blocking scan for huge local packs.
const MAX_LOCAL_FILE_HASH_LOOKUP_SIZE: u64 = 1024 * 1024 * 1024;
#[derive(Clone, Debug)]
pub struct CreatePackDescription {
pub icon: Option<PathBuf>,
@@ -176,28 +185,31 @@ pub async fn get_profile_from_pack(
.to_string_lossy()
.to_string();
let state = State::get().await?;
let file_bytes = io::read(&path).await?;
let hash =
crate::util::fetch::sha1_async(bytes::Bytes::from(file_bytes))
.await?;
let is_known_file = match CachedEntry::get_file_many(
&[&hash],
Some(CacheBehaviour::StaleWhileRevalidateSkipOffline),
&state.pool,
&state.api_semaphore,
)
.await
let is_known_file = if tokio::fs::metadata(&path).await?.len()
<= MAX_LOCAL_FILE_HASH_LOOKUP_SIZE
{
Ok(files) => !files.is_empty(),
Err(err) => {
tracing::warn!(
"Failed to check Modrinth file hash for {}: {}",
path.display(),
err
);
false
let state = State::get().await?;
let (_, hash) = sha1_file_async(&path).await?;
match CachedEntry::get_file_many(
&[&hash],
Some(CacheBehaviour::StaleWhileRevalidateSkipOffline),
&state.pool,
&state.api_semaphore,
)
.await
{
Ok(files) => !files.is_empty(),
Err(err) => {
tracing::warn!(
"Failed to check Modrinth file hash for {}: {}",
path.display(),
err
);
false
}
}
} else {
false
};
Ok(CreatePackProfile {
@@ -380,7 +392,7 @@ pub async fn generate_pack_from_version_id(
}
Ok(CreatePack {
file,
file: CreatePackFile::Bytes(file),
description: CreatePackDescription {
icon,
override_title: Some(title),
@@ -398,9 +410,8 @@ pub async fn generate_pack_from_file(
path: PathBuf,
profile_path: String,
) -> crate::Result<CreatePack> {
let file = io::read(&path).await?;
Ok(CreatePack {
file: bytes::Bytes::from(file),
file: CreatePackFile::Path(path),
description: CreatePackDescription {
icon: None,
override_title: None,