git.delta.rocks / jrsonnet / refs/commits / c6d77aa9f34e

difftreelog

feat remove lock

Yaroslav Bolyukin2021-07-10parent: #e6bd094.patch.diff
in: trunk
Building is locked on nix store anyway

1 file changed

modifiedsrc/db/db.rsdiffbeforeafterboth
before · src/db/db.rs
1//! Small .toml based readable data store23use anyhow::{Context, Result};4use serde::{de::DeserializeOwned, Serialize};5use std::{6	cell::Cell,7	collections::HashSet,8	io::Write,9	ops::{Deref, DerefMut},10	path::Path,11	path::PathBuf,12	sync::{Arc, Mutex},13};1415struct DbInternal {16	root: PathBuf,17	locked_paths: HashSet<PathBuf>,18	_lockfile: lockfile::Lockfile,19}2021pub trait DbData: DeserializeOwned + Serialize + Default {22	const DB_NAME: &'static str;2324	fn open(db: &Db) -> Result<DbFile<Self>> {25		db.db::<Self>()26	}27}2829#[derive(Clone)]30pub struct Db(Arc<Mutex<DbInternal>>);31impl Db {32	pub fn new(root: impl AsRef<Path>) -> Result<Self> {33		let root: &Path = root.as_ref();34		std::fs::create_dir_all(&root).context("db root")?;35		let mut lockfile = root.to_owned();36		lockfile.push(".lock");37		let lockfile = lockfile::Lockfile::create(lockfile).context("db lock")?;38		Ok(Db(Arc::new(Mutex::new(DbInternal {39			root: root.to_owned(),40			locked_paths: HashSet::new(),41			_lockfile: lockfile,42		}))))43	}4445	pub fn db<T: DbData>(&self) -> Result<DbFile<T>> {46		let name = T::DB_NAME;47		assert!(!name.contains("/") && !name.contains("\\"));48		let mut db = self.0.lock().unwrap();49		let mut data_path = db.root.clone();50		data_path.push(format!("{}.toml", name));5152		if !db.locked_paths.insert(data_path.clone()) {53			anyhow::bail!("file is already open");54		}5556		let data = if data_path.exists() {57			let raw_data = std::fs::read(&data_path).context("reading file")?;58			toml::from_slice(&raw_data).context("parsing file")?59		} else {60			T::default()61		};6263		Ok(DbFile {64			db: self.clone(),65			root: db.root.clone(),66			path: data_path,67			data,68			dirty: Cell::new(false),69		})70	}71}7273pub struct DbFile<T: DbData> {74	db: Db,75	root: PathBuf,76	path: PathBuf,77	data: T,78	dirty: Cell<bool>,79}8081impl<T: DbData> Deref for DbFile<T> {82	type Target = T;8384	fn deref(&self) -> &Self::Target {85		&self.data86	}87}8889impl<T: DbData> DerefMut for DbFile<T> {90	fn deref_mut(&mut self) -> &mut Self::Target {91		self.dirty.set(true);92		&mut self.data93	}94}9596impl<T: DbData> DbFile<T> {97	pub fn write(&self) -> Result<()> {98		if !self.dirty.get() {99			return Ok(());100		}101		let mut temp = tempfile::Builder::new()102			.prefix("~")103			.suffix(".toml")104			.tempfile_in(&self.root)?;105		let mut out = String::new();106		let mut serializer = toml::Serializer::new(&mut out);107		serializer.pretty_array(true).pretty_string(true);108		self.data.serialize(&mut serializer)?;109		temp.write_all(&out.as_bytes())?;110		temp.persist(&self.path)?;111		self.dirty.set(false);112		Ok(())113	}114}115116impl<T: DbData> Drop for DbFile<T> {117	fn drop(&mut self) {118		let mut db = self.db.0.lock().unwrap();119		self.write().unwrap();120		db.locked_paths.remove(&self.path);121	}122}
after · src/db/db.rs
1//! Small .toml based readable data store23use anyhow::{Context, Result};4use serde::{de::DeserializeOwned, Serialize};5use std::{6	cell::Cell,7	collections::HashSet,8	io::Write,9	ops::{Deref, DerefMut},10	path::Path,11	path::PathBuf,12	sync::{Arc, Mutex},13};1415struct DbInternal {16	root: PathBuf,17	locked_paths: HashSet<PathBuf>,18}1920pub trait DbData: DeserializeOwned + Serialize + Default {21	const DB_NAME: &'static str;2223	fn open(db: &Db) -> Result<DbFile<Self>> {24		db.db::<Self>()25	}26}2728#[derive(Clone)]29pub struct Db(Arc<Mutex<DbInternal>>);30impl Db {31	pub fn new(root: impl AsRef<Path>) -> Result<Self> {32		let root: &Path = root.as_ref();33		std::fs::create_dir_all(&root).context("db root")?;34		Ok(Db(Arc::new(Mutex::new(DbInternal {35			root: root.to_owned(),36			locked_paths: HashSet::new(),37		}))))38	}3940	pub fn db<T: DbData>(&self) -> Result<DbFile<T>> {41		let name = T::DB_NAME;42		assert!(!name.contains("/") && !name.contains("\\"));43		let mut db = self.0.lock().unwrap();44		let mut data_path = db.root.clone();45		data_path.push(format!("{}.toml", name));4647		if !db.locked_paths.insert(data_path.clone()) {48			anyhow::bail!("file is already open");49		}5051		let data = if data_path.exists() {52			let raw_data = std::fs::read(&data_path).context("reading file")?;53			toml::from_slice(&raw_data).context("parsing file")?54		} else {55			T::default()56		};5758		Ok(DbFile {59			db: self.clone(),60			root: db.root.clone(),61			path: data_path,62			data,63			dirty: Cell::new(false),64		})65	}66}6768pub struct DbFile<T: DbData> {69	db: Db,70	root: PathBuf,71	path: PathBuf,72	data: T,73	dirty: Cell<bool>,74}7576impl<T: DbData> Deref for DbFile<T> {77	type Target = T;7879	fn deref(&self) -> &Self::Target {80		&self.data81	}82}8384impl<T: DbData> DerefMut for DbFile<T> {85	fn deref_mut(&mut self) -> &mut Self::Target {86		self.dirty.set(true);87		&mut self.data88	}89}9091impl<T: DbData> DbFile<T> {92	pub fn write(&self) -> Result<()> {93		if !self.dirty.get() {94			return Ok(());95		}96		let mut temp = tempfile::Builder::new()97			.prefix("~")98			.suffix(".toml")99			.tempfile_in(&self.root)?;100		let mut out = String::new();101		let mut serializer = toml::Serializer::new(&mut out);102		serializer.pretty_array(true).pretty_string(true);103		self.data.serialize(&mut serializer)?;104		temp.write_all(&out.as_bytes())?;105		temp.persist(&self.path)?;106		self.dirty.set(false);107		Ok(())108	}109}110111impl<T: DbData> Drop for DbFile<T> {112	fn drop(&mut self) {113		let mut db = self.db.0.lock().unwrap();114		self.write().unwrap();115		db.locked_paths.remove(&self.path);116	}117}