Remove duplicated LSN fields from the page cache.

Having multiple copies of the same values is a source of confusion.
Commit da9bf5dc63 fixed one race condition caused by that, for example.
See also discussion at
https://github.com/zenithdb/zenith/issues/57#issuecomment-824393470

This changes SeqWait.advance() to return the old number, and not panic if
you try to move the value backwards. The caller should check for that and
act accordingly.
This commit is contained in:
Heikki Linnakangas
2021-04-27 10:32:39 +03:00
parent 4acdcbe90f
commit cff671c1bd
3 changed files with 77 additions and 96 deletions
+6
View File
@@ -171,6 +171,12 @@ impl AtomicLsn {
}
Lsn(prev)
}
/// Atomically sets the Lsn to the max of old and new value, returning the old value.
pub fn fetch_max(&self, lsn: Lsn) -> Lsn {
let prev = self.inner.fetch_max(lsn.0, Ordering::AcqRel);
Lsn(prev)
}
}
#[cfg(test)]
+23 -11
View File
@@ -173,17 +173,15 @@ where
///
/// All waiters at this value or below will be woken.
///
/// `advance` will panic if you send it a lower number than
/// a previous call.
pub fn advance(&self, num: T) {
/// Returns the old number.
pub fn advance(&self, num: T) -> T {
let old_value;
let wake_these = {
let mut internal = self.internal.lock().unwrap();
if internal.current > num {
panic!(
"tried to advance backwards, from {:?} to {:?}",
internal.current, num
);
old_value = internal.current;
if old_value >= num {
return old_value;
}
internal.current = num;
@@ -204,6 +202,12 @@ where
// We don't care; discard the error.
let _ = tx.send(());
}
old_value
}
/// Read the current value, without waiting.
pub fn load(&self) -> T {
self.internal.lock().unwrap().current
}
}
@@ -222,7 +226,8 @@ mod tests {
let seq3 = Arc::clone(&seq);
spawn(move || {
seq2.wait_for(42).expect("wait_for 42");
seq2.advance(100);
let old = seq2.advance(100);
assert_eq!(old, 99);
seq2.wait_for(999).expect_err("no 999");
});
spawn(move || {
@@ -230,8 +235,14 @@ mod tests {
seq3.wait_for(0).expect("wait_for 0");
});
sleep(Duration::from_secs(1));
seq.advance(99);
let old = seq.advance(99);
assert_eq!(old, 0);
seq.wait_for(100).expect("wait_for 100");
// Calling advance with a smaller value is a no-op
assert_eq!(seq.advance(98), 100);
assert_eq!(seq.load(), 100);
seq.shutdown();
}
@@ -247,6 +258,7 @@ mod tests {
sleep(Duration::from_secs(1));
// This will attempt to wake, but nothing will happen
// because the waiter already dropped its Receiver.
seq.advance(99);
let old = seq.advance(99);
assert_eq!(old, 0)
}
}