| // 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 {} |