Skip to content

Commit e55dd89

Browse files
committed
use read txn in replicator
1 parent 961ecb8 commit e55dd89

4 files changed

Lines changed: 106 additions & 76 deletions

File tree

libsql-wal/src/replication/replicator.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,13 @@ impl<IO: Io> Replicator<IO> {
5858
tracing::debug!(most_recent_frame_no, "new frame_no available");
5959

6060
let mut commit_frame_no = 0;
61+
let tx = self.shared.begin_read(u64::MAX);
6162
// we have stuff to replicate
6263
if most_recent_frame_no >= self.next_frame_no {
6364
// first replicate the most recent version of each page from the current
6465
// segment. We also return how far back we have replicated from the current log
65-
let current = self.shared.current.load();
6666
let mut seen = RoaringBitmap::new();
67-
let (stream, replicated_until, size_after) = current.frame_stream_from(self.next_frame_no, &mut seen);
67+
let (stream, replicated_until) = tx.current.frame_stream_from(self.next_frame_no, &mut seen, &tx);
6868
let should_replicate_from_tail = replicated_until != self.next_frame_no;
6969

7070
{
@@ -78,7 +78,7 @@ impl<IO: Io> Replicator<IO> {
7878
let mut frame = frame.map_err(|e| Error::CurrentSegment(e.into()))?;
7979
commit_frame_no = frame.header().frame_no().max(commit_frame_no);
8080
if stream.peek().await.is_none() && !should_replicate_from_tail {
81-
frame.header_mut().set_size_after(size_after);
81+
frame.header_mut().set_size_after(tx.db_size);
8282
self.next_frame_no = commit_frame_no + 1;
8383
}
8484

@@ -90,9 +90,9 @@ impl<IO: Io> Replicator<IO> {
9090
// wee need to take frames from the sealed segments.
9191
if should_replicate_from_tail {
9292
let replicated_until = {
93-
let (stream, replicated_until) = current
93+
let (stream, replicated_until) = tx.current
9494
.tail()
95-
.stream_pages_from(replicated_until, self.next_frame_no, &mut seen).await;
95+
.stream_pages_from(replicated_until, self.next_frame_no, &mut seen, &tx).await;
9696
tokio::pin!(stream);
9797

9898
tracing::debug!(replicated_until, "replicating from tail");
@@ -105,7 +105,7 @@ impl<IO: Io> Replicator<IO> {
105105
let mut frame = frame.map_err(|e| Error::SealedSegment(e.into()))?;
106106
commit_frame_no = frame.header().frame_no().max(commit_frame_no);
107107
if stream.peek().await.is_none() && !should_replicate_from_storage {
108-
frame.header_mut().set_size_after(size_after);
108+
frame.header_mut().set_size_after(tx.db_size);
109109
self.next_frame_no = commit_frame_no + 1;
110110
}
111111

@@ -132,7 +132,7 @@ impl<IO: Io> Replicator<IO> {
132132
let mut frame = frame?;
133133
commit_frame_no = frame.header().frame_no().max(commit_frame_no);
134134
if stream.peek().await.is_none() {
135-
frame.header_mut().set_size_after(size_after);
135+
frame.header_mut().set_size_after(tx.db_size);
136136
self.next_frame_no = commit_frame_no + 1;
137137
}
138138

libsql-wal/src/replication/storage.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ where
6161
let segment = match maybe_seg {
6262
Some(ref seg) => seg,
6363
None => {
64+
tracing::debug!(key = %key, "fetching segment");
6465
maybe_seg = Some(storage.fetch_segment_data(&namespace, &key, None).await?);
6566
maybe_seg.as_ref().unwrap()
6667
},

libsql-wal/src/segment/current.rs

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use crate::io::file::FileExt;
2424
use crate::io::Inspect;
2525
use crate::segment::{checked_frame_offset, SegmentFlags};
2626
use crate::segment::{frame_offset, page_offset, sealed::SealedSegment};
27-
use crate::transaction::{Transaction, TxGuardOwned, TxGuardShared};
27+
use crate::transaction::{ReadTransaction, Transaction, TxGuardOwned, TxGuardShared};
2828
use crate::{LIBSQL_MAGIC, LIBSQL_PAGE_SIZE, LIBSQL_WAL_VERSION};
2929

3030
use super::list::SegmentList;
@@ -507,22 +507,23 @@ impl<F> CurrentSegment<F> {
507507
&'a self,
508508
start_frame_no: u64,
509509
seen: &'a mut RoaringBitmap,
510-
) -> (impl Stream<Item = Result<Box<Frame>>> + 'a, u64, u32)
510+
// not actually used, but ensures that a read lock is held while this method id called
511+
tx: &'a ReadTransaction<F>,
512+
) -> (impl Stream<Item = Result<Box<Frame>>> + 'a, u64)
511513
where
512514
F: FileExt,
513515
{
514-
let (seg_start_frame_no, last_committed, db_size) =
515-
self.with_header(|h| (h.start_frame_no.get(), h.last_committed(), h.size_after()));
516+
let seg_start_frame_no = tx.current.with_header(|h| h.start_frame_no.get());
516517
let replicated_until = seg_start_frame_no
517518
// if current is empty, start_frame_no doesn't exist
518-
.min(last_committed)
519+
.min(tx.max_frame_no)
519520
.max(start_frame_no);
520521

521522
// TODO: optim, we could read less frames if we had a mapping from frame_no to page_no in
522523
// the index
523524
let stream = async_stream::try_stream! {
524525
if !self.is_empty() {
525-
let mut frame_offset = (last_committed - seg_start_frame_no) as u32;
526+
let mut frame_offset = (tx.max_frame_no - seg_start_frame_no) as u32;
526527
loop {
527528
let buf = ZeroCopyBoxIoBuf::new(Frame::new_box_zeroed());
528529
let (buf, res) = self.read_frame_offset_async(frame_offset, buf).await;
@@ -551,7 +552,7 @@ impl<F> CurrentSegment<F> {
551552
}
552553
};
553554

554-
(stream, replicated_until, db_size)
555+
(stream, replicated_until)
555556
}
556557

557558
fn recompute_checksum(&self, start_offset: u32, until_offset: u32) -> Result<u32>
@@ -714,18 +715,20 @@ mod test {
714715
.unwrap();
715716
}
716717

717-
let mut seen = RoaringBitmap::new();
718-
let current = shared.current.load();
719-
let (stream, replicated_until, size_after) = current.frame_stream_from(1, &mut seen);
720-
tokio::pin!(stream);
721-
assert_eq!(replicated_until, 1);
722-
assert_eq!(size_after, 6);
723-
724718
let mut tmp = tempfile().unwrap();
725-
while let Some(frame) = stream.next().await {
726-
let frame = frame.unwrap();
727-
let offset = (frame.header().page_no() - 1) * 4096;
728-
tmp.write_all_at(frame.data(), offset as _).unwrap();
719+
{
720+
let tx = shared.begin_read(u64::MAX);
721+
let mut seen = RoaringBitmap::new();
722+
let (stream, replicated_until) = tx.current.frame_stream_from(1, &mut seen, &tx);
723+
tokio::pin!(stream);
724+
assert_eq!(replicated_until, 1);
725+
assert_eq!(tx.db_size, 6);
726+
727+
while let Some(frame) = stream.next().await {
728+
let frame = frame.unwrap();
729+
let offset = (frame.header().page_no() - 1) * 4096;
730+
tmp.write_all_at(frame.data(), offset as _).unwrap();
731+
}
729732
}
730733

731734
seal_current_segment(&shared);
@@ -743,6 +746,7 @@ mod test {
743746
let mut copy = Vec::new();
744747
tmp.read_to_end(&mut copy).unwrap();
745748

749+
dbg!(copy.len(), orig.len());
746750
assert_eq!(db_payload(&copy), db_payload(&orig));
747751
}
748752

@@ -768,11 +772,11 @@ mod test {
768772

769773
let mut seen = RoaringBitmap::new();
770774
{
771-
let current = shared.current.load();
772-
let (stream, replicated_until, size_after) = current.frame_stream_from(1, &mut seen);
775+
let tx = shared.begin_read(u64::MAX);
776+
let (stream, replicated_until) = tx.current.frame_stream_from(1, &mut seen, &tx);
773777
tokio::pin!(stream);
774778
assert_eq!(replicated_until, 60);
775-
assert_eq!(size_after, 9);
779+
assert_eq!(tx.db_size, 9);
776780
assert_eq!(stream.fold(0, |count, _| count + 1).await, 6);
777781
}
778782
assert_debug_snapshot!(seen);
@@ -787,12 +791,12 @@ mod test {
787791
conn.execute("create table test (x)", ()).unwrap();
788792

789793
let mut seen = RoaringBitmap::new();
790-
let current = shared.current.load();
791-
let (stream, replicated_until, size_after) = current.frame_stream_from(100, &mut seen);
794+
let tx = shared.begin_read(u64::MAX);
795+
let (stream, replicated_until) = tx.current.frame_stream_from(100, &mut seen, &tx);
792796
tokio::pin!(stream);
793797
assert_eq!(replicated_until, 100);
794798
assert_eq!(stream.fold(0, |count, _| count + 1).await, 0);
795-
assert_eq!(size_after, 2);
799+
assert_eq!(tx.db_size, 2);
796800
}
797801

798802
#[tokio::test]
@@ -805,11 +809,11 @@ mod test {
805809
seal_current_segment(&shared);
806810

807811
let mut seen = RoaringBitmap::new();
808-
let current = shared.current.load();
809-
let (stream, replicated_until, size_after) = current.frame_stream_from(1, &mut seen);
812+
let tx = shared.begin_read(u64::MAX);
813+
let (stream, replicated_until) = tx.current.frame_stream_from(1, &mut seen, &tx);
810814
tokio::pin!(stream);
811815
assert_eq!(replicated_until, 2);
812-
assert_eq!(size_after, 2);
816+
assert_eq!(tx.db_size, 2);
813817
assert_eq!(stream.fold(0, |count, _| count + 1).await, 0);
814818
}
815819

@@ -1014,8 +1018,8 @@ mod test {
10141018
}
10151019
}
10161020

1017-
fn db_payload(db: &[u8]) -> &[u8] {
1021+
fn db_payload(db: &[u8]) -> u32 {
10181022
let size = (db.len() / 4096) * 4096;
1019-
&db[..size]
1023+
crc32fast::hash(&db[..size])
10201024
}
10211025
}

libsql-wal/src/segment/list.rs

Lines changed: 65 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::error::Result;
1515
use crate::io::buf::{ZeroCopyBoxIoBuf, ZeroCopyBuf};
1616
use crate::io::{FileExt, Io};
1717
use crate::segment::Frame;
18+
use crate::transaction::ReadTransaction;
1819
use crate::{LibsqlFooter, LIBSQL_MAGIC, LIBSQL_PAGE_SIZE, LIBSQL_WAL_VERSION};
1920

2021
use super::Segment;
@@ -209,11 +210,13 @@ where
209210
/// returns a stream of pages from the sealed segment list, and what's the lowest replication index
210211
/// that was covered. If the returned index is less than start frame_no, the missing frames
211212
/// must be read somewhere else.
212-
pub async fn stream_pages_from<'a>(
213+
pub async fn stream_pages_from<'a, F>(
213214
&self,
214215
current_fno: u64,
215216
until_fno: u64,
216217
seen: &'a mut RoaringBitmap,
218+
// not actually used, but ensures that a read lock is held while this method id called
219+
_tx: &ReadTransaction<F>,
217220
) -> (
218221
impl Stream<Item = crate::error::Result<Box<Frame>>> + 'a,
219222
u64,
@@ -434,10 +437,13 @@ mod test {
434437

435438
seal_current_segment(&shared);
436439

437-
let current = shared.current.load();
438-
let segment_list = current.tail();
440+
let tx = shared.begin_read(u64::MAX);
439441
let mut seen = RoaringBitmap::new();
440-
let (stream, _) = segment_list.stream_pages_from(0, 0, &mut seen).await;
442+
let (stream, _) = tx
443+
.current
444+
.tail()
445+
.stream_pages_from(0, 0, &mut seen, &tx)
446+
.await;
441447
tokio::pin!(stream);
442448

443449
let mut file = NamedTempFile::new().unwrap();
@@ -485,10 +491,13 @@ mod test {
485491

486492
seal_current_segment(&shared);
487493

488-
let current = shared.current.load();
489-
let segment_list = current.tail();
494+
let tx = shared.begin_read(u64::MAX);
490495
let mut seen = RoaringBitmap::new();
491-
let (stream, replicated_until) = segment_list.stream_pages_from(0, 10, &mut seen).await;
496+
let (stream, replicated_until) = tx
497+
.current
498+
.tail()
499+
.stream_pages_from(0, 10, &mut seen, &tx)
500+
.await;
492501
tokio::pin!(stream);
493502

494503
assert_eq!(replicated_until, 10);
@@ -513,10 +522,13 @@ mod test {
513522

514523
seal_current_segment(&shared);
515524

516-
let current = shared.current.load();
517-
let segment_list = current.tail();
525+
let tx = shared.begin_read(u64::MAX);
518526
let mut seen = RoaringBitmap::from_sorted_iter([1]).unwrap();
519-
let (stream, replicated_until) = segment_list.stream_pages_from(0, 1, &mut seen).await;
527+
let (stream, replicated_until) = tx
528+
.current
529+
.tail()
530+
.stream_pages_from(0, 1, &mut seen, &tx)
531+
.await;
520532
tokio::pin!(stream);
521533

522534
assert_eq!(replicated_until, 1);
@@ -541,22 +553,27 @@ mod test {
541553

542554
seal_current_segment(&shared);
543555

544-
let current = shared.current.load();
545-
let segment_list = current.tail();
546-
let mut seen = RoaringBitmap::new();
547-
let (stream, replicated_until) = segment_list.stream_pages_from(0, 1, &mut seen).await;
548-
tokio::pin!(stream);
556+
let mut tmp = tempfile().unwrap();
557+
let mut last_offset = 0;
549558

550-
assert_eq!(replicated_until, 1);
559+
{
560+
let tx = shared.begin_read(u64::MAX);
561+
let mut seen = RoaringBitmap::new();
562+
let (stream, replicated_until) = tx
563+
.current
564+
.tail()
565+
.stream_pages_from(0, 1, &mut seen, &tx)
566+
.await;
567+
tokio::pin!(stream);
551568

552-
let mut tmp = tempfile().unwrap();
569+
assert_eq!(replicated_until, 1);
553570

554-
let mut last_offset = 0;
555-
while let Some(frame) = stream.next().await {
556-
let frame = frame.unwrap();
557-
let offset = (frame.header().page_no() - 1) * 4096;
558-
tmp.write_all_at(frame.data(), offset as u64).unwrap();
559-
last_offset = last_offset.max(frame.header().frame_no());
571+
while let Some(frame) = stream.next().await {
572+
let frame = frame.unwrap();
573+
let offset = (frame.header().page_no() - 1) * 4096;
574+
tmp.write_all_at(frame.data(), offset as u64).unwrap();
575+
last_offset = last_offset.max(frame.header().frame_no());
576+
}
560577
}
561578

562579
for _ in 0..10 {
@@ -565,21 +582,26 @@ mod test {
565582

566583
seal_current_segment(&shared);
567584

568-
let mut seen = RoaringBitmap::new();
569-
let (stream, replicated_until) = segment_list
570-
.stream_pages_from(0, last_offset, &mut seen)
571-
.await;
572-
tokio::pin!(stream);
585+
{
586+
let tx = shared.begin_read(u64::MAX);
587+
let mut seen = RoaringBitmap::new();
588+
let (stream, replicated_until) = tx
589+
.current
590+
.tail()
591+
.stream_pages_from(0, last_offset, &mut seen, &tx)
592+
.await;
593+
tokio::pin!(stream);
573594

574-
assert_eq!(replicated_until, last_offset);
595+
assert_eq!(replicated_until, last_offset);
575596

576-
while let Some(frame) = stream.next().await {
577-
let frame = frame.unwrap();
578-
let offset = (frame.header().page_no() - 1) * 4096;
579-
tmp.write_all_at(frame.data(), offset as u64).unwrap();
580-
}
597+
while let Some(frame) = stream.next().await {
598+
let frame = frame.unwrap();
599+
let offset = (frame.header().page_no() - 1) * 4096;
600+
tmp.write_all_at(frame.data(), offset as u64).unwrap();
601+
}
581602

582-
*shared.durable_frame_no.lock() = 999999;
603+
*shared.durable_frame_no.lock() = 999999;
604+
}
583605

584606
shared.checkpoint().await.unwrap();
585607
tmp.seek(std::io::SeekFrom::Start(0)).unwrap();
@@ -618,10 +640,13 @@ mod test {
618640
}
619641
seal_current_segment(&shared);
620642

621-
let current = shared.current.load();
622-
let segment_list = current.tail();
643+
let tx = shared.begin_read(u64::MAX);
623644
let mut seen = RoaringBitmap::new();
624-
let (stream, replicated_from) = segment_list.stream_pages_from(0, 0, &mut seen).await;
645+
let (stream, replicated_from) = tx
646+
.current
647+
.tail()
648+
.stream_pages_from(0, 0, &mut seen, &tx)
649+
.await;
625650
tokio::pin!(stream);
626651

627652
let mut count = 0;
@@ -633,8 +658,8 @@ mod test {
633658
assert_eq!(replicated_from, 13);
634659
}
635660

636-
fn db_payload(db: &[u8]) -> &[u8] {
661+
fn db_payload(db: &[u8]) -> u32 {
637662
let size = (db.len() / 4096) * 4096;
638-
&db[..size]
663+
crc32fast::hash(&db[..size])
639664
}
640665
}

0 commit comments

Comments
 (0)