graft_kernel/
graft_writer.rs

1use 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
11/// A type which can write to a Graft
12pub 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}