add WAL API methods to the rust bindings and extend result of wal_insert_frame method

This commit is contained in:
Nikita Sivukhin
2025-07-28 17:06:10 +04:00
parent 1e4e8c243a
commit 09b18f6b6e
4 changed files with 69 additions and 7 deletions

View File

@@ -37,11 +37,12 @@ pub mod transaction;
pub mod value;
use transaction::TransactionBehavior;
use turso_core::types::WalInsertInfo;
pub use value::Value;
pub use params::params_from_iter;
pub use params::IntoParams;
use crate::params::*;
use std::fmt::Debug;
use std::num::NonZero;
use std::sync::{Arc, Mutex};
@@ -54,6 +55,8 @@ pub enum Error {
MutexError(String),
#[error("SQL execution failure: `{0}`")]
SqlExecutionFailure(String),
#[error("WAL operation error: `{0}`")]
WalOperationError(String),
}
impl From<turso_core::LimboError> for Error {
@@ -170,6 +173,51 @@ impl Connection {
stmt.execute(params).await
}
pub fn wal_frame_count(&self) -> Result<u64> {
let conn = self
.inner
.lock()
.map_err(|e| Error::MutexError(e.to_string()))?;
conn.wal_frame_count()
.map_err(|e| Error::WalOperationError(format!("wal_insert_begin failed: {}", e)))
}
pub fn wal_insert_begin(&self) -> Result<()> {
let conn = self
.inner
.lock()
.map_err(|e| Error::MutexError(e.to_string()))?;
conn.wal_insert_begin()
.map_err(|e| Error::WalOperationError(format!("wal_insert_begin failed: {}", e)))
}
pub fn wal_insert_end(&self) -> Result<()> {
let conn = self
.inner
.lock()
.map_err(|e| Error::MutexError(e.to_string()))?;
conn.wal_insert_end()
.map_err(|e| Error::WalOperationError(format!("wal_insert_end failed: {}", e)))
}
pub fn wal_insert_frame(&self, frame_no: u32, frame: &[u8]) -> Result<WalInsertInfo> {
let conn = self
.inner
.lock()
.map_err(|e| Error::MutexError(e.to_string()))?;
conn.wal_insert_frame(frame_no, frame)
.map_err(|e| Error::WalOperationError(format!("wal_insert_frame failed: {}", e)))
}
pub fn wal_get_frame(&self, frame_no: u32, frame: &mut [u8]) -> Result<()> {
let conn = self
.inner
.lock()
.map_err(|e| Error::MutexError(e.to_string()))?;
conn.wal_get_frame(frame_no, frame)
.map_err(|e| Error::WalOperationError(format!("wal_insert_frame failed: {}", e)))
}
/// Prepare a SQL statement for later execution.
pub async fn prepare(&self, sql: &str) -> Result<Statement> {
let conn = self
@@ -351,6 +399,12 @@ impl Statement {
cols
}
/// Reset internal statement state after previous execution so it can be reused again
pub fn reset(&self) {
let mut stmt = self.inner.lock().unwrap();
stmt.reset();
}
}
/// Column information.

View File

@@ -217,6 +217,7 @@ macro_rules! named_tuple_into_params {
}
}
named_tuple_into_params!(1: (0 A));
named_tuple_into_params!(2: (0 A), (1 B));
named_tuple_into_params!(3: (0 A), (1 B), (2 C));
named_tuple_into_params!(4: (0 A), (1 B), (2 C), (3 D));
@@ -233,6 +234,7 @@ named_tuple_into_params!(14: (0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7
named_tuple_into_params!(15: (0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7 H), (8 I), (9 J), (10 K), (11 L), (12 M), (13 N), (14 O));
named_tuple_into_params!(16: (0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7 H), (8 I), (9 J), (10 K), (11 L), (12 M), (13 N), (14 O), (15 P));
tuple_into_params!(1: (0 A));
tuple_into_params!(2: (0 A), (1 B));
tuple_into_params!(3: (0 A), (1 B), (2 C));
tuple_into_params!(4: (0 A), (1 B), (2 C), (3 D));

View File

@@ -47,6 +47,8 @@ use crate::storage::{header_accessor, wal::DummyWAL};
use crate::translate::optimizer::optimize_plan;
use crate::translate::pragma::TURSO_CDC_DEFAULT_TABLE_NAME;
#[cfg(feature = "fs")]
use crate::types::WalInsertInfo;
#[cfg(feature = "fs")]
use crate::util::{IOExt, OpenMode, OpenOptions};
use crate::vtab::VirtualTable;
use core::str;
@@ -1037,15 +1039,16 @@ impl Connection {
}
#[cfg(feature = "fs")]
pub fn wal_get_frame(&self, frame_no: u32, frame: &mut [u8]) -> Result<Arc<Completion>> {
self.pager.borrow().wal_get_frame(frame_no, frame)
pub fn wal_get_frame(&self, frame_no: u32, frame: &mut [u8]) -> Result<()> {
let c = self.pager.borrow().wal_get_frame(frame_no, frame)?;
self._db.io.wait_for_completion(c)
}
/// Insert `frame` (header included) at the position `frame_no` in the WAL
/// If WAL already has frame at that position - turso-db will compare content of the page and either report conflict or return OK
/// If attempt to write frame at the position `frame_no` will create gap in the WAL - method will return error
#[cfg(feature = "fs")]
pub fn wal_insert_frame(&self, frame_no: u32, frame: &[u8]) -> Result<()> {
pub fn wal_insert_frame(&self, frame_no: u32, frame: &[u8]) -> Result<WalInsertInfo> {
self.pager.borrow().wal_insert_frame(frame_no, frame)
}

View File

@@ -7,7 +7,7 @@ use crate::storage::sqlite3_ondisk::{
self, parse_wal_frame_header, DatabaseHeader, PageContent, PageType,
};
use crate::storage::wal::{CheckpointResult, Wal};
use crate::types::IOResult;
use crate::types::{IOResult, WalInsertInfo};
use crate::util::IOExt as _;
use crate::{return_if_io, Completion};
use crate::{turso_assert, Buffer, Connection, LimboError, Result};
@@ -1173,7 +1173,7 @@ impl Pager {
}
#[instrument(skip_all, level = Level::DEBUG)]
pub fn wal_insert_frame(&self, frame_no: u32, frame: &[u8]) -> Result<()> {
pub fn wal_insert_frame(&self, frame_no: u32, frame: &[u8]) -> Result<WalInsertInfo> {
let mut wal = self.wal.borrow_mut();
let (header, raw_page) = parse_wal_frame_header(frame);
wal.write_frame_raw(
@@ -1201,7 +1201,10 @@ impl Pager {
}
self.dirty_pages.borrow_mut().clear();
}
Ok(())
Ok(WalInsertInfo {
page_no: header.page_number as usize,
is_commit: header.is_commit_frame(),
})
}
#[instrument(skip_all, level = Level::DEBUG, name = "pager_checkpoint",)]