Skip to content

Commit 18e7c0c

Browse files
committed
replicate from db-file when start_frame_no is 1
1 parent 348c4c9 commit 18e7c0c

4 files changed

Lines changed: 56 additions & 11 deletions

File tree

libsql-wal/src/replication/replicator.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
use std::pin::Pin;
12
use std::sync::Arc;
23

34
use roaring::RoaringBitmap;
45
use tokio::sync::watch;
5-
use tokio_stream::{Stream, StreamExt};
6+
use tokio_stream::{Stream, StreamExt as _};
67

78
use crate::io::Io;
89
use crate::replication::Error;
@@ -118,12 +119,21 @@ impl<IO: Io> Replicator<IO> {
118119
// Replicating from sealed segments was not enough, so we replicate from
119120
// durable storage
120121
if let Some(replicated_until) = replicated_until {
121-
tracing::debug!("replicating from durable storage");
122-
let stream = self
123-
.shared
124-
.stored_segments
125-
.stream(&mut seen, replicated_until, self.next_frame_no)
126-
.peekable();
122+
let stream: Pin<Box<dyn Stream<Item = _> + Send>> = if self.next_frame_no == 1 {
123+
// we're replicating from scratch, read straight from the main db
124+
// file
125+
tracing::debug!("replicating main db file");
126+
Box::pin(self.shared.replicate_from_db_file(&mut seen, &tx, replicated_until))
127+
} else {
128+
tracing::debug!("replicating from durable storage");
129+
Box::pin(self
130+
.shared
131+
.stored_segments
132+
.stream(&mut seen, replicated_until, self.next_frame_no)
133+
.peekable())
134+
};
135+
136+
let stream = stream.peekable();
127137

128138
tokio::pin!(stream);
129139

libsql-wal/src/segment/current.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ impl<F> CurrentSegment<F> {
525525
if !self.is_empty() {
526526
let mut frame_offset = (tx.max_frame_no - seg_start_frame_no) as u32;
527527
loop {
528-
let buf = ZeroCopyBoxIoBuf::new(Frame::new_box_zeroed());
528+
let buf = ZeroCopyBoxIoBuf::new_uninit(Frame::new_box_zeroed());
529529
let (buf, res) = self.read_frame_offset_async(frame_offset, buf).await;
530530
res?;
531531

@@ -746,7 +746,6 @@ mod test {
746746
let mut copy = Vec::new();
747747
tmp.read_to_end(&mut copy).unwrap();
748748

749-
dbg!(copy.len(), orig.len());
750749
assert_eq!(db_payload(&copy), db_payload(&orig));
751750
}
752751

libsql-wal/src/segment/list.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,10 @@ where
138138

139139
let mut buf = ZeroCopyBuf::<Frame>::new_uninit();
140140
let mut last_replication_index = 0;
141+
let mut checkpointed = RoaringBitmap::new();
141142
while let Some((k, v)) = union.next() {
142143
let page_no = u32::from_be_bytes(k.try_into().unwrap());
144+
checkpointed.insert(page_no);
143145
tracing::trace!(page_no);
144146
let v = v.iter().min_by_key(|i| i.index).unwrap();
145147
let offset = v.value as u32;
@@ -156,6 +158,7 @@ where
156158
.await;
157159
ret?;
158160
buf = read_buf.into_inner();
161+
buf.deinit();
159162
}
160163

161164
// update the footer at the end of the db file.
@@ -174,7 +177,6 @@ where
174177
.await;
175178
ret?;
176179

177-
// todo: truncate if necessary
178180
//// TODO: make async
179181
db_file.sync_all()?;
180182

@@ -265,7 +267,7 @@ where
265267
continue
266268
}
267269

268-
let buf = ZeroCopyBoxIoBuf::new(Frame::new_box_zeroed());
270+
let buf = ZeroCopyBoxIoBuf::new_uninit(Frame::new_box_zeroed());
269271
let (buf, ret) = segment.read_frame_offset_async(*frame_offset as u32, buf).await;
270272
ret?;
271273
let mut frame = buf.into_inner();

libsql-wal/src/shared_wal.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,24 @@ use std::time::Instant;
66
use arc_swap::ArcSwap;
77
use crossbeam::deque::Injector;
88
use crossbeam::sync::Unparker;
9+
use futures::Stream;
910
use parking_lot::{Mutex, MutexGuard};
11+
use roaring::RoaringBitmap;
1012
use tokio::sync::{mpsc, watch};
1113
use uuid::Uuid;
14+
use zerocopy::FromZeroes;
1215

1316
use crate::checkpointer::CheckpointMessage;
1417
use crate::error::{Error, Result};
18+
use crate::io::buf::ZeroCopyBoxIoBuf;
1519
use crate::io::file::FileExt;
1620
use crate::io::Io;
1721
use crate::replication::storage::ReplicateFromStorage;
1822
use crate::segment::current::CurrentSegment;
23+
use crate::segment::{Frame, FrameHeader};
1924
use crate::segment_swap_strategy::SegmentSwapStrategy;
2025
use crate::transaction::{ReadTransaction, Savepoint, Transaction, TxGuard, WriteTransaction};
26+
use crate::LIBSQL_PAGE_SIZE;
2127
use libsql_sys::name::NamespaceName;
2228

2329
#[derive(Default)]
@@ -334,6 +340,34 @@ impl<IO: Io> SharedWal<IO> {
334340
pub fn namespace(&self) -> &NamespaceName {
335341
&self.namespace
336342
}
343+
344+
/// read frames from the main db file.
345+
pub(crate) fn replicate_from_db_file<'a>(
346+
&'a self,
347+
seen: &'a RoaringBitmap,
348+
tx: &'a ReadTransaction<IO::File>,
349+
until: u64,
350+
) -> impl Stream<Item = crate::replication::Result<Box<Frame>>> + Send + 'a {
351+
async_stream::try_stream! {
352+
let mut all = RoaringBitmap::new();
353+
all.insert_range(1..=tx.db_size);
354+
let to_take = all - seen;
355+
for page_no in to_take {
356+
let mut frame = Frame::new_box_zeroed();
357+
*frame.header_mut() = FrameHeader {
358+
page_no: page_no.into(),
359+
size_after: 0.into(),
360+
// we don't really know what the frame_no is, so we set it to a number less that any other frame_no
361+
frame_no: until.into(),
362+
};
363+
let buf = unsafe { ZeroCopyBoxIoBuf::new_uninit_partial(frame, size_of::<FrameHeader>()) };
364+
let (buf, ret) = self.db_file.read_exact_at_async(buf, (page_no as u64 - 1) * LIBSQL_PAGE_SIZE as u64).await;
365+
ret?;
366+
let frame = buf.into_inner();
367+
yield frame;
368+
}
369+
}
370+
}
337371
}
338372

339373
#[cfg(test)]

0 commit comments

Comments
 (0)