[fractal/backend: 4/9] Thread local singleton for the connection
- From: Daniel Garcia Moreno <danigm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal/backend: 4/9] Thread local singleton for the connection
- Date: Wed, 30 Jan 2019 11:53:37 +0000 (UTC)
commit 379f2ffe9ec5481516283ee16e8c532a5a208f69
Author: Daniel García Moreno <danigm wadobo com>
Date: Mon Dec 24 17:05:01 2018 +0100
Thread local singleton for the connection
This allow us to implement tests and run with multiple threads without
problems because the connection will not be shared.
Cargo.lock | 28 ++++++++++++++++++++---
fractal-backend/Cargo.toml | 2 +-
fractal-backend/src/lib.rs | 50 +++++++++++++++++++++++++++++++++++++++++
fractal-backend/tests/models.rs | 17 +++++++-------
4 files changed, 84 insertions(+), 13 deletions(-)
---
diff --git a/Cargo.lock b/Cargo.lock
index 99cf195b..d9743b21 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -465,11 +465,19 @@ name = "fractal-backend"
version = "0.1.0"
dependencies = [
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+<<<<<<< HEAD
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"fractal-matrix-api 4.0.0",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rusqlite 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
+=======
+ "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fractal-matrix-api 4.0.0",
+ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rusqlite 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
+>>>>>>> Thread local singleton for the connection
]
[[package]]
@@ -1158,7 +1166,7 @@ dependencies = [
[[package]]
name = "libsqlite3-sys"
-version = "0.10.0"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2020,13 +2028,17 @@ dependencies = [
[[package]]
name = "rusqlite"
-version = "0.15.0"
+version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "libsqlite3-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libsqlite3-sys 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+<<<<<<< HEAD
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+=======
+ "time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
+>>>>>>> Thread local singleton for the connection
]
[[package]]
@@ -2767,9 +2779,14 @@ dependencies = [
"checksum libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)" =
"48450664a984b25d5b479554c29cc04e3150c97aa4c01da5604a2d4ed9151476"
"checksum libdbus-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" =
"18cb88963258d00f4962205dbb5933d82780d9962c8c8a064b651d2ad7189210"
"checksum libflate 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" =
"bff3ac7d6f23730d3b533c35ed75eef638167634476a499feef16c428d74b57b"
+<<<<<<< HEAD
"checksum libhandy 0.1.0 (git+https://gitlab.gnome.org/jsparber/libhandy-rs)" = "<none>"
"checksum libhandy-sys 0.1.0 (git+https://gitlab.gnome.org/jsparber/libhandy-rs)" = "<none>"
"checksum libsqlite3-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" =
"742b695cbfb89e549dca6960a55e6802f67d352e33e97859ee46dee835211b0f"
+=======
+"checksum libhandy 0.2.0 (git+https://gitlab.gnome.org/jsparber/libhandy-rs)" = "<none>"
+"checksum libsqlite3-sys 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" =
"6864266fa0d613f5382997f6152280edeccfd46173285459b627d6319526f5c9"
+>>>>>>> Thread local singleton for the connection
"checksum linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" =
"7860ec297f7008ff7a1e3382d7f7e1dcd69efc94751a2284bafc3d013c2aa939"
"checksum linkify 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" =
"9ce9439c6f4a1092dc1861272bef01034891da39f13aa1cdcf40ca3e4081de5f"
"checksum lmdb 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" =
"5b0908efb5d6496aa977d96f91413da2635a902e5e31dbef0bfb88986c248539"
@@ -2860,8 +2877,13 @@ dependencies = [
"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" =
"7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
"checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" =
"4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" =
"3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
+<<<<<<< HEAD
"checksum reqwest 0.9.8 (registry+https://github.com/rust-lang/crates.io-index)" =
"0e60f169af3915c294818d55dde549f00d2966cef36d6c5e7255d75df3f2b16f"
"checksum rusqlite 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" =
"39bae767eb27866f5c0be918635ae54af705bc09db11be2c43a3c6b361cf3462"
+=======
+"checksum reqwest 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" =
"ab52e462d1e15891441aeefadff68bdea005174328ce3da0a314f2ad313ec837"
+"checksum rusqlite 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" =
"6381ddfe91dbb659b4b132168da15985bc84162378cf4fcdc4eb99c857d063e2"
+>>>>>>> Thread local singleton for the connection
"checksum rust-crypto 0.2.36
(git+https://github.com/awmath/rust-crypto?rev=394c247254dbe2ac5d44483232cf335d10cf0260)" = "<none>"
"checksum rust-gmp 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" =
"4cd7d57377b309a73f69e164109203aa9ab3fee6ea68ac5fb76e2edb50662e9b"
"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" =
"adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
diff --git a/fractal-backend/Cargo.toml b/fractal-backend/Cargo.toml
index 9f5e8bc0..33236bee 100644
--- a/fractal-backend/Cargo.toml
+++ b/fractal-backend/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
authors = ["Daniel García Moreno <danigm wadobo com>"]
[dependencies]
-rusqlite = "0.15.0"
+rusqlite = "0.16.0"
failure = "0.1.3"
lazy_static = "1.2.0"
serde_json = "1.0.33"
diff --git a/fractal-backend/src/lib.rs b/fractal-backend/src/lib.rs
index 41673c8e..097b76ea 100644
--- a/fractal-backend/src/lib.rs
+++ b/fractal-backend/src/lib.rs
@@ -1,3 +1,16 @@
+//! This crate defines a singleton for the database connection, the use of
+//! `init` or `init_local` will initialize the database and that will be used by
+//! all models queries to database
+//!
+//! If you want to use the connection as a process singleton, shared by all
+//! threads, use the `init` function. In other case use the `init_local` that
+//! provides a thread local singleton so each thread should call to `init_local`
+//! and will have an unique database connection.
+//!
+//! Don't merge the `init` and the `init_local` function calls in the same
+//! program. In any case, the local will take preference, so if you merge those
+//! two, the local will be used if it's initialized.
+
extern crate chrono;
extern crate failure;
extern crate fractal_matrix_api as api;
@@ -9,6 +22,7 @@ extern crate lazy_static;
pub mod model;
+use std::cell::RefCell;
use std::sync::Arc;
use std::sync::Mutex;
@@ -16,16 +30,36 @@ use failure::err_msg;
use failure::Error;
use rusqlite::Connection;
+// Thread local singleton
+thread_local! {
+ static CONN_LOCAL: RefCell<Option<Connection>> = RefCell::new(None);
+}
+
// CONN is a singleton
lazy_static! {
static ref CONN: Arc<Mutex<Option<Connection>>> = Arc::new(Mutex::new(None));
}
+/// Function to run a query to the database with a connection
+///
+/// This function receives a closure that will receive a ref to the connection.
+/// The `def` value is the return value used when there's no connection or
+/// the connection is not created
pub fn conn<T, F>(f: F, def: T) -> T
where
T: Sized,
F: Fn(&Connection) -> T + Sized,
{
+ // first we try with the thread local
+ if let Some(output) = CONN_LOCAL.with(|c| match *c.borrow() {
+ Some(ref c) => Some(f(c)),
+ None => None,
+ }) {
+ return output;
+ }
+
+ // If the thread local is none or doesn't exists we check the global
+ // singleton
if let Ok(guard) = CONN.lock() {
return match guard.as_ref() {
Some(c) => f(c),
@@ -36,6 +70,10 @@ where
def
}
+/// Initialized the connection database as a singleton, shared by all threads
+/// and used in the `conn` function. The `path` should be a correct string for a
+/// sqlite database:
+/// https://sqlite.org/c3ref/open.html#urifilenamesinsqlite3open
pub fn init(path: &str) -> Result<(), Error> {
if let Ok(mut guard) = CONN.lock() {
let conn = Connection::open(path).map_err(|e| err_msg(e.to_string()))?;
@@ -44,3 +82,15 @@ pub fn init(path: &str) -> Result<(), Error> {
Ok(())
}
+
+/// Initialized the connection database as a local thread variable, and used in
+/// the `conn` function. The `path` should be a correct string for a sqlite
+/// database:
+/// https://sqlite.org/c3ref/open.html#urifilenamesinsqlite3open
+pub fn init_local(path: &str) -> Result<(), Error> {
+ CONN_LOCAL.with(|c| -> Result<(), Error> {
+ let conn: Connection = Connection::open(path).map_err(|e| err_msg(e.to_string()))?;
+ *c.borrow_mut() = Some(conn);
+ Ok(())
+ })
+}
diff --git a/fractal-backend/tests/models.rs b/fractal-backend/tests/models.rs
index 462eb2a3..faf8c5b4 100644
--- a/fractal-backend/tests/models.rs
+++ b/fractal-backend/tests/models.rs
@@ -1,19 +1,18 @@
extern crate fractal_backend;
-use fractal_backend::init;
+use fractal_backend::init_local as init;
use fractal_backend::model::Message;
use fractal_backend::model::Model;
use fractal_backend::model::Room;
-use std::fs::remove_file;
#[test]
fn room_model() {
- let _ = remove_file("/tmp/db.sqlite3");
- let _ = init("/tmp/db.sqlite3").unwrap();
+ let _ = init("").unwrap();
- let mut r = Room::new("ROOM ID".to_string(), Some("ROOM NAME".to_string()));
let created = Room::create_table();
assert!(created.is_ok());
+
+ let mut r = Room::new("ROOM ID".to_string(), Some("ROOM NAME".to_string()));
let stored = r.store();
assert!(stored.is_ok());
@@ -41,13 +40,13 @@ fn room_model() {
#[test]
fn message_model() {
- let _ = remove_file("/tmp/db.sqlite3");
- let _ = init("/tmp/db.sqlite3").unwrap();
+ let _ = init("").unwrap();
- let mut msg = Message::default();
- msg.id = Some("MSGID".to_string());
let created = Message::create_table();
assert!(created.is_ok());
+
+ let mut msg = Message::default();
+ msg.id = Some("MSGID".to_string());
let stored = msg.store();
assert!(stored.is_ok());
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]