added hlc logic

This commit is contained in:
2025-07-11 13:29:34 +02:00
parent 41472e02ad
commit 0c304d7900
11 changed files with 96 additions and 394 deletions

67
src-tauri/src/crdt/hlc.rs Normal file
View File

@ -0,0 +1,67 @@
use rusqlite::{params, Connection, Result};
use std::sync::{Arc, Mutex};
use uhlc::{Timestamp, HLC};
use uuid::Uuid;
const HLC_SETTING_TYPE: &str = "hlc_timestamp";
pub const GET_HLC_FUNCTION: &str = "get_hlc_timestamp";
pub const CRDT_SETTINGS_TABLE: &str = "haex_crdt_settings";
pub struct HlcService(pub Arc<Mutex<HLC>>);
pub fn setup_hlc(conn: &mut Connection) -> Result<()> {
// 1. Lade den letzten HLC-Zustand oder erstelle einen neuen.
let hlc = conn
.query_row(
"SELECT value FROM {CRDT_SETTINGS_TABLE} meta WHERE type = ?1",
params![HLC_SETTING_TYPE],
|row| {
let state_str: String = row.get(0)?;
let timestamp = Timestamp::from_str(&state_str)
.map_err(|_| rusqlite::Error::ExecuteReturnedResults)?; // Konvertiere den Fehler
Ok(HLC::new(timestamp))
},
)
.unwrap_or_else(|_| HLC::default()); // Bei Fehler (z.B. nicht gefunden) -> neuen HLC erstellen.
let hlc_arc = Arc::new(Mutex::new(hlc));
// 2. Erstelle eine Klon für die SQL-Funktion und speichere den Zustand bei jeder neuen Timestamp-Generierung.
let hlc_clone = hlc_arc.clone();
let db_conn_arc = Arc::new(Mutex::new(conn.try_clone()?));
conn.create_scalar_function(
GET_HLC_FUNCTION,
0,
rusqlite::functions::FunctionFlags::SQLITE_UTF8
| rusqlite::functions::FunctionFlags::SQLITE_DETERMINISTIC,
move |_| {
let mut hlc = hlc_clone.lock().unwrap();
let new_timestamp = hlc.new_timestamp();
let timestamp_str = new_timestamp.to_string();
// 3. Speichere den neuen Zustand sofort zurück in die DB.
// UPSERT-Logik: Ersetze den Wert, falls der Schlüssel existiert, sonst füge ihn ein.
let db_conn = db_conn_arc.lock().unwrap();
db_conn
.execute(
"INSERT INTO {CRDT_SETTINGS_TABLE} (id, type, value) VALUES (?1, ?2, ?3)
ON CONFLICT(type) DO UPDATE SET value = excluded.value",
params![
Uuid::new_v4().to_string(), // Generiere eine neue ID für den Fall eines INSERTs
HLC_SETTING_TYPE,
&timestamp_str
],
)
.expect("HLC state could not be persisted."); // In Prod sollte hier ein besseres Error-Handling hin.
Ok(timestamp_str)
},
)?;
// Hinweis: Den HLC-Service im Tauri-State zu managen ist nicht mehr zwingend,
// da die SQL-Funktion nun alles Notwendige über geklonte Arcs erhält.
// Falls du ihn dennoch für andere Commands brauchst, kannst du ihn im State speichern.
Ok(())
}

View File

@ -0,0 +1,4 @@
pub mod hlc;
pub mod log;
pub mod proxy;
pub mod trigger;

View File

@ -1,7 +1,6 @@
// In src-tauri/src/sql_proxy.rs
use rusqlite::Connection;
use sqlparser::ast::Statement;
use sqlparser::ast::{ColumnDef, DataType, Expr, Ident, Query, Statement, TableWithJoins, Value};
use sqlparser::dialect::SQLiteDialect;
use sqlparser::parser::Parser;
@ -9,11 +8,9 @@ use sqlparser::visit_mut::{self, VisitorMut};
use std::ops::ControlFlow;
// Der Name der Tombstone-Spalte als Konstante, um "Magic Strings" zu vermeiden.
pub const TOMBSTONE_COLUMN_NAME: &str = "tombstone";
const EXCLUDED_TABLES: &[&str] = &["crdt_log"];
pub const TOMBSTONE_COLUMN_NAME: &str = "haex_tombstone";
const EXCLUDED_TABLES: &[&str] = &["haex_crdt_log"];
// Die Hauptstruktur unseres Proxys.
// Sie ist zustandslos, da wir uns gegen einen Schema-Cache entschieden haben.
pub struct SqlProxy;
impl SqlProxy {

View File

@ -1,8 +1,10 @@
// In src-tauri/src/trigger_manager.rs -> impl<'a> TriggerManager<'a>
// In einem neuen Modul, z.B. src-tauri/src/trigger_manager.rs
use crate::sql_proxy::ColumnInfo;
use rusqlite::{Result, Transaction};
use crate::crdt::proxy::ColumnInfo;
use rusqlite::{params, Connection, Result, Transaction};
use std::sync::{Arc, Mutex};
use tauri::AppHandle;
pub struct TriggerManager<'a> {
tx: &'a Transaction<'a>,
@ -94,7 +96,7 @@ impl<'a> TriggerManager<'a> {
)).collect::<Vec<_>>().join("\n");
// Erstellt die Logik für den Soft-Delete
let delete_logic = format!(
let soft_delete_logic = format!(
r#"
-- Protokolliere den Soft-Delete
INSERT INTO crdt_log (hlc_timestamp, op_type, table_name, row_pk)
@ -117,7 +119,7 @@ impl<'a> TriggerManager<'a> {
FOR EACH ROW
BEGIN
{column_updates}
{delete_logic}
{soft_delete_logic}
END;"
)
}