Skip to content

Commit eb8da3d

Browse files
committed
Move PersistenceBarrier from host layer to RelationalDB
The persistence barrier is a database-layer concern (it intercepts durability requests), not a host-layer concern. Move it out of prepared_tx.rs into relational_db.rs where it belongs. prepared_tx.rs now only contains PreparedTxInfo and PreparedTransactions (the host-layer registry for tracking in-flight 2PC transactions).
1 parent eae5d36 commit eb8da3d

2 files changed

Lines changed: 81 additions & 83 deletions

File tree

crates/core/src/db/relational_db.rs

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,84 @@ type RowCountFn = Arc<dyn Fn(TableId, &str) -> i64 + Send + Sync>;
7676
/// The type of transactions committed by [RelationalDB].
7777
pub type Txdata = commitlog::payload::Txdata<ProductValue>;
7878

79+
/// A buffered durability request, held behind the persistence barrier.
80+
pub struct BufferedDurabilityRequest {
81+
pub reducer_context: Option<ReducerContext>,
82+
pub tx_data: Arc<TxData>,
83+
}
84+
85+
/// The persistence barrier prevents durability requests from being sent to the
86+
/// durability worker while a 2PC PREPARE is pending.
87+
///
88+
/// When active:
89+
/// - The PREPARE's own durability request has already been sent to the worker.
90+
/// - All subsequent durability requests are buffered here.
91+
/// - Once the PREPARE is confirmed durable and a COMMIT/ABORT decision is made:
92+
/// - COMMIT: buffered requests are flushed to the worker.
93+
/// - ABORT: buffered requests are discarded.
94+
#[derive(Default)]
95+
pub struct PersistenceBarrier {
96+
inner: std::sync::Mutex<PersistenceBarrierInner>,
97+
}
98+
99+
#[derive(Default)]
100+
struct PersistenceBarrierInner {
101+
/// If Some, a PREPARE is pending at this offset. All durability requests
102+
/// are buffered until the barrier is lifted.
103+
active_prepare: Option<TxOffset>,
104+
/// Buffered durability requests that arrived while the barrier was active.
105+
buffered: Vec<BufferedDurabilityRequest>,
106+
}
107+
108+
impl PersistenceBarrier {
109+
pub fn new() -> Self {
110+
Self::default()
111+
}
112+
113+
/// Activate the barrier for a PREPARE at the given offset.
114+
pub fn activate(&self, prepare_offset: TxOffset) {
115+
let mut inner = self.inner.lock().unwrap();
116+
assert!(
117+
inner.active_prepare.is_none(),
118+
"persistence barrier already active at offset {:?}, cannot activate for {prepare_offset}",
119+
inner.active_prepare,
120+
);
121+
inner.active_prepare = Some(prepare_offset);
122+
inner.buffered.clear();
123+
}
124+
125+
/// If the barrier is active, buffer the durability request and return None.
126+
/// If the barrier is not active, return the arguments back unchanged.
127+
pub fn try_buffer(
128+
&self,
129+
reducer_context: Option<ReducerContext>,
130+
tx_data: &Arc<TxData>,
131+
) -> Option<Option<ReducerContext>> {
132+
let mut inner = self.inner.lock().unwrap();
133+
if inner.active_prepare.is_some() {
134+
inner.buffered.push(BufferedDurabilityRequest {
135+
reducer_context,
136+
tx_data: tx_data.clone(),
137+
});
138+
None // buffered
139+
} else {
140+
Some(reducer_context) // not buffered, return back
141+
}
142+
}
143+
144+
/// Deactivate the barrier and return the buffered requests.
145+
pub fn deactivate(&self) -> Vec<BufferedDurabilityRequest> {
146+
let mut inner = self.inner.lock().unwrap();
147+
inner.active_prepare = None;
148+
std::mem::take(&mut inner.buffered)
149+
}
150+
151+
/// Check if the barrier is currently active.
152+
pub fn is_active(&self) -> bool {
153+
self.inner.lock().unwrap().active_prepare.is_some()
154+
}
155+
}
156+
79157
/// We've added a module version field to the system tables, but we don't yet
80158
/// have the infrastructure to support multiple versions.
81159
/// All modules are currently locked to this version, but this will be
@@ -114,7 +192,7 @@ pub struct RelationalDB {
114192

115193
/// 2PC persistence barrier. When active, durability requests are buffered
116194
/// instead of being sent to the durability worker.
117-
persistence_barrier: crate::host::prepared_tx::PersistenceBarrier,
195+
persistence_barrier: PersistenceBarrier,
118196
}
119197

120198
/// Perform a snapshot every `SNAPSHOT_FREQUENCY` transactions.
@@ -179,7 +257,7 @@ impl RelationalDB {
179257

180258
workload_type_to_exec_counters,
181259
metrics_recorder_queue,
182-
persistence_barrier: crate::host::prepared_tx::PersistenceBarrier::new(),
260+
persistence_barrier: PersistenceBarrier::new(),
183261
}
184262
}
185263

@@ -934,7 +1012,7 @@ impl RelationalDB {
9341012
}
9351013

9361014
/// Get a reference to the persistence barrier (for 2PC).
937-
pub fn persistence_barrier(&self) -> &crate::host::prepared_tx::PersistenceBarrier {
1015+
pub fn persistence_barrier(&self) -> &PersistenceBarrier {
9381016
&self.persistence_barrier
9391017
}
9401018

crates/core/src/host/prepared_tx.rs

Lines changed: 0 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -35,83 +35,3 @@ impl PreparedTransactions {
3535
self.inner.lock().unwrap().remove(id)
3636
}
3737
}
38-
39-
/// A buffered durability request, held behind the persistence barrier.
40-
pub struct BufferedDurabilityRequest {
41-
pub reducer_context: Option<ReducerContext>,
42-
pub tx_data: Arc<TxData>,
43-
}
44-
45-
/// The persistence barrier prevents durability requests from being sent to the
46-
/// durability worker while a 2PC PREPARE is pending.
47-
///
48-
/// When active:
49-
/// - The PREPARE's own durability request has already been sent to the worker.
50-
/// - All subsequent `request_durability()` calls are buffered here.
51-
/// - Once the PREPARE is confirmed durable and a COMMIT/ABORT decision is made:
52-
/// - COMMIT: buffered requests are flushed to the worker.
53-
/// - ABORT: buffered requests are discarded.
54-
#[derive(Default)]
55-
pub struct PersistenceBarrier {
56-
inner: Mutex<PersistenceBarrierInner>,
57-
}
58-
59-
#[derive(Default)]
60-
struct PersistenceBarrierInner {
61-
/// If Some, a PREPARE is pending at this offset. All durability requests
62-
/// are buffered until the barrier is lifted.
63-
active_prepare: Option<TxOffset>,
64-
/// Buffered durability requests that arrived while the barrier was active.
65-
buffered: Vec<BufferedDurabilityRequest>,
66-
}
67-
68-
impl PersistenceBarrier {
69-
pub fn new() -> Self {
70-
Self::default()
71-
}
72-
73-
/// Activate the barrier for a PREPARE at the given offset.
74-
/// Subsequent calls to `try_buffer` will return `true` (buffered).
75-
pub fn activate(&self, prepare_offset: TxOffset) {
76-
let mut inner = self.inner.lock().unwrap();
77-
assert!(
78-
inner.active_prepare.is_none(),
79-
"persistence barrier already active at offset {:?}, cannot activate for {prepare_offset}",
80-
inner.active_prepare,
81-
);
82-
inner.active_prepare = Some(prepare_offset);
83-
inner.buffered.clear();
84-
}
85-
86-
/// If the barrier is active, buffer the durability request and return None.
87-
/// If the barrier is not active, return the arguments back (caller should send normally).
88-
pub fn try_buffer(
89-
&self,
90-
reducer_context: Option<ReducerContext>,
91-
tx_data: &Arc<TxData>,
92-
) -> Option<Option<ReducerContext>> {
93-
let mut inner = self.inner.lock().unwrap();
94-
if inner.active_prepare.is_some() {
95-
inner.buffered.push(BufferedDurabilityRequest {
96-
reducer_context,
97-
tx_data: tx_data.clone(),
98-
});
99-
None // buffered successfully
100-
} else {
101-
Some(reducer_context) // not buffered, return context back
102-
}
103-
}
104-
105-
/// Deactivate the barrier and return the buffered requests.
106-
/// Called on COMMIT (to flush them) or ABORT (to discard them).
107-
pub fn deactivate(&self) -> Vec<BufferedDurabilityRequest> {
108-
let mut inner = self.inner.lock().unwrap();
109-
inner.active_prepare = None;
110-
std::mem::take(&mut inner.buffered)
111-
}
112-
113-
/// Check if the barrier is currently active.
114-
pub fn is_active(&self) -> bool {
115-
self.inner.lock().unwrap().active_prepare.is_some()
116-
}
117-
}

0 commit comments

Comments
 (0)