pub struct FormatAccess<S: Storage + 'static> {
inner: Box<dyn FormatDriverInstance<Storage = S>>,
writable: bool,
read_parallelization: usize,
write_parallelization: usize,
}
Expand description
Provides access to a disk image.
Fields§
§inner: Box<dyn FormatDriverInstance<Storage = S>>
Image format driver.
writable: bool
Whether this image may be modified.
read_parallelization: usize
How many asynchronous requests to perform per read request in parallel.
write_parallelization: usize
How many asynchronous requests to perform per write request in parallel.
Implementations§
Source§impl<S: Storage + 'static> FormatAccess<S>
impl<S: Storage + 'static> FormatAccess<S>
Sourcepub fn new<D: FormatDriverInstance<Storage = S> + 'static>(inner: D) -> Self
pub fn new<D: FormatDriverInstance<Storage = S> + 'static>(inner: D) -> Self
Wrap a format driver instance in FormatAccess
.
FormatAccess
provides I/O access to disk images, based on the functionality offered by
the individual format drivers via FormatDriverInstance
.
Sourcepub fn inner(&self) -> &dyn FormatDriverInstance<Storage = S>
pub fn inner(&self) -> &dyn FormatDriverInstance<Storage = S>
Return the contained format driver instance.
Sourcepub fn inner_mut(&mut self) -> &mut dyn FormatDriverInstance<Storage = S>
pub fn inner_mut(&mut self) -> &mut dyn FormatDriverInstance<Storage = S>
Return the contained format driver instance.
Sourcepub fn set_async_read_parallelization(&mut self, count: usize)
pub fn set_async_read_parallelization(&mut self, count: usize)
Set the number of simultaneous async requests per read.
When issuing read requests, issue this many async requests in parallel (still in a single
thread). The default count is 1
, i.e. no parallel requests.
Sourcepub fn set_async_write_parallelization(&mut self, count: usize)
pub fn set_async_write_parallelization(&mut self, count: usize)
Set the number of simultaneous async requests per write.
When issuing write requests, issue this many async requests in parallel (still in a single
thread). The default count is 1
, i.e. no parallel requests.
Sourcepub(crate) fn collect_storage_dependencies(&self) -> Vec<&S>
pub(crate) fn collect_storage_dependencies(&self) -> Vec<&S>
Return all storage dependencies of this image.
Includes recursive dependencies, i.e. those from other image dependencies like backing images.
Sourcepub fn req_align(&self) -> usize
pub fn req_align(&self) -> usize
Minimal I/O alignment, for both length and offset.
All requests to this image should be aligned to this value, both in length and offset.
Requests that do not match this alignment will be realigned internally, which requires creating bounce buffers and read-modify-write cycles for write requests, which is costly, so should be avoided.
Sourcepub fn mem_align(&self) -> usize
pub fn mem_align(&self) -> usize
Minimal memory buffer alignment, for both address and length.
All buffers used in requests to this image should be aligned to this value, both their address and length.
Request buffers that do not match this alignment will be realigned internally, which requires creating bounce buffers, which is costly, so should be avoided.
Sourceasync fn read_chunk(
&self,
bufv: IoVectorMut<'_>,
mapping: Mapping<'_, S>,
) -> Result<()>
async fn read_chunk( &self, bufv: IoVectorMut<'_>, mapping: Mapping<'_, S>, ) -> Result<()>
Read the data from the given mapping.
Sourcepub async fn get_shallow_mapping(
&self,
offset: u64,
max_length: u64,
) -> Result<(ShallowMapping<'_, S>, u64)>
pub async fn get_shallow_mapping( &self, offset: u64, max_length: u64, ) -> Result<(ShallowMapping<'_, S>, u64)>
Return the shallow mapping at offset
.
Find what offset
is mapped to, which may be another format layer, return that
information, and the length of the continuous mapping (from offset
).
Use FormatAccess::get_mapping()
to recursively fully resolve references to other format
layers.
Sourcepub async fn get_mapping(
&self,
offset: u64,
max_length: u64,
) -> Result<(Mapping<'_, S>, u64)>
pub async fn get_mapping( &self, offset: u64, max_length: u64, ) -> Result<(Mapping<'_, S>, u64)>
Return the recursively resolved mapping at offset
.
Find what offset
is mapped to, return that mapping information, and the length of that
continuous mapping (from offset
).
All data references to other format layers are automatically resolved (recursively), so that the result are more “trivial” mappings (unless prevented by special mappings like compressed clusters).
Sourcepub async fn ensure_data_mapping(
&self,
offset: u64,
length: u64,
overwrite: bool,
) -> Result<(&S, u64, u64)>
pub async fn ensure_data_mapping( &self, offset: u64, length: u64, overwrite: bool, ) -> Result<(&S, u64, u64)>
Create a raw data mapping at offset
.
Ensure that offset
is directly mapped to some storage object, up to a length of length
.
Return the storage object, the corresponding offset there, and the continuous length that
we were able to map (less than or equal to length
).
If overwrite
is true, the contents in the range are supposed to be overwritten and may be
discarded. Otherwise, they are kept.
Sourcepub async fn readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> Result<()>
pub async fn readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> Result<()>
Read data at offset
into bufv
.
Reads until bufv
is filled completely, i.e. will not do short reads. When reaching the
end of file, the rest of bufv
is filled with 0.
Sourcepub async fn read(
&self,
buf: impl Into<IoVectorMut<'_>>,
offset: u64,
) -> Result<()>
pub async fn read( &self, buf: impl Into<IoVectorMut<'_>>, offset: u64, ) -> Result<()>
Read data at offset
into buf
.
Reads until buf
is filled completely, i.e. will not do short reads. When reaching the
end of file, the rest of buf
is filled with 0.
Sourcepub async fn writev(&self, bufv: IoVector<'_>, offset: u64) -> Result<()>
pub async fn writev(&self, bufv: IoVector<'_>, offset: u64) -> Result<()>
Write data from bufv
to offset
.
Writes all data from bufv
(or returns an error), i.e. will not do short writes. Reaching
the end of file before the end of the buffer results in an error.
Sourcepub async fn write(
&self,
buf: impl Into<IoVector<'_>>,
offset: u64,
) -> Result<()>
pub async fn write( &self, buf: impl Into<IoVector<'_>>, offset: u64, ) -> Result<()>
Write data from buf
to offset
.
Writes all data from bufv
(or returns an error), i.e. will not do short writes. Reaching
the end of file before the end of the buffer results in an error.
Sourceasync fn is_range_zero(&self, offset: u64, length: u64) -> bool
async fn is_range_zero(&self, offset: u64, length: u64) -> bool
Check whether the given range is zero.
Checks for zero mappings, not zero data (although this might be changed in the future).
Errors are treated as non-zero areas.
Sourceasync fn soft_ensure_zero(&self, offset: u64, length: u64) -> Result<()>
async fn soft_ensure_zero(&self, offset: u64, length: u64) -> Result<()>
Ensure the given range reads as zeroes, without write-zeroes support.
Does not require support for efficient zeroing, instead writing zeroes when the range is
not zero yet. If allocate
is true, areas that are not currently allocated will be
allocated to write zeroes there; if it is false, unallocated areas that currently read as
zero are left alone.
However, can still use efficient zero support if present.
The main use case is to handle unaligned zero requests. Quite inefficient for large areas.
Sourcepub async fn write_zeroes(&self, offset: u64, length: u64) -> Result<()>
pub async fn write_zeroes(&self, offset: u64, length: u64) -> Result<()>
Ensure the given range reads as zeroes.
May use efficient zeroing for a subset of the given range, if supported by the format. Will not discard anything, which keeps existing data mappings usable, albeit writing to mappings that are now zeroed may have no effect.
Check if FormatAccess::discard_to_zero()
better suits your needs: It may work better on
a wider range of formats (write_zeroes()
requires support for preallocated zero clusters,
which qcow2 does have, but other formats may not), and can actually free up space.
However, because it can break existing data mappings, it requires a mutable self
reference.
Sourcepub async fn discard_to_zero(&mut self, offset: u64, length: u64) -> Result<()>
pub async fn discard_to_zero(&mut self, offset: u64, length: u64) -> Result<()>
Discard the given range, ensure it is read back as zeroes.
Effectively the same as FormatAccess::write_zeroes()
, but discard as much of the
existing allocation as possible. This breaks existing data mappings, so needs a mutable
reference to self
, which ensures that existing data references (which have the lifetime
of an immutable self
reference) cannot be kept.
Areas that cannot be discarded (because of format-inherent alignment restrictions) are still overwritten with zeroes, unless discarding is not supported altogether.
Sourcepub async fn discard_to_any(&mut self, offset: u64, length: u64) -> Result<()>
pub async fn discard_to_any(&mut self, offset: u64, length: u64) -> Result<()>
Discard the given range, not guaranteeing specific data on read-back.
Discard as much of the given range as possible, and keep the rest as-is. Does not
guarantee any specific data on read-back, in contrast to
FormatAccess::discard_to_zero()
.
Discarding being unsupported by this format is still returned as an error
(std::io::ErrorKind::Unsupported
)
Sourcepub async fn discard_to_backing(
&mut self,
offset: u64,
length: u64,
) -> Result<()>
pub async fn discard_to_backing( &mut self, offset: u64, length: u64, ) -> Result<()>
Discard the given range, such that the backing image becomes visible.
Discard as much of the given range as possible so that a backing image’s data becomes
visible, and keep the rest as-is. This breaks existing data mappings, so needs a mutable
reference to self
, which ensures that existing data references (which have the lifetime
of an immutable self
reference) cannot be kept.
Sourcepub async fn flush(&self) -> Result<()>
pub async fn flush(&self) -> Result<()>
Flush internal buffers. Always call this before drop!
Does not necessarily sync those buffers to disk. When using flush()
, consider whether
you want to call sync()
afterwards.
Because of the current lack of stable async_drop
, you must manually call this before
dropping a FormatAccess
instance! (Not necessarily for read-only images, though.)
Note that this will not drop the buffers, so they may still be used to serve later
accesses. Use FormatAccess::invalidate_cache()
to drop all buffers.
Sourcepub async fn sync(&self) -> Result<()>
pub async fn sync(&self) -> Result<()>
Sync data already written to the storage hardware.
This does not necessarily include flushing internal buffers, i.e. flush
. When using
sync()
, consider whether you want to call flush()
before it.
Sourcepub async unsafe fn invalidate_cache(&self) -> Result<()>
pub async unsafe fn invalidate_cache(&self) -> Result<()>
Drop internal buffers.
This drops all internal buffers, but does not flush them! All cached data is reloaded from disk on subsequent accesses.
§Safety
Not flushing internal buffers may cause image corruption. You must ensure the on-disk state is consistent.
Sourcepub async fn resize(
&mut self,
new_size: u64,
prealloc_mode: PreallocateMode,
) -> Result<()>
pub async fn resize( &mut self, new_size: u64, prealloc_mode: PreallocateMode, ) -> Result<()>
Resize to the given size.
Set the disk size to new_size
. If new_size
is smaller than the current size, ignore
both preallocation modes and discard the data after new_size
.
If new_size
is larger than the current size, prealloc_mode
determines whether and how
the new range should be allocated; depending on the image format, is possible some
preallocation modes are not supported, in which case an std::io::ErrorKind::Unsupported
is returned.
This may break existing data mappings, so needs a mutable reference to self
, which
ensures that existing data references (which have the lifetime of an immutable self
reference) cannot be kept.
See also FormatAccess::resize_grow()
and FormatAccess::resize_shrink()
, whose more
specialized interface may be useful when you know whether you want to grow or shrink the
image.
Sourcepub async fn resize_grow(
&self,
new_size: u64,
prealloc_mode: PreallocateMode,
) -> Result<()>
pub async fn resize_grow( &self, new_size: u64, prealloc_mode: PreallocateMode, ) -> Result<()>
Resize to the given size, which must be greater than the current size.
Set the disk size to new_size
, preallocating the new space according to prealloc_mode
.
Depending on the image format, it is possible some preallocation modes are not supported,
in which case an std::io::ErrorKind::Unsupported
is returned.
If the current size is already new_size
or greater, do nothing.
Sourcepub async fn resize_shrink(&mut self, new_size: u64) -> Result<()>
pub async fn resize_shrink(&mut self, new_size: u64) -> Result<()>
Truncate to the given size, which must be smaller than the current size.
Set the disk size to new_size
, discarding the data after new_size
.
May break existing data mappings thanks to the mutable self
reference.
If the current size is already new_size
or smaller, do nothing.
Trait Implementations§
Source§impl<S: Storage> Display for FormatAccess<S>
impl<S: Storage> Display for FormatAccess<S>
Source§impl<S: Storage> TryFrom<FormatAccess<S>> for SyncFormatAccess<S>
impl<S: Storage> TryFrom<FormatAccess<S>> for SyncFormatAccess<S>
Source§impl<S: Storage> WrappedFormat<S> for FormatAccess<S>
impl<S: Storage> WrappedFormat<S> for FormatAccess<S>
Source§fn wrap(inner: FormatAccess<S>) -> Self
fn wrap(inner: FormatAccess<S>) -> Self
WrappedFormat
.