Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chain_data/grin.lock to prevent multiple grin processes running from same dir #2600

Merged
merged 1 commit into from
Feb 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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