blob: c2b676a6ed38c72404839c11552b4b0c1e2acd72 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
crate::{
device::buffer::{Buffer, BufferRef, MutableBufferRef},
object_store::transaction::Transaction,
},
anyhow::{bail, Error},
async_trait::async_trait,
std::ops::Range,
};
#[async_trait]
pub trait ObjectHandle: Send + Sync {
/// Returns the object identifier for this object which will be unique for the store that the
/// object is contained in, but not necessarily unique within the entire system.
fn object_id(&self) -> u64;
/// Allocates a buffer for doing I/O (read and write) for the object.
fn allocate_buffer(&self, size: usize) -> Buffer<'_>;
/// Fills |buf| with |len| bytes read from |offset| on the underlying device.
/// The remainder of |buf| will be zeroed (so it is prudent to make |buf| as close in size to
/// |len| as possible, for example by taking a buf.subslice().)
/// |buf.size()| must be at least |len| bytes.
async fn read(&self, offset: u64, buf: MutableBufferRef<'_>) -> Result<usize, Error>;
/// Writes |buf| to the device at |offset|.
async fn txn_write<'a>(
&'a self,
transaction: &mut Transaction<'a>,
offset: u64,
buf: BufferRef<'_>,
) -> Result<(), Error>;
// Returns the size of the object.
fn get_size(&self) -> u64;
/// Sets the size of the object to |size|. If this extends the object, a hole is created. If
/// this shrinks the object, space will be deallocated (if there are no more references to the
/// data).
async fn truncate<'a>(
&'a self,
transaction: &mut Transaction<'a>,
size: u64,
) -> Result<(), Error>;
/// Preallocates the given file range. Data will not be initialised so this should be a
/// privileged operation for now. The data can be later written to using an overwrite mode.
/// Returns the device ranges allocated. Existing allocated ranges will be left untouched and
/// the ranges returned will include those.
async fn preallocate_range<'a>(
&'a self,
transaction: &mut Transaction<'a>,
range: Range<u64>,
) -> Result<Vec<Range<u64>>, Error>;
/// Returns a new transaction including a lock for this handle.
async fn new_transaction<'a>(&self) -> Result<Transaction<'a>, Error>;
}
#[async_trait]
pub trait ObjectHandleExt: ObjectHandle {
// Returns the contents of the object. The object must be < |limit| bytes in size.
async fn contents(&self, limit: usize) -> Result<Box<[u8]>, Error> {
let size = self.get_size();
if size > limit as u64 {
bail!("Object too big ({} > {})", size, limit);
}
let mut buf = self.allocate_buffer(size as usize);
self.read(0u64, buf.as_mut()).await?;
let mut vec = vec![0; size as usize];
vec.copy_from_slice(&buf.as_slice());
Ok(vec.into())
}
/// Performs a write within a transaction.
async fn write(&self, offset: u64, buf: BufferRef<'_>) -> Result<(), Error> {
let mut transaction = self.new_transaction().await?;
self.txn_write(&mut transaction, offset, buf).await?;
transaction.commit().await;
Ok(())
}
}
#[async_trait]
impl<T: ObjectHandle + ?Sized> ObjectHandleExt for T {}