terminal: PageList has page_serial_min

pull/9711/head
Mitchell Hashimoto 2025-11-26 08:41:26 -08:00
parent e549af76fe
commit 30f189d774
No known key found for this signature in database
GPG Key ID: 523D5DC389D273BC
1 changed files with 32 additions and 2 deletions

View File

@ -128,6 +128,10 @@ pages: List,
/// going to risk it. /// going to risk it.
page_serial: u64, page_serial: u64,
/// The lowest still valid serial number that could exist. This allows
/// for quick comparisons to find invalid pages in references.
page_serial_min: u64,
/// Byte size of the total amount of allocated pages. Note this does /// Byte size of the total amount of allocated pages. Note this does
/// not include the total allocated amount in the pool which may be more /// not include the total allocated amount in the pool which may be more
/// than this due to preheating. /// than this due to preheating.
@ -304,6 +308,7 @@ pub fn init(
.pool_owned = true, .pool_owned = true,
.pages = page_list, .pages = page_list,
.page_serial = page_serial, .page_serial = page_serial,
.page_serial_min = 0,
.page_size = page_size, .page_size = page_size,
.explicit_max_size = max_size orelse std.math.maxInt(usize), .explicit_max_size = max_size orelse std.math.maxInt(usize),
.min_max_size = min_max_size, .min_max_size = min_max_size,
@ -390,6 +395,7 @@ pub inline fn pauseIntegrityChecks(self: *PageList, pause: bool) void {
const IntegrityError = error{ const IntegrityError = error{
TotalRowsMismatch, TotalRowsMismatch,
ViewportPinOffsetMismatch, ViewportPinOffsetMismatch,
PageSerialInvalid,
}; };
/// Verify the integrity of the PageList. This is expensive and should /// Verify the integrity of the PageList. This is expensive and should
@ -401,8 +407,27 @@ fn verifyIntegrity(self: *const PageList) IntegrityError!void {
// Our viewport pin should never be garbage // Our viewport pin should never be garbage
assert(!self.viewport_pin.garbage); assert(!self.viewport_pin.garbage);
// Grab our total rows
var actual_total: usize = 0;
{
var node_ = self.pages.first;
while (node_) |node| {
actual_total += node.data.size.rows;
node_ = node.next;
// While doing this traversal, verify no node has a serial
// number lower than our min.
if (node.serial < self.page_serial_min) {
log.warn(
"PageList integrity violation: page serial too low serial={} min={}",
.{ node.serial, self.page_serial_min },
);
return IntegrityError.PageSerialInvalid;
}
}
}
// Verify that our cached total_rows matches the actual row count // Verify that our cached total_rows matches the actual row count
const actual_total = self.totalRows();
if (actual_total != self.total_rows) { if (actual_total != self.total_rows) {
log.warn( log.warn(
"PageList integrity violation: total_rows mismatch cached={} actual={}", "PageList integrity violation: total_rows mismatch cached={} actual={}",
@ -721,6 +746,7 @@ pub fn clone(
}, },
.pages = page_list, .pages = page_list,
.page_serial = page_serial, .page_serial = page_serial,
.page_serial_min = 0,
.page_size = page_size, .page_size = page_size,
.explicit_max_size = self.explicit_max_size, .explicit_max_size = self.explicit_max_size,
.min_max_size = self.min_max_size, .min_max_size = self.min_max_size,
@ -2462,7 +2488,11 @@ pub fn grow(self: *PageList) !?*List.Node {
first.data.size.rows = 1; first.data.size.rows = 1;
self.pages.insertAfter(last, first); self.pages.insertAfter(last, first);
// We also need to reset the serial number // We also need to reset the serial number. Since this is the only
// place we ever reuse a serial number, we also can safely set
// page_serial_min to be one more than the old serial because we
// only ever prune the oldest pages.
self.page_serial_min = first.serial + 1;
first.serial = self.page_serial; first.serial = self.page_serial;
self.page_serial += 1; self.page_serial += 1;