@@ -3,7 +3,7 @@ use super::datastore::locking_tx_datastore::datastore::{report_tx_metricses, TxM
33use super :: datastore:: locking_tx_datastore:: state_view:: {
44 IterByColEqMutTx , IterByColRangeMutTx , IterMutTx , IterTx , StateView ,
55} ;
6- use super :: datastore:: system_tables:: ST_MODULE_ID ;
6+ use super :: datastore:: system_tables:: { StFields , StVarFields , StVarName , StVarRow , ST_MODULE_ID , ST_VAR_ID } ;
77use super :: datastore:: traits:: {
88 InsertFlags , IsolationLevel , Metadata , MutTx as _, MutTxDatastore , Program , RowTypeForTable , Tx as _, TxDatastore ,
99 UpdateFlags ,
@@ -31,10 +31,12 @@ use spacetimedb_commitlog as commitlog;
3131use spacetimedb_durability:: { self as durability, TxOffset } ;
3232use spacetimedb_lib:: db:: auth:: StAccess ;
3333use spacetimedb_lib:: db:: raw_def:: v9:: { btree, RawModuleDefV9Builder , RawSql } ;
34+ use spacetimedb_lib:: st_var:: StVarValue ;
3435use spacetimedb_lib:: ConnectionId ;
3536use spacetimedb_lib:: Identity ;
3637use spacetimedb_paths:: server:: { CommitLogDir , ReplicaDir , SnapshotsPath } ;
3738use spacetimedb_primitives:: * ;
39+ use spacetimedb_sats:: algebraic_type:: fmt:: fmt_algebraic_type;
3840use spacetimedb_sats:: { AlgebraicType , AlgebraicValue , ProductType , ProductValue } ;
3941use spacetimedb_schema:: def:: { ModuleDef , TableDef } ;
4042use spacetimedb_schema:: schema:: { IndexSchema , RowLevelSecuritySchema , Schema , SequenceSchema , TableSchema } ;
@@ -43,6 +45,8 @@ use spacetimedb_table::indexes::RowPointer;
4345use spacetimedb_table:: page_pool:: PagePool ;
4446use spacetimedb_table:: table:: RowRef ;
4547use spacetimedb_table:: MemoryUsage ;
48+ use spacetimedb_vm:: errors:: { ErrorType , ErrorVm } ;
49+ use spacetimedb_vm:: ops:: parse;
4650use std:: borrow:: Cow ;
4751use std:: collections:: HashSet ;
4852use std:: fmt;
@@ -1365,6 +1369,78 @@ impl RelationalDB {
13651369 pub fn report ( & self , reducer : & str , metrics : & TxMetrics , tx_data : Option < & TxData > ) {
13661370 metrics. report ( tx_data, reducer, |wl : WorkloadType | self . exec_counters_for ( wl) ) ;
13671371 }
1372+
1373+ /// Read the value of [ST_VARNAME_ROW_LIMIT] from `st_var`
1374+ pub ( crate ) fn row_limit ( & self , tx : & Tx ) -> Result < Option < u64 > , DBError > {
1375+ let data = self . read_var ( tx, StVarName :: RowLimit ) ;
1376+
1377+ if let Some ( StVarValue :: U64 ( limit) ) = data? {
1378+ return Ok ( Some ( limit) ) ;
1379+ }
1380+ Ok ( None )
1381+ }
1382+
1383+ /// Read the value of [ST_VARNAME_SLOW_QRY] from `st_var`
1384+ pub ( crate ) fn query_limit ( & self , tx : & Tx ) -> Result < Option < u64 > , DBError > {
1385+ if let Some ( StVarValue :: U64 ( ms) ) = self . read_var ( tx, StVarName :: SlowQryThreshold ) ? {
1386+ return Ok ( Some ( ms) ) ;
1387+ }
1388+ Ok ( None )
1389+ }
1390+
1391+ /// Read the value of [ST_VARNAME_SLOW_SUB] from `st_var`
1392+ #[ allow( dead_code) ]
1393+ pub ( crate ) fn sub_limit ( & self , tx : & Tx ) -> Result < Option < u64 > , DBError > {
1394+ if let Some ( StVarValue :: U64 ( ms) ) = self . read_var ( tx, StVarName :: SlowSubThreshold ) ? {
1395+ return Ok ( Some ( ms) ) ;
1396+ }
1397+ Ok ( None )
1398+ }
1399+
1400+ /// Read the value of [ST_VARNAME_SLOW_INC] from `st_var`
1401+ #[ allow( dead_code) ]
1402+ pub ( crate ) fn incr_limit ( & self , tx : & Tx ) -> Result < Option < u64 > , DBError > {
1403+ if let Some ( StVarValue :: U64 ( ms) ) = self . read_var ( tx, StVarName :: SlowIncThreshold ) ? {
1404+ return Ok ( Some ( ms) ) ;
1405+ }
1406+ Ok ( None )
1407+ }
1408+
1409+ /// Read the value of a system variable from `st_var`
1410+ pub ( crate ) fn read_var ( & self , tx : & Tx , name : StVarName ) -> Result < Option < StVarValue > , DBError > {
1411+ if let Some ( row_ref) = self
1412+ . iter_by_col_eq ( tx, ST_VAR_ID , StVarFields :: Name . col_id ( ) , & name. into ( ) ) ?
1413+ . next ( )
1414+ {
1415+ return Ok ( Some ( StVarRow :: try_from ( row_ref) ?. value ) ) ;
1416+ }
1417+ Ok ( None )
1418+ }
1419+
1420+ /// Update the value of a system variable in `st_var`
1421+ pub ( crate ) fn write_var ( & self , tx : & mut MutTx , name : StVarName , literal : & str ) -> Result < ( ) , DBError > {
1422+ let value = Self :: parse_var ( name, literal) ?;
1423+ if let Some ( row_ref) = self
1424+ . iter_by_col_eq_mut ( tx, ST_VAR_ID , StVarFields :: Name . col_id ( ) , & name. into ( ) ) ?
1425+ . next ( )
1426+ {
1427+ self . delete ( tx, ST_VAR_ID , [ row_ref. pointer ( ) ] ) ;
1428+ }
1429+ tx. insert_via_serialize_bsatn ( ST_VAR_ID , & StVarRow { name, value } ) ?;
1430+ Ok ( ( ) )
1431+ }
1432+
1433+ /// Parse the literal representation of a system variable
1434+ fn parse_var ( name : StVarName , literal : & str ) -> Result < StVarValue , DBError > {
1435+ StVarValue :: try_from_primitive ( parse:: parse ( literal, & name. type_of ( ) ) ?) . map_err ( |v| {
1436+ ErrorVm :: Type ( ErrorType :: Parse {
1437+ value : literal. to_string ( ) ,
1438+ ty : fmt_algebraic_type ( & name. type_of ( ) ) . to_string ( ) ,
1439+ err : format ! ( "error parsing value: {:?}" , v) ,
1440+ } )
1441+ . into ( )
1442+ } )
1443+ }
13681444}
13691445
13701446#[ allow( unused) ]
@@ -1925,7 +2001,9 @@ mod tests {
19252001 system_tables, StConstraintRow , StIndexRow , StSequenceRow , StTableRow , ST_CONSTRAINT_ID , ST_INDEX_ID ,
19262002 ST_SEQUENCE_ID , ST_TABLE_ID ,
19272003 } ;
1928- use crate :: db:: relational_db:: tests_utils:: { begin_tx, insert, make_snapshot, TestDB } ;
2004+ use crate :: db:: relational_db:: tests_utils:: {
2005+ begin_tx, insert, make_snapshot, with_auto_commit, with_read_only, TestDB ,
2006+ } ;
19292007 use crate :: error:: IndexError ;
19302008 use crate :: execution_context:: ReducerContext ;
19312009 use anyhow:: bail;
@@ -2009,6 +2087,18 @@ mod tests {
20092087 Ok ( ( ) )
20102088 }
20112089
2090+ #[ test]
2091+ fn test_system_variables ( ) {
2092+ let db = TestDB :: durable ( ) . expect ( "failed to create db" ) ;
2093+ let _ = with_auto_commit ( & db, |tx| db. write_var ( tx, StVarName :: RowLimit , "5" ) ) ;
2094+ assert_eq ! (
2095+ 5 ,
2096+ with_read_only( & db, |tx| db. row_limit( tx) )
2097+ . expect( "failed to read from st_var" )
2098+ . expect( "row_limit does not exist" )
2099+ ) ;
2100+ }
2101+
20122102 #[ test]
20132103 fn test_open_twice ( ) -> ResultTest < ( ) > {
20142104 let stdb = TestDB :: durable ( ) ?;
0 commit comments