Skip to content

Commit d1b23ab

Browse files
committed
Merge branch 'main' into newtype-it
2 parents 845e01e + ac1e509 commit d1b23ab

File tree

6 files changed

+123
-55
lines changed

6 files changed

+123
-55
lines changed

Cargo.lock

Lines changed: 43 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "iroh-blobs"
3-
version = "0.93.0"
3+
version = "0.94.0"
44
edition = "2021"
55
description = "content-addressed blobs for iroh"
66
license = "MIT OR Apache-2.0"
@@ -19,7 +19,7 @@ derive_more = { version = "2.0.1", features = ["from", "try_from", "into", "debu
1919
futures-lite = "2.6.0"
2020
quinn = { package = "iroh-quinn", version = "0.14.0" }
2121
n0-future = "0.2.0"
22-
n0-snafu = "0.2.0"
22+
n0-snafu = "0.2.2"
2323
range-collections = { version = "0.4.6", features = ["serde"] }
2424
smallvec = { version = "1", features = ["serde", "const_new"] }
2525
snafu = "0.8.5"
@@ -36,11 +36,11 @@ chrono = "0.4.39"
3636
nested_enum_utils = "0.2.1"
3737
ref-cast = "1.0.24"
3838
arrayvec = "0.7.6"
39-
iroh = "0.91.1"
39+
iroh = "0.92"
4040
self_cell = "1.1.0"
4141
genawaiter = { version = "0.99.1", features = ["futures03"] }
42-
iroh-base = "0.91.1"
43-
irpc = { version = "0.7.0", features = ["rpc", "quinn_endpoint_setup", "spans", "stream", "derive"], default-features = false }
42+
iroh-base = "0.92"
43+
irpc = { version = "0.8.0", features = ["rpc", "quinn_endpoint_setup", "spans", "stream", "derive"], default-features = false }
4444
iroh-metrics = { version = "0.35" }
4545
redb = { version = "=2.4", optional = true }
4646
reflink-copy = { version = "0.1.24", optional = true }
@@ -55,11 +55,11 @@ serde_test = "1.0.177"
5555
tempfile = "3.17.1"
5656
test-strategy = "0.4.0"
5757
testresult = "0.4.1"
58-
tracing-subscriber = { version = "0.3.19", features = ["fmt"] }
58+
tracing-subscriber = { version = "0.3.20", features = ["fmt"] }
5959
tracing-test = "0.2.5"
6060
walkdir = "2.5.0"
6161
atomic_refcell = "0.1.13"
62-
iroh = { version = "0.91.1", features = ["discovery-local-network"]}
62+
iroh = { version = "0.92", features = ["discovery-local-network"]}
6363
async-compression = { version = "0.4.30", features = ["lz4", "tokio"] }
6464
concat_const = "0.2.0"
6565

deny.toml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,3 @@ name = "ring"
3939
[[licenses.clarify.license-files]]
4040
hash = 3171872035
4141
path = "LICENSE"
42-
43-
[sources]
44-
allow-git = [
45-
"https://github.com/n0-computer/iroh",
46-
]

src/store/fs.rs

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ use crate::{
152152
HashAndFormat,
153153
};
154154

155+
/// Maximum number of external paths we track per blob.
156+
const MAX_EXTERNAL_PATHS: usize = 8;
157+
155158
/// Create a 16 byte unique ID.
156159
fn new_uuid() -> [u8; 16] {
157160
use rand::RngCore;
@@ -1239,18 +1242,21 @@ async fn export_path_impl(
12391242
}
12401243
};
12411244
trace!("exporting {} to {}", cmd.hash.to_hex(), target.display());
1242-
let data = match data_location {
1243-
DataLocation::Inline(data) => MemOrFile::Mem(data),
1244-
DataLocation::Owned(size) => {
1245-
MemOrFile::File((ctx.options().path.data_path(&cmd.hash), size))
1246-
}
1247-
DataLocation::External(paths, size) => MemOrFile::File((
1248-
paths
1249-
.into_iter()
1250-
.next()
1251-
.ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "no external data path"))?,
1252-
size,
1253-
)),
1245+
let (data, mut external) = match data_location {
1246+
DataLocation::Inline(data) => (MemOrFile::Mem(data), vec![]),
1247+
DataLocation::Owned(size) => (
1248+
MemOrFile::File((ctx.options().path.data_path(&cmd.hash), size)),
1249+
vec![],
1250+
),
1251+
DataLocation::External(paths, size) => (
1252+
MemOrFile::File((
1253+
paths.first().cloned().ok_or_else(|| {
1254+
io::Error::new(io::ErrorKind::NotFound, "no external data path")
1255+
})?,
1256+
size,
1257+
)),
1258+
paths,
1259+
),
12541260
};
12551261
let size = match &data {
12561262
MemOrFile::Mem(data) => data.len() as u64,
@@ -1274,21 +1280,40 @@ async fn export_path_impl(
12741280
);
12751281
}
12761282
ExportMode::TryReference => {
1277-
match std::fs::rename(&source_path, &target) {
1278-
Ok(()) => {}
1279-
Err(cause) => {
1280-
const ERR_CROSS: i32 = 18;
1281-
if cause.raw_os_error() == Some(ERR_CROSS) {
1282-
let source = fs::File::open(&source_path)?;
1283-
let mut target = fs::File::create(&target)?;
1284-
copy_with_progress(&source, size, &mut target, tx).await?;
1285-
} else {
1286-
return Err(cause.into());
1283+
if !external.is_empty() {
1284+
// the file already exists externally, so we need to copy it.
1285+
// if the OS supports reflink, we might as well use that.
1286+
let res =
1287+
reflink_or_copy_with_progress(&source_path, &target, size, tx).await?;
1288+
trace!(
1289+
"exported {} also to {}, {res:?}",
1290+
source_path.display(),
1291+
target.display()
1292+
);
1293+
external.push(target);
1294+
external.sort();
1295+
external.dedup();
1296+
external.truncate(MAX_EXTERNAL_PATHS);
1297+
} else {
1298+
// the file was previously owned, so we can just move it.
1299+
// if that fails with ERR_CROSS, we fall back to copy.
1300+
match std::fs::rename(&source_path, &target) {
1301+
Ok(()) => {}
1302+
Err(cause) => {
1303+
const ERR_CROSS: i32 = 18;
1304+
if cause.raw_os_error() == Some(ERR_CROSS) {
1305+
reflink_or_copy_with_progress(&source_path, &target, size, tx)
1306+
.await?;
1307+
} else {
1308+
return Err(cause.into());
1309+
}
12871310
}
12881311
}
1289-
}
1312+
external.push(target);
1313+
};
1314+
// setting the new entry state will also take care of deleting the owned data file!
12901315
ctx.set(EntryState::Complete {
1291-
data_location: DataLocation::External(vec![target], size),
1316+
data_location: DataLocation::External(external, size),
12921317
outboard_location,
12931318
})
12941319
.await?;
@@ -1421,6 +1446,12 @@ pub struct FsStore {
14211446
db: tokio::sync::mpsc::Sender<InternalCommand>,
14221447
}
14231448

1449+
impl From<FsStore> for Store {
1450+
fn from(value: FsStore) -> Self {
1451+
Store::from_sender(value.sender)
1452+
}
1453+
}
1454+
14241455
impl Deref for FsStore {
14251456
type Target = Store;
14261457

src/store/mem.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@ pub struct MemStore {
7474
client: ApiClient,
7575
}
7676

77+
impl From<MemStore> for crate::api::Store {
78+
fn from(value: MemStore) -> Self {
79+
crate::api::Store::from_sender(value.client)
80+
}
81+
}
82+
7783
impl AsRef<crate::api::Store> for MemStore {
7884
fn as_ref(&self) -> &crate::api::Store {
7985
crate::api::Store::ref_from_sender(&self.client)

src/store/readonly_mem.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,18 @@ impl Deref for ReadonlyMemStore {
5959
}
6060
}
6161

62+
impl From<ReadonlyMemStore> for crate::api::Store {
63+
fn from(value: ReadonlyMemStore) -> Self {
64+
crate::api::Store::from_sender(value.client)
65+
}
66+
}
67+
68+
impl AsRef<crate::api::Store> for ReadonlyMemStore {
69+
fn as_ref(&self) -> &crate::api::Store {
70+
crate::api::Store::ref_from_sender(&self.client)
71+
}
72+
}
73+
6274
struct Actor {
6375
commands: tokio::sync::mpsc::Receiver<proto::Command>,
6476
tasks: JoinSet<()>,

0 commit comments

Comments
 (0)