use std::sync::Arc;
use log::trace;
use wdev::Device;
use super::HybridLog;
use crate::error::{Error, Result};
impl<D: Device> HybridLog<D> {
pub fn shift_read_only_address(&self, new_ro: u64) {
let old_ro = self.addresses.shift_read_only_address(new_ro);
if new_ro > old_ro {
let addrs = Arc::clone(&self.addresses);
self.epoch.bump_current_epoch_action(move || {
addrs.shift_safe_read_only_address(new_ro);
trace!("Epoch 安全推进 SafeReadOnlyAddress 至 {new_ro:#x}");
});
if !self.epoch.this_instance_protected() {
self.epoch.bump_epoch();
}
}
}
pub fn shift_head_address(&self, new_head: u64) {
let old_head = self.addresses.shift_head_address(new_head);
if new_head > old_head {
let addrs = Arc::clone(&self.addresses);
self.epoch.bump_current_epoch_action(move || {
addrs.shift_safe_head_address(new_head);
trace!("Epoch 安全推进 SafeHeadAddress 至 {new_head:#x}");
});
if !self.epoch.this_instance_protected() {
self.epoch.bump_epoch();
}
}
}
pub async fn shift_begin_address(&self, new_begin: u64) -> Result<()> {
let flushed = self.addresses.flushed_until();
if flushed < new_begin {
self.shift_read_only_address(new_begin);
let start_page = self.config.page_id(flushed);
let end_page = self.config.page_id(new_begin.saturating_sub(1));
self.flush_pages_range(start_page, end_page).await?;
}
if self.addresses.flushed_until() < new_begin {
return Err(Error::InvalidState(
"shift_begin_address 前置条件不满足:待截断区间未完整落盘(调用方应先推进只读边界并排空纪元,参照 checkpoint 屏障)"
.into(),
));
}
self.shift_head_address(new_begin);
self.addresses.shift_begin_address(new_begin);
let dev = Arc::clone(&self.device);
dev
.truncate_until_address(new_begin)
.await
.map_err(Error::from)
}
#[inline]
pub fn tail_address(&self) -> u64 {
self.addresses.tail()
}
#[inline]
pub fn shift_read_only_to_tail(&self) -> u64 {
let tail = self.addresses.tail();
self.shift_read_only_address(tail);
tail
}
#[inline]
pub fn read_only_address(&self) -> u64 {
self.addresses.read_only()
}
#[inline]
pub fn safe_read_only_address(&self) -> u64 {
self.addresses.safe_read_only()
}
#[inline]
pub fn head_address(&self) -> u64 {
self.addresses.head()
}
#[inline]
pub fn safe_head_address(&self) -> u64 {
self.addresses.safe_head()
}
#[inline]
pub fn flushed_until_address(&self) -> u64 {
self.addresses.flushed_until()
}
#[inline]
pub fn begin_address(&self) -> u64 {
self.addresses.begin()
}
#[inline]
pub fn is_mutable(&self, addr: u64) -> bool {
self.addresses.is_mutable(addr)
}
#[inline]
pub fn is_read_only(&self, addr: u64) -> bool {
self.addresses.is_read_only(addr)
}
#[inline]
pub fn is_in_memory(&self, addr: u64) -> bool {
self.addresses.is_in_memory(addr)
}
#[inline]
pub fn is_on_disk(&self, addr: u64) -> bool {
self.addresses.is_on_disk(addr)
}
}