#[cfg(test)]
mod tests {
use crate::write_coordinator::{WriteCoordinator, CoordinatorMode, CompatCommitRequest, CompatCommitResponse, CommitWriteSet};
use fsqlite_types::{TxnToken, TxnId, TxnEpoch, CommitSeq, PageNumber, PageData, Snapshot};
use std::collections::{HashMap, HashSet};
fn test_token(id: u64) -> TxnToken {
TxnToken::new(TxnId::new(id).unwrap(), TxnEpoch::new(0))
}
fn test_snapshot(high: u64) -> Snapshot {
Snapshot {
high: CommitSeq::new(high),
schema_epoch: fsqlite_types::SchemaEpoch::new(1),
}
}
fn inline_write_set(pages: &[u32]) -> CommitWriteSet {
let mut map = HashMap::new();
for &pgno in pages {
let mut data = vec![0u8; 4096];
data[0] = 1; map.insert(PageNumber::new(pgno).unwrap(), PageData::from_vec(data));
}
CommitWriteSet::Inline(map)
}
#[test]
fn test_repro_fcw_loss_on_coordinator_restart() {
let coord1 = WriteCoordinator::new(CoordinatorMode::Compatibility);
coord1.acquire_lease(100, 0);
let t1 = test_token(1);
let t2 = test_token(2);
let snapshot = test_snapshot(0);
let req1 = CompatCommitRequest {
txn: t1,
mode: crate::core_types::TransactionMode::Concurrent,
write_set: inline_write_set(&[10]),
intent_log: Vec::new(),
page_locks: HashSet::from([PageNumber::new(10).unwrap()]),
snapshot,
has_in_rw: false,
has_out_rw: false,
wal_fec_r: 0,
};
let resp1 = coord1.compat_commit(&req1);
let CompatCommitResponse::Ok { commit_seq: seq1, .. } = resp1 else {
panic!("T1 failed to commit");
};
assert_eq!(seq1.get(), 1);
let coord2 = WriteCoordinator::new(CoordinatorMode::Compatibility);
coord2.acquire_lease(200, 10);
let req2 = CompatCommitRequest {
txn: t2,
mode: crate::core_types::TransactionMode::Concurrent,
write_set: inline_write_set(&[10]),
intent_log: Vec::new(),
page_locks: HashSet::from([PageNumber::new(10).unwrap()]),
snapshot, has_in_rw: false,
has_out_rw: false,
wal_fec_r: 0,
};
let resp2 = coord2.compat_commit(&req2);
if let CompatCommitResponse::Ok { .. } = resp2 {
panic!("FCW violation! T2 committed despite conflict with T1 (lost on restart)");
}
}
}