Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions gitoxide-core/src/pack/explode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,18 @@ impl gix::objs::Write for OutputWriter {
}
}

fn write_buf_with_known_id(
&self,
kind: object::Kind,
from: &[u8],
id: ObjectId,
) -> Result<ObjectId, gix::objs::write::Error> {
match self {
OutputWriter::Loose(db) => db.write_buf_with_known_id(kind, from, id),
OutputWriter::Sink(db) => db.write_buf_with_known_id(kind, from, id),
}
}

fn write_stream(
&self,
kind: object::Kind,
Expand All @@ -116,6 +128,19 @@ impl gix::objs::Write for OutputWriter {
OutputWriter::Sink(db) => db.write_stream(kind, size, from),
}
}

fn write_stream_with_known_id(
&self,
kind: object::Kind,
size: u64,
from: &mut dyn Read,
id: ObjectId,
) -> Result<ObjectId, gix::objs::write::Error> {
match self {
OutputWriter::Loose(db) => db.write_stream_with_known_id(kind, size, from, id),
OutputWriter::Sink(db) => db.write_stream_with_known_id(kind, size, from, id),
}
}
}

impl OutputWriter {
Expand Down
57 changes: 57 additions & 0 deletions gix-object/src/traits/_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,28 @@ where
(*self).write_buf(object, from)
}

fn write_buf_with_known_id(
&self,
object: Kind,
from: &[u8],
id: ObjectId,
) -> Result<ObjectId, crate::write::Error> {
(*self).write_buf_with_known_id(object, from, id)
}

fn write_stream(&self, kind: Kind, size: u64, from: &mut dyn Read) -> Result<ObjectId, crate::write::Error> {
(*self).write_stream(kind, size, from)
}

fn write_stream_with_known_id(
&self,
kind: Kind,
size: u64,
from: &mut dyn Read,
id: ObjectId,
) -> Result<ObjectId, crate::write::Error> {
(*self).write_stream_with_known_id(kind, size, from, id)
}
}

impl<T> crate::Write for Arc<T>
Expand All @@ -33,9 +52,28 @@ where
self.deref().write_buf(object, from)
}

fn write_buf_with_known_id(
&self,
object: Kind,
from: &[u8],
id: ObjectId,
) -> Result<ObjectId, crate::write::Error> {
self.deref().write_buf_with_known_id(object, from, id)
}

fn write_stream(&self, kind: Kind, size: u64, from: &mut dyn Read) -> Result<ObjectId, crate::write::Error> {
self.deref().write_stream(kind, size, from)
}

fn write_stream_with_known_id(
&self,
kind: Kind,
size: u64,
from: &mut dyn Read,
id: ObjectId,
) -> Result<ObjectId, crate::write::Error> {
self.deref().write_stream_with_known_id(kind, size, from, id)
}
}

impl<T> crate::Write for Rc<T>
Expand All @@ -50,9 +88,28 @@ where
self.deref().write_buf(object, from)
}

fn write_buf_with_known_id(
&self,
object: Kind,
from: &[u8],
id: ObjectId,
) -> Result<ObjectId, crate::write::Error> {
self.deref().write_buf_with_known_id(object, from, id)
}

fn write_stream(&self, kind: Kind, size: u64, from: &mut dyn Read) -> Result<ObjectId, crate::write::Error> {
self.deref().write_stream(kind, size, from)
}

fn write_stream_with_known_id(
&self,
kind: Kind,
size: u64,
from: &mut dyn Read,
id: ObjectId,
) -> Result<ObjectId, crate::write::Error> {
self.deref().write_stream_with_known_id(kind, size, from, id)
}
}

impl<T> WriteTo for &T
Expand Down
21 changes: 21 additions & 0 deletions gix-object/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ pub trait Write {
fn write_buf(&self, object: crate::Kind, mut from: &[u8]) -> Result<gix_hash::ObjectId, crate::write::Error> {
self.write_stream(object, from.len() as u64, &mut from)
}
/// As [`write_buf`](Write::write_buf), but the object `id` has already been computed by the caller.
///
/// Implementations may trust the given `id` and avoid computing it again. Callers must make sure `id` matches
/// the provided `object` and `from` bytes.
fn write_buf_with_known_id(
&self,
object: crate::Kind,
from: &[u8],
id: gix_hash::ObjectId,
) -> Result<gix_hash::ObjectId, crate::write::Error>;
/// As [`write`](Write::write), but takes an input stream.
/// This is commonly used for writing blobs directly without reading them to memory first.
fn write_stream(
Expand All @@ -23,6 +33,17 @@ pub trait Write {
size: u64,
from: &mut dyn io::Read,
) -> Result<gix_hash::ObjectId, crate::write::Error>;
/// As [`write_stream`](Write::write_stream), but the object `id` has already been computed by the caller.
///
/// Implementations may trust the given `id` and avoid computing it again. Callers must make sure `id` matches
/// the provided `kind`, `size` and stream contents.
fn write_stream_with_known_id(
&self,
kind: crate::Kind,
size: u64,
from: &mut dyn io::Read,
id: gix_hash::ObjectId,
) -> Result<gix_hash::ObjectId, crate::write::Error>;
Comment thread
Byron marked this conversation as resolved.
}

/// Writing of objects to a `Write` implementation
Expand Down
19 changes: 19 additions & 0 deletions gix-odb/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,25 @@ mod impls {
) -> Result<ObjectId, gix_object::write::Error> {
self.inner.write_stream(kind, size, from)
}

fn write_buf_with_known_id(
&self,
kind: Kind,
from: &[u8],
id: ObjectId,
) -> Result<ObjectId, gix_object::write::Error> {
self.inner.write_buf_with_known_id(kind, from, id)
}

fn write_stream_with_known_id(
&self,
kind: Kind,
size: u64,
from: &mut dyn Read,
id: ObjectId,
) -> Result<ObjectId, gix_object::write::Error> {
self.inner.write_stream_with_known_id(kind, size, from, id)
}
}

impl<S> gix_object::Find for Cache<S>
Expand Down
32 changes: 32 additions & 0 deletions gix-odb/src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,38 @@ where
map.borrow_mut().insert(id, (kind, buf));
Ok(id)
}

fn write_buf_with_known_id(
&self,
kind: gix_object::Kind,
from: &[u8],
id: gix_hash::ObjectId,
) -> Result<gix_hash::ObjectId, gix_object::write::Error> {
let Some(map) = self.memory.as_ref() else {
return self.inner.write_buf_with_known_id(kind, from, id);
};

map.borrow_mut().insert(id, (kind, from.to_owned()));
Ok(id)
}

fn write_stream_with_known_id(
&self,
kind: gix_object::Kind,
size: u64,
from: &mut dyn std::io::Read,
id: gix_hash::ObjectId,
) -> Result<gix_hash::ObjectId, gix_object::write::Error> {
let Some(map) = self.memory.as_ref() else {
return self.inner.write_stream_with_known_id(kind, size, from, id);
};

let mut buf = Vec::new();
from.read_to_end(&mut buf)?;

map.borrow_mut().insert(id, (kind, buf));
Ok(id)
}
}

impl<T> Deref for Proxy<T> {
Expand Down
43 changes: 43 additions & 0 deletions gix-odb/src/sink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ impl Sink {
}

impl gix_object::Write for Sink {
fn write_buf_with_known_id(
&self,
kind: gix_object::Kind,
mut from: &[u8],
id: gix_hash::ObjectId,
) -> Result<gix_hash::ObjectId, gix_object::write::Error> {
self.write_stream_with_known_id(kind, from.len() as u64, &mut from, id)
}

fn write_stream(
&self,
kind: gix_object::Kind,
Expand Down Expand Up @@ -55,4 +64,38 @@ impl gix_object::Write for Sink {

Ok(hasher.try_finalize()?)
}

fn write_stream_with_known_id(
&self,
kind: gix_object::Kind,
mut size: u64,
from: &mut dyn io::Read,
id: gix_hash::ObjectId,
) -> Result<gix_hash::ObjectId, gix_object::write::Error> {
let mut buf = [0u8; u16::MAX as usize];
let header = gix_object::encode::loose_header(kind, size);

let possibly_compress = |buf: &[u8]| -> io::Result<()> {
if let Some(compressor) = self.compressor.as_ref() {
compressor.try_borrow_mut().expect("no recursion").write_all(buf)?;
}
Ok(())
};

possibly_compress(&header).map_err(Box::new)?;

while size != 0 {
let bytes = (size as usize).min(buf.len());
from.read_exact(&mut buf[..bytes]).map_err(Box::new)?;
possibly_compress(&buf[..bytes]).map_err(Box::new)?;
size -= bytes as u64;
}
if let Some(compressor) = self.compressor.as_ref() {
let mut c = compressor.borrow_mut();
c.flush().map_err(Box::new)?;
c.reset();
}

Ok(id)
}
}
43 changes: 43 additions & 0 deletions gix-odb/src/store_impls/dynamic/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,47 @@ where
}
})
}

fn write_buf_with_known_id(
&self,
kind: Kind,
from: &[u8],
id: ObjectId,
) -> Result<ObjectId, gix_object::write::Error> {
let mut snapshot = self.snapshot.borrow_mut();
Ok(match snapshot.loose_dbs.first() {
Some(ldb) => ldb.write_buf_with_known_id(kind, from, id)?,
None => {
let new_snapshot = self
.store
.load_one_index(self.refresh, snapshot.marker)
.map_err(Box::new)?
.expect("there is always at least one ODB, and this code runs only once for initialization");
*snapshot = new_snapshot;
snapshot.loose_dbs[0].write_buf_with_known_id(kind, from, id)?
}
})
}

fn write_stream_with_known_id(
&self,
kind: Kind,
size: u64,
from: &mut dyn Read,
id: ObjectId,
) -> Result<ObjectId, gix_object::write::Error> {
let mut snapshot = self.snapshot.borrow_mut();
Ok(match snapshot.loose_dbs.first() {
Some(ldb) => ldb.write_stream_with_known_id(kind, size, from, id)?,
None => {
let new_snapshot = self
.store
.load_one_index(self.refresh, snapshot.marker)
.map_err(Box::new)?
.expect("there is always at least one ODB, and this code runs only once for initialization");
*snapshot = new_snapshot;
snapshot.loose_dbs[0].write_stream_with_known_id(kind, size, from, id)?
}
})
}
}
Loading
Loading