Skip to content

Commit

Permalink
use fs2 advisory file lock on startup (#2600)
Browse files Browse the repository at this point in the history
  • Loading branch information
antiochp authored Feb 19, 2019
1 parent 5dc01b3 commit 48b7421
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 1 deletion.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions servers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ edition = "2018"

[dependencies]
hyper = "0.12"
fs2 = "0.4"
futures = "0.1"
http = "0.1"
hyper-staticfile = "0.3"
Expand Down
8 changes: 7 additions & 1 deletion servers/src/common/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ pub enum Error {
Pool(pool::PoolError),
/// Invalid Arguments.
ArgumentError(String),
/// Error originating from some I/O operation (likely a file on disk).
IOError(std::io::Error),
}

impl From<core::block::Error> for Error {
Expand All @@ -60,7 +62,11 @@ impl From<chain::Error> for Error {
Error::Chain(e)
}
}

impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Error {
Error::IOError(e)
}
}
impl From<p2p::Error> for Error {
fn from(e: p2p::Error) -> Error {
Error::P2P(e)
Expand Down
38 changes: 38 additions & 0 deletions servers/src/grin/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,15 @@
//! the peer-to-peer server, the blockchain and the transaction pool) and acts
//! as a facade.
use std::fs;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use std::sync::Arc;
use std::{thread, time};

use fs2::FileExt;

use crate::api;
use crate::api::TLSConfig;
use crate::chain;
Expand Down Expand Up @@ -59,6 +65,8 @@ pub struct Server {
state_info: ServerStateInfo,
/// Stop flag
pub stop_state: Arc<Mutex<StopState>>,
/// Maintain a lock_file so we do not run multiple Grin nodes from same dir.
lock_file: Arc<File>,
}

impl Server {
Expand Down Expand Up @@ -102,8 +110,36 @@ impl Server {
}
}

// Exclusive (advisory) lock_file to ensure we do not run multiple
// instance of grin server from the same dir.
// This uses fs2 and should be safe cross-platform unless somebody abuses the file itself.
fn one_grin_at_a_time(config: &ServerConfig) -> Result<Arc<File>, Error> {
let path = Path::new(&config.db_root);
fs::create_dir_all(path.clone())?;
let path = path.join("grin.lock");
let lock_file = fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&path)?;
lock_file.try_lock_exclusive().map_err(|e| {
let mut stderr = std::io::stderr();
writeln!(
&mut stderr,
"Failed to lock {:?} (grin server already running?)",
path
)
.expect("Could not write to stderr");
e
})?;
Ok(Arc::new(lock_file))
}

/// Instantiates a new server associated with the provided future reactor.
pub fn new(config: ServerConfig) -> Result<Server, Error> {
// Obtain our lock_file or fail immediately with an error.
let lock_file = Server::one_grin_at_a_time(&config)?;

// Defaults to None (optional) in config file.
// This translates to false here.
let archive_mode = match config.archive_mode {
Expand Down Expand Up @@ -264,6 +300,7 @@ impl Server {
..Default::default()
},
stop_state,
lock_file,
})
}

Expand Down Expand Up @@ -451,6 +488,7 @@ impl Server {
pub fn stop(&self) {
self.p2p.stop();
self.stop_state.lock().stop();
let _ = self.lock_file.unlock();
}

/// Pause the p2p server.
Expand Down

0 comments on commit 48b7421

Please sign in to comment.