core: allocate 2 registers for checkpoint opcode execution

This commit is contained in:
sonhmai
2025-01-18 11:20:36 +07:00
committed by sonhmai
parent cb631dafdc
commit e45a807f0e
5 changed files with 50 additions and 25 deletions

View File

@@ -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
}
}

View File

@@ -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(())
}

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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;