From e45a807f0e65cdc79bf50850ea1b74cfb4fc322c Mon Sep 17 00:00:00 2001 From: sonhmai <14060682+sonhmai@users.noreply.github.com> Date: Sat, 18 Jan 2025 11:20:36 +0700 Subject: [PATCH] core: allocate 2 registers for checkpoint opcode execution --- cli/tests/test_journal.rs | 12 +++++++----- core/translate/mod.rs | 24 ++++++++++++++++++------ core/vdbe/explain.rs | 7 +++++-- core/vdbe/insn.rs | 6 +++--- core/vdbe/mod.rs | 26 +++++++++++++++++--------- 5 files changed, 50 insertions(+), 25 deletions(-) diff --git a/cli/tests/test_journal.rs b/cli/tests/test_journal.rs index fa3b851df..3d34719b1 100644 --- a/cli/tests/test_journal.rs +++ b/cli/tests/test_journal.rs @@ -4,7 +4,7 @@ mod tests { use assert_cmd::cargo::cargo_bin; use rexpect::error::*; - use rexpect::session::spawn_command; + use rexpect::session::{spawn_command, PtySession}; use std::process; #[test] @@ -14,9 +14,7 @@ mod tests { child.exp_regex(".?")?; child.send_line("pragma journal_mode;")?; child.exp_string("wal")?; - child.send_line(".quit")?; - child.exp_eof()?; - Ok(()) + quit(&mut child) } #[test] @@ -26,6 +24,10 @@ mod tests { child.exp_regex(".?")?; child.send_line("pragma wal_checkpoint;")?; child.exp_string("0|0|0")?; + quit(&mut child) + } + + fn quit(child: &mut PtySession) -> Result<(), Error> { child.send_line(".quit")?; child.exp_eof()?; Ok(()) @@ -33,7 +35,7 @@ mod tests { fn run_cli() -> process::Command { let bin_path = cargo_bin("limbo"); - let mut cmd = process::Command::new(bin_path); + let cmd = process::Command::new(bin_path); cmd } } diff --git a/core/translate/mod.rs b/core/translate/mod.rs index c37e5dbbd..31731dd85 100644 --- a/core/translate/mod.rs +++ b/core/translate/mod.rs @@ -25,6 +25,7 @@ pub(crate) mod subquery; use crate::schema::Schema; use crate::storage::pager::Pager; use crate::storage::sqlite3_ondisk::{DatabaseHeader, MIN_PAGE_CACHE_SIZE}; +use crate::storage::wal::CheckpointMode; use crate::translate::delete::translate_delete; use crate::util::PRIMARY_KEY_AUTOMATIC_INDEX_NAME_PREFIX; use crate::vdbe::builder::CursorType; @@ -37,7 +38,6 @@ use std::cell::RefCell; use std::fmt::Display; use std::rc::{Rc, Weak}; use std::str::FromStr; -use crate::storage::wal::CheckpointMode; /// Translate SQL statement into bytecode program. pub fn translate( @@ -594,7 +594,7 @@ fn update_pragma( Ok(()) } PragmaName::WalCheckpoint => { - // TODO + query_pragma("wal_checkpoint", header, program)?; Ok(()) } } @@ -616,26 +616,38 @@ fn query_pragma( value: database_header.borrow().default_page_cache_size.into(), dest: register, }); + program.emit_insn(Insn::ResultRow { + start_reg: register, + count: 1, + }); } PragmaName::JournalMode => { program.emit_insn(Insn::String8 { value: "wal".into(), dest: register, }); + program.emit_insn(Insn::ResultRow { + start_reg: register, + count: 1, + }); } PragmaName::WalCheckpoint => { + // Checkpoint uses 3 registers: P1, P2, P3. Ref Insn::Checkpoint for more info. + // Allocate two more here as one was allocated at the top. + program.alloc_register(); + program.alloc_register(); program.emit_insn(Insn::Checkpoint { database: 0, checkpoint_mode: CheckpointMode::Passive, dest: register, }); + program.emit_insn(Insn::ResultRow { + start_reg: register, + count: 3, + }); } } - program.emit_insn(Insn::ResultRow { - start_reg: register, - count: 1, - }); Ok(()) } diff --git a/core/vdbe/explain.rs b/core/vdbe/explain.rs index e959af17e..2d508f4c9 100644 --- a/core/vdbe/explain.rs +++ b/core/vdbe/explain.rs @@ -2,7 +2,6 @@ use crate::vdbe::builder::CursorType; use super::{Insn, InsnReference, OwnedValue, Program}; use std::rc::Rc; -use crate::storage::wal::CheckpointMode; pub fn insn_to_str( program: &Program, @@ -85,7 +84,11 @@ pub fn insn_to_str( 0, format!("r[{}]=~r[{}]", dest, reg), ), - Insn::Checkpoint { database, checkpoint_mode: _, dest } => ( + Insn::Checkpoint { + database, + checkpoint_mode: _, + dest, + } => ( "Checkpoint", *database as i32, *dest as i32, diff --git a/core/vdbe/insn.rs b/core/vdbe/insn.rs index 093041456..5dd1a7b13 100644 --- a/core/vdbe/insn.rs +++ b/core/vdbe/insn.rs @@ -1,9 +1,9 @@ use std::num::NonZero; use super::{AggFunc, BranchOffset, CursorID, FuncCtx, PageIdx}; +use crate::storage::wal::CheckpointMode; use crate::types::{OwnedRecord, OwnedValue}; use limbo_macros::Description; -use crate::storage::wal::CheckpointMode; #[derive(Description, Debug)] pub enum Insn { @@ -69,9 +69,9 @@ pub enum Insn { }, // Checkpoint the database (applying wal file content to database file). Checkpoint { - database: usize, // checkpoint database P1 + database: usize, // checkpoint database P1 checkpoint_mode: CheckpointMode, // P2 checkpoint mode - dest: usize, // P3 checkpoint result + dest: usize, // P3 checkpoint result }, // Divide lhs by rhs and place the remainder in dest register. Remainder { diff --git a/core/vdbe/mod.rs b/core/vdbe/mod.rs index 5a720afd1..1732a8f7f 100644 --- a/core/vdbe/mod.rs +++ b/core/vdbe/mod.rs @@ -362,16 +362,24 @@ impl Program { state.registers[*dest] = exec_bit_not(&state.registers[*reg]); state.pc += 1; } - Insn::Checkpoint { database: _, checkpoint_mode: _, dest } => { - // Write 1 (checkpoint SQLITE_BUSY) or 0 (not busy). - // fixme currently hard coded not implemented - let result = self.connection - .upgrade() - .unwrap() - .checkpoint(); + Insn::Checkpoint { + database: _, + checkpoint_mode: _, + dest, + } => { + let result = self.connection.upgrade().unwrap().checkpoint(); match result { - Ok(()) => state.registers[*dest] = OwnedValue::Integer(0), - Err(err) => state.registers[*dest] = OwnedValue::Integer(1) + Ok(()) => { + // https://sqlite.org/pragma.html#pragma_wal_checkpoint + // TODO make 2nd and 3rd cols available through checkpoint method + // 1st col: 1 (checkpoint SQLITE_BUSY) or 0 (not busy). + state.registers[*dest] = OwnedValue::Integer(0); + // 2nd col: # modified pages written to wal file + state.registers[*dest + 1] = OwnedValue::Integer(0); + // 3rd col: # pages moved to db after checkpoint + state.registers[*dest + 2] = OwnedValue::Integer(0); + } + Err(_err) => state.registers[*dest] = OwnedValue::Integer(1), } state.pc += 1;