diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 03c038bb..953b9195 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -123,7 +123,7 @@ jobs: - uses: actions/checkout@v3 with: submodules: true - - run: rustup update && rustup toolchain install nightly && rustup default 1.67.0 + - run: rustup update && rustup toolchain install nightly && rustup default 1.70.0 - uses: Swatinem/rust-cache@v2 - run: rm Cargo.lock && cargo +nightly update -Z direct-minimal-versions - run: cargo test @@ -253,7 +253,7 @@ jobs: - uses: actions/checkout@v3 with: submodules: true - - run: rustup update && rustup toolchain install nightly && rustup default 1.67.0 + - run: rustup update && rustup toolchain install nightly && rustup default 1.70.0 - uses: Swatinem/rust-cache@v2 - uses: actions/setup-python@v4 with: diff --git a/Cargo.lock b/Cargo.lock index 93c81493..8fea3245 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -960,7 +960,6 @@ dependencies = [ "hex", "js-sys", "json-event-parser", - "lazy_static", "libc", "md-5", "oxhttp", @@ -1017,7 +1016,6 @@ dependencies = [ "anyhow", "clap", "criterion", - "lazy_static", "oxigraph", "oxttl", "rio_api", diff --git a/Cargo.toml b/Cargo.toml index 0d6bc83e..8264afa9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ authors = ["Tpt "] license = "MIT OR Apache-2.0" homepage = "https://oxigraph.org/" edition = "2021" -rust-version = "1.67" +rust-version = "1.70" [profile.release] lto = true diff --git a/cli/Cargo.toml b/cli/Cargo.toml index ef9f42de..05c7df74 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -24,7 +24,7 @@ rocksdb-pkg-config = ["oxigraph/rocksdb-pkg-config"] [dependencies] anyhow = "1.0.72" oxhttp = { version = "0.1.7", features = ["rayon"] } -clap = { version = ">=4.0, <5.0", features = ["derive"] } +clap = { version = "4.0", features = ["derive"] } oxigraph = { version = "0.4.0-alpha.1-dev", path = "../lib", features = ["http_client"] } rand = "0.8" url = "2.4" diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 900b0b92..de97438f 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -9,7 +9,6 @@ cargo-fuzz = true [dependencies] anyhow = "1.0.72" -lazy_static = "1.4" libfuzzer-sys = "0.4" oxrdf = { path = "../lib/oxrdf", features = ["rdf-star"] } oxttl = { path = "../lib/oxttl", features = ["rdf-star"] } diff --git a/fuzz/fuzz_targets/sparql_eval.rs b/fuzz/fuzz_targets/sparql_eval.rs index 5b52f4bd..24c8a176 100644 --- a/fuzz/fuzz_targets/sparql_eval.rs +++ b/fuzz/fuzz_targets/sparql_eval.rs @@ -1,27 +1,26 @@ #![no_main] -use lazy_static::lazy_static; use libfuzzer_sys::fuzz_target; use oxigraph::io::RdfFormat; use oxigraph::sparql::{Query, QueryOptions, QueryResults, QuerySolutionIter}; use oxigraph::store::Store; +use std::sync::OnceLock; -lazy_static! { - static ref STORE: Store = { +fuzz_target!(|data: sparql_smith::Query| { + static STORE: OnceLock = OnceLock::new(); + let store = STORE.get_or_init(|| { let store = Store::new().unwrap(); store .load_dataset(sparql_smith::DATA_TRIG.as_bytes(), RdfFormat::TriG, None) .unwrap(); store - }; -} + }); -fuzz_target!(|data: sparql_smith::Query| { let query_str = data.to_string(); if let Ok(query) = Query::parse(&query_str, None) { let options = QueryOptions::default(); - let with_opt = STORE.query_opt(query.clone(), options.clone()).unwrap(); - let without_opt = STORE + let with_opt = store.query_opt(query.clone(), options.clone()).unwrap(); + let without_opt = store .query_opt(query, options.without_optimizations()) .unwrap(); match (with_opt, without_opt) { diff --git a/lib/Cargo.toml b/lib/Cargo.toml index f05e8a56..e4b4b92a 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -26,7 +26,6 @@ rocksdb_debug = [] digest = "0.10" hex = "0.4" json-event-parser = "0.1" -lazy_static = "1.4" md-5 = "0.10" oxilangtag = "0.1" oxiri = "0.2" diff --git a/lib/oxsdatatypes/src/double.rs b/lib/oxsdatatypes/src/double.rs index 6e3f890e..bc040738 100644 --- a/lib/oxsdatatypes/src/double.rs +++ b/lib/oxsdatatypes/src/double.rs @@ -173,7 +173,7 @@ impl From for Double { impl From for Double { #[inline] fn from(value: Boolean) -> Self { - if bool::from(value) { 1. } else { 0. }.into() + f64::from(bool::from(value)).into() } } diff --git a/lib/oxsdatatypes/src/float.rs b/lib/oxsdatatypes/src/float.rs index ce88c0e4..996a6401 100644 --- a/lib/oxsdatatypes/src/float.rs +++ b/lib/oxsdatatypes/src/float.rs @@ -153,7 +153,7 @@ impl From for Float { impl From for Float { #[inline] fn from(value: Boolean) -> Self { - if bool::from(value) { 1. } else { 0. }.into() + f32::from(bool::from(value)).into() } } diff --git a/lib/src/storage/backend/rocksdb.rs b/lib/src/storage/backend/rocksdb.rs index 4360e3e6..6d065059 100644 --- a/lib/src/storage/backend/rocksdb.rs +++ b/lib/src/storage/backend/rocksdb.rs @@ -9,7 +9,6 @@ )] use crate::storage::error::{CorruptionError, StorageError}; -use lazy_static::lazy_static; use libc::{self, c_void, free}; use oxrocksdb_sys::*; use rand::random; @@ -26,7 +25,7 @@ use std::marker::PhantomData; use std::ops::Deref; use std::path::{Path, PathBuf}; use std::rc::{Rc, Weak}; -use std::sync::Arc; +use std::sync::{Arc, OnceLock}; use std::thread::{available_parallelism, yield_now}; use std::{ptr, slice}; @@ -57,23 +56,6 @@ macro_rules! ffi_result_impl { }} } -lazy_static! { - static ref ROCKSDB_ENV: UnsafeEnv = { - unsafe { - let env = rocksdb_create_default_env(); - assert!(!env.is_null(), "rocksdb_create_default_env returned null"); - UnsafeEnv(env) - } - }; - static ref ROCKSDB_MEM_ENV: UnsafeEnv = { - unsafe { - let env = rocksdb_create_mem_env(); - assert!(!env.is_null(), "rocksdb_create_mem_env returned null"); - UnsafeEnv(env) - } - }; -} - pub struct ColumnFamilyDefinition { pub name: &'static str, pub use_iter: bool, @@ -472,6 +454,9 @@ impl Db { limit_max_open_files: bool, in_memory: bool, ) -> Result<*mut rocksdb_options_t, StorageError> { + static ROCKSDB_ENV: OnceLock = OnceLock::new(); + static ROCKSDB_MEM_ENV: OnceLock = OnceLock::new(); + unsafe { let options = rocksdb_options_create(); assert!(!options.is_null(), "rocksdb_options_create returned null"); @@ -508,10 +493,19 @@ impl Db { rocksdb_options_set_env( options, if in_memory { - ROCKSDB_MEM_ENV.0 + ROCKSDB_MEM_ENV.get_or_init(|| { + let env = rocksdb_create_mem_env(); + assert!(!env.is_null(), "rocksdb_create_mem_env returned null"); + UnsafeEnv(env) + }) } else { - ROCKSDB_ENV.0 - }, + ROCKSDB_ENV.get_or_init(|| { + let env = rocksdb_create_default_env(); + assert!(!env.is_null(), "rocksdb_create_default_env returned null"); + UnsafeEnv(env) + }) + } + .0, ); Ok(options) } @@ -1400,7 +1394,8 @@ impl From for StorageError { struct UnsafeEnv(*mut rocksdb_env_t); -// Hack for lazy_static. OK because only written in lazy static and used in a thread-safe way by RocksDB +// Hack for OnceCell. OK because only written in OnceCell and used in a thread-safe way by RocksDB +unsafe impl Send for UnsafeEnv {} unsafe impl Sync for UnsafeEnv {} fn path_to_cstring(path: &Path) -> Result { diff --git a/python/src/io.rs b/python/src/io.rs index be494e22..e8da9a8c 100644 --- a/python/src/io.rs +++ b/python/src/io.rs @@ -14,6 +14,7 @@ use std::ffi::OsStr; use std::fs::File; use std::io::{self, BufWriter, Cursor, Read, Write}; use std::path::{Path, PathBuf}; +use std::sync::OnceLock; /// Parses RDF graph and dataset serialization formats. /// @@ -400,7 +401,7 @@ pub fn map_parse_error(error: ParseError, file_path: Option) -> PyErr { match error { ParseError::Syntax(error) => { // Python 3.9 does not support end line and end column - if python_version() >= (3, 10) { + if python_version() >= (3, 10, 0) { let params = if let Some(location) = error.location() { ( file_path, @@ -457,9 +458,12 @@ pub fn allow_threads_unsafe(_py: Python<'_>, f: impl FnOnce() -> T) -> T { f() } -fn python_version() -> (u8, u8) { - Python::with_gil(|py| { - let v = py.version_info(); - (v.major, v.minor) +fn python_version() -> (u8, u8, u8) { + static VERSION: OnceLock<(u8, u8, u8)> = OnceLock::new(); + *VERSION.get_or_init(|| { + Python::with_gil(|py| { + let v = py.version_info(); + (v.major, v.minor, v.patch) + }) }) } diff --git a/testsuite/Cargo.toml b/testsuite/Cargo.toml index 47c3ce2e..59b751c2 100644 --- a/testsuite/Cargo.toml +++ b/testsuite/Cargo.toml @@ -12,8 +12,7 @@ publish = false [dependencies] anyhow = "1.0.72" -clap = { version = ">=4.0, <5.0", features = ["derive"] } -lazy_static = "1.4" +clap = { version = "4.0", features = ["derive"] } oxigraph = { path = "../lib" } oxttl = { path= "../lib/oxttl" } sparopt = { path = "../lib/sparopt" } diff --git a/testsuite/src/sparql_evaluator.rs b/testsuite/src/sparql_evaluator.rs index d5b4d265..67081be6 100644 --- a/testsuite/src/sparql_evaluator.rs +++ b/testsuite/src/sparql_evaluator.rs @@ -4,7 +4,6 @@ use crate::manifest::*; use crate::report::{dataset_diff, format_diff}; use crate::vocab::*; use anyhow::{anyhow, bail, ensure, Error, Result}; -use lazy_static::lazy_static; use oxigraph::model::vocab::*; use oxigraph::model::*; use oxigraph::sparql::results::QueryResultsFormat; @@ -16,7 +15,7 @@ use std::fmt::Write; use std::io::{self, BufReader, Cursor}; use std::ops::Deref; use std::str::FromStr; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, OnceLock}; pub fn register_sparql_tests(evaluator: &mut TestEvaluator) { evaluator.register( @@ -740,13 +739,11 @@ fn evaluate_query_optimization_test(test: &Test) -> Result<()> { Ok(()) } -lazy_static! { - // Pool of stores to avoid allocating/deallocating them a lot - static ref STORE_POOL: Mutex> = Mutex::new(Vec::new()); -} +// Pool of stores to avoid allocating/deallocating them a lot +static STORE_POOL: OnceLock>> = OnceLock::new(); fn get_store() -> Result { - let store = if let Some(store) = STORE_POOL.lock().unwrap().pop() { + let store = if let Some(store) = STORE_POOL.get_or_init(Mutex::default).lock().unwrap().pop() { store } else { Store::new()? @@ -761,7 +758,11 @@ struct StoreRef { impl Drop for StoreRef { fn drop(&mut self) { if self.store.clear().is_ok() { - STORE_POOL.lock().unwrap().push(self.store.clone()) + STORE_POOL + .get_or_init(Mutex::default) + .lock() + .unwrap() + .push(self.store.clone()) } } }