graft_kernel/
graft_writer.rs1use culprit::{Result, ResultExt};
2use graft_core::{PageCount, PageIdx, VolumeId, commit::SegmentIdx, page::Page};
3
4use crate::{
5 KernelErr,
6 graft_reader::{GraftRead, GraftReader},
7 rt::runtime::Runtime,
8 snapshot::Snapshot,
9};
10
11pub trait GraftWrite {
13 fn write_page(&mut self, pageidx: PageIdx, page: Page) -> Result<(), KernelErr>;
14 fn truncate(&mut self, page_count: PageCount) -> Result<(), KernelErr>;
15 fn commit(self) -> Result<GraftReader, KernelErr>;
16}
17
18#[derive(Debug)]
19pub struct GraftWriter {
20 runtime: Runtime,
21 graft: VolumeId,
22 snapshot: Snapshot,
23 page_count: PageCount,
24 segment: SegmentIdx,
25}
26
27impl GraftWriter {
28 pub(crate) fn new(
29 runtime: Runtime,
30 graft: VolumeId,
31 snapshot: Snapshot,
32 page_count: PageCount,
33 ) -> Self {
34 let segment = runtime.create_staged_segment();
35 Self {
36 runtime,
37 graft,
38 snapshot,
39 page_count,
40 segment,
41 }
42 }
43}
44
45impl GraftRead for GraftWriter {
46 fn snapshot(&self) -> &Snapshot {
47 &self.snapshot
48 }
49
50 fn page_count(&self) -> Result<PageCount, KernelErr> {
51 Ok(self.page_count)
52 }
53
54 fn read_page(&self, pageidx: PageIdx) -> Result<Page, KernelErr> {
55 if !self.page_count.contains(pageidx) {
56 Ok(Page::EMPTY)
57 } else if self.segment.contains(pageidx) {
58 self.runtime
59 .storage()
60 .read()
61 .read_page(self.segment.sid().clone(), pageidx)
62 .transpose()
63 .expect("BUG: Staged segment out of sync with storage")
64 .or_into_ctx()
65 } else {
66 self.runtime.read_page(&self.snapshot, pageidx)
67 }
68 }
69}
70
71impl GraftWrite for GraftWriter {
72 fn write_page(&mut self, pageidx: PageIdx, page: Page) -> Result<(), KernelErr> {
73 self.page_count = self.page_count.max(pageidx.pages());
74 self.segment.insert(pageidx);
75 self.runtime
76 .storage()
77 .write_page(self.segment.sid().clone(), pageidx, page)
78 .or_into_ctx()
79 }
80
81 fn truncate(&mut self, page_count: PageCount) -> Result<(), KernelErr> {
82 let start = page_count
83 .last_pageidx()
84 .unwrap_or_default()
85 .saturating_next();
86 self.page_count = page_count;
87 self.segment.remove_page_range(start..=PageIdx::LAST);
88 self.runtime
89 .storage()
90 .remove_page_range(self.segment.sid(), start..=PageIdx::LAST)
91 .or_into_ctx()
92 }
93
94 fn commit(self) -> Result<GraftReader, KernelErr> {
95 let snapshot = self
96 .runtime
97 .storage()
98 .read_write()
99 .commit(&self.graft, self.snapshot, self.page_count, self.segment)
100 .or_into_ctx()?;
101 Ok(GraftReader::new(self.runtime, self.graft, snapshot))
102 }
103}