libblobd/
inode.rs

1use crate::tile::TILE_SIZE;
2use crate::tile::TILE_SIZE_U64;
3
4/**
5
6Structure
7---------
8
9We cannot store head data inline as we need to know the inode size in order to allocate a fragment for it, but we cannot know any inline head data length unless we know the inode size. For simplicity and flexibility, we just use a fragment for tail data, instead of storing it inline which would make it subject to the free space within the same fragmented tile.
10
11The ordering of these fields is important (and somewhat strange/seemingly random), as we want to avoid multiple small reads.
12- **write_object** requires `size`, `obj_id`, `key_len`, `tail_data_fragment_dev_offset_or_zero_if_none`, and one `tile` element.
13- **find_inode_in_bucket** requires `obj_id`, `key_len`, `key`, and `next_inode_dev_offset_or_zero_if_end`.
14- **read_object** requires *find_inode_in_bucket* as well as `size`, `tail_data_fragment_dev_offset_or_zero_if_none`, and one `tile` element.
15- **commit_object** requires `obj_id`.
16
17u48 tail_data_fragment_dev_offset_or_zero_if_none
18u40 size
19u64 obj_id
20u16 key_len
21u48 next_inode_dev_offset_or_zero_if_end
22u8[] key
23u24[] tiles
24
25**/
26
27pub(crate) const INO_OFFSETOF_TAIL_FRAG_DEV_OFFSET: u64 = 0;
28pub(crate) const INO_OFFSETOF_SIZE: u64 = INO_OFFSETOF_TAIL_FRAG_DEV_OFFSET + 6;
29pub(crate) const INO_OFFSETOF_OBJ_ID: u64 = INO_OFFSETOF_SIZE + 5;
30pub(crate) const INO_OFFSETOF_KEY_LEN: u64 = INO_OFFSETOF_OBJ_ID + 8;
31pub(crate) const INO_OFFSETOF_NEXT_INODE_DEV_OFFSET: u64 = INO_OFFSETOF_KEY_LEN + 2;
32pub(crate) const INO_OFFSETOF_KEY: u64 = INO_OFFSETOF_NEXT_INODE_DEV_OFFSET + 6;
33#[allow(non_snake_case)]
34pub(crate) fn INO_OFFSETOF_TILE_IDX(key_len: u16, tile_idx: u16) -> u64 {
35  INO_OFFSETOF_KEY + u64::from(key_len) + 3 * u64::from(tile_idx)
36}
37#[allow(non_snake_case)]
38pub(crate) fn INO_OFFSETOF_TILES(key_len: u16) -> u64 {
39  INO_OFFSETOF_TILE_IDX(key_len, 0)
40}
41#[allow(non_snake_case)]
42pub(crate) fn INO_SIZE(key_len: u16, tile_count: u16) -> u32 {
43  INO_OFFSETOF_TILE_IDX(key_len, tile_count)
44    .try_into()
45    .unwrap()
46}
47
48pub(crate) struct ObjectAllocCfg {
49  pub tile_count: u16,
50  pub tail_len: u32,
51}
52
53pub(crate) fn get_object_alloc_cfg(object_size: u64) -> ObjectAllocCfg {
54  // We only allow up to 65,536 solid tiles for a single object.
55  let mut tile_count: u16 = (object_size / TILE_SIZE_U64).try_into().unwrap();
56  let mut tail_len: u32 = (object_size % TILE_SIZE_U64).try_into().unwrap();
57  // TODO Analyse this hyperparameter: is this mechanism useful? What are the impacts of higher/lower values?
58  if tail_len >= TILE_SIZE - 128 {
59    // The tail is too close to a full tile, so just allocate and use an extra tile instead.
60    tile_count += 1;
61    tail_len = 0;
62  };
63  ObjectAllocCfg {
64    tile_count,
65    tail_len,
66  }
67}