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