fxfs/
object_handle.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::object_store::{PosixAttributes, Timestamp};
6use anyhow::Error;
7use async_trait::async_trait;
8use std::future::Future;
9use std::ops::Deref;
10use std::pin::Pin;
11use storage_device::buffer::{BufferFuture, BufferRef, MutableBufferRef};
12
13// Some places use Default and assume that zero is an invalid object ID, so this cannot be changed
14// easily.
15pub const INVALID_OBJECT_ID: u64 = 0;
16
17/// A handle for a generic object.  For objects with a data payload, use the ReadObjectHandle or
18/// WriteObjectHandle traits.
19pub trait ObjectHandle: Send + Sync + 'static {
20    /// Returns the object identifier for this object which will be unique for the store that the
21    /// object is contained in, but not necessarily unique within the entire system.
22    fn object_id(&self) -> u64;
23
24    /// Returns the filesystem block size, which should be at least as big as the device block size,
25    /// but not necessarily the same.
26    fn block_size(&self) -> u64;
27
28    /// Allocates a buffer for doing I/O (read and write) for the object.
29    fn allocate_buffer(&self, size: usize) -> BufferFuture<'_>;
30
31    /// Sets tracing for this object.
32    fn set_trace(&self, _v: bool) {}
33}
34
35#[derive(Clone, Debug, PartialEq)]
36pub struct ObjectProperties {
37    /// The number of references to this object.
38    pub refs: u64,
39    /// The number of bytes allocated to all extents across all attributes for this object.
40    pub allocated_size: u64,
41    /// The logical content size for the default data attribute of this object, i.e. the size of a
42    /// file.  (Objects with no data attribute have size 0.)
43    pub data_attribute_size: u64,
44    /// The timestamp at which the object was created (i.e. crtime).
45    pub creation_time: Timestamp,
46    /// The timestamp at which the objects's data was last modified (i.e. mtime).
47    pub modification_time: Timestamp,
48    /// The timestamp at which the object was last read (i.e. atime).
49    pub access_time: Timestamp,
50    /// The timestamp at which the object's status was last modified (i.e. ctime).
51    pub change_time: Timestamp,
52    /// The number of sub-directories.
53    pub sub_dirs: u64,
54    /// The POSIX attributes: mode, uid, gid, rdev
55    pub posix_attributes: Option<PosixAttributes>,
56    /// True if this is a directory that has casefolding enabled.
57    pub casefold: bool,
58    pub wrapping_key_id: Option<u128>,
59}
60
61#[async_trait]
62pub trait ReadObjectHandle: ObjectHandle {
63    /// Fills |buf| with up to |buf.len()| bytes read from |offset| on the underlying device.
64    /// |offset| and |buf| must both be block-aligned.
65    async fn read(&self, offset: u64, buf: MutableBufferRef<'_>) -> Result<usize, Error>;
66
67    /// Returns the size of the object.
68    fn get_size(&self) -> u64;
69}
70
71pub trait WriteObjectHandle: ObjectHandle {
72    /// Writes |buf.len())| bytes at |offset| (or the end of the file), returning the object size
73    /// after writing.
74    /// The writes may be cached, in which case a later call to |flush| is necessary to persist the
75    /// writes.
76    fn write_or_append(
77        &self,
78        offset: Option<u64>,
79        buf: BufferRef<'_>,
80    ) -> impl Future<Output = Result<u64, Error>> + Send;
81
82    /// Truncates the object to |size| bytes.
83    /// The truncate may be cached, in which case a later call to |flush| is necessary to persist
84    /// the truncate.
85    fn truncate(&self, size: u64) -> impl Future<Output = Result<(), Error>> + Send;
86
87    /// Flushes all pending data and metadata updates for the object.
88    fn flush(&self) -> impl Future<Output = Result<(), Error>> + Send;
89}
90
91/// This trait is an asynchronous streaming writer.
92pub trait WriteBytes: Sized {
93    fn block_size(&self) -> u64;
94
95    /// Buffers writes to be written to the underlying handle. This may flush bytes immediately
96    /// or when buffers are full.
97    fn write_bytes(&mut self, buf: &[u8]) -> impl Future<Output = Result<(), Error>> + Send;
98
99    /// Called to flush to the handle.  Named to avoid conflict with the flush method above.
100    fn complete(&mut self) -> impl Future<Output = Result<(), Error>> + Send;
101
102    /// Moves the offset forward by `amount`, which will result in zeroes in the output stream, even
103    /// if no other data is appended to it.
104    fn skip(&mut self, amount: u64) -> impl Future<Output = Result<(), Error>> + Send;
105}
106
107// Implements ReadObjectHandle for things like `Arc<dyn ReadObjectHandle>` and
108// `Box<dyn ReadObjectHandle>`.  The below impl of `ObjectHandle` is also necessary for this.
109impl<T: Deref<Target = dyn ReadObjectHandle> + Send + Sync + 'static> ReadObjectHandle for T {
110    // Manual expansion of `async_trait` to avoid double boxing the `Future`.
111    fn read<'a, 'b, 'c>(
112        &'a self,
113        offset: u64,
114        buf: MutableBufferRef<'b>,
115    ) -> Pin<Box<dyn Future<Output = Result<usize, Error>> + Send + 'c>>
116    where
117        'a: 'c,
118        'b: 'c,
119        Self: 'c,
120    {
121        (**self).read(offset, buf)
122    }
123
124    fn get_size(&self) -> u64 {
125        (**self).get_size()
126    }
127}
128
129impl<T: Deref<Target = dyn ReadObjectHandle> + Send + Sync + 'static> ObjectHandle for T {
130    fn object_id(&self) -> u64 {
131        (**self).object_id()
132    }
133
134    fn block_size(&self) -> u64 {
135        (**self).block_size()
136    }
137
138    fn allocate_buffer(&self, size: usize) -> BufferFuture<'_> {
139        (**self).allocate_buffer(size)
140    }
141
142    fn set_trace(&self, v: bool) {
143        (**self).set_trace(v)
144    }
145}