use lightning::util::logger::Logger;
use lightning::util::ser::Writeable;
use std::fs;
+use std::collections::HashMap;
use std::io::{Error, Write};
use std::path::PathBuf;
-use std::sync::Arc;
+use std::sync::{Arc, RwLock, Mutex};
#[cfg(test)]
use {
lightning::util::ser::ReadableArgs,
bitcoin::{BlockHash, Txid},
bitcoin::hashes::hex::FromHex,
- std::collections::HashMap,
std::io::Cursor
};
/// FilesystemPersister.
pub struct FilesystemPersister {
path_to_channel_data: String,
+ monitor_logs: RwLock<HashMap<String, Mutex<fs::File>>>, // This locking structure is insane
}
impl<Signer: Sign> DiskWriteable for ChannelMonitor<Signer> {
pub fn new(path_to_channel_data: String) -> Self {
return Self {
path_to_channel_data,
+ monitor_logs: RwLock::new(HashMap::new()),
}
}
}
fn update_persisted_channel(&self, funding_txo: OutPoint, update: &ChannelMonitorUpdate, _monitor: &ChannelMonitor<ChannelSigner>) -> Result<(), ChannelMonitorUpdateErr> {
- let filename = format!("{}_{}_{}", funding_txo.txid.to_hex(), funding_txo.index, update.update_id);
- util::write_to_new_file(self.path_to_monitor_data(), &filename, update)
- .map_err(|_| ChannelMonitorUpdateErr::PermanentFailure)
+ let filename = format!("{}_{}.log", funding_txo.txid.to_hex(), funding_txo.index);
+ {
+ let logs = self.monitor_logs.read().unwrap();
+ match logs.get(&filename) {
+ Some(file) => {
+ return util::write_to_open_file(&mut *file.lock().unwrap(), update).map_err(|_| ChannelMonitorUpdateErr::PermanentFailure);
+ },
+ None => {},
+ }
+ }
+ let mut logs = self.monitor_logs.write().unwrap();
+ let mut f = util::open_file(self.path_to_monitor_data(), &filename).map_err(|_| ChannelMonitorUpdateErr::PermanentFailure)?;
+ util::write_to_open_file(&mut f, update).map_err(|_| ChannelMonitorUpdateErr::PermanentFailure)?;
+ assert!(logs.insert(filename, Mutex::new(f)).is_none(), "We cannot have parallel calls to update a single monitor");
+ Ok(())
}
}
path.as_ref().encode_wide().chain(Some(0)).collect()
}
-pub(crate) fn write_to_new_file<D: DiskWriteable>(path: PathBuf, filename: &str, data: &D) -> std::io::Result<()> {
- let filename_with_path = get_full_filepath(path.clone(), &filename);
- fs::create_dir_all(path)?;
-
+pub(crate) fn write_to_open_file<D: DiskWriteable>(f: &mut fs::File, data: &D) -> std::io::Result<()> {
// Note that going by rust-lang/rust@d602a6b, on MacOS it is only safe to use
// rust stdlib 1.36 or higher.
- let mut f = fs::File::create(filename_with_path)?;
- data.write_to_file(&mut f)?;
+ data.write_to_file(f)?;
f.sync_all()?;
Ok(())
}
+pub(crate) fn open_file(path: PathBuf, filename: &str) -> std::io::Result<fs::File> {
+ let filename_with_path = get_full_filepath(path.clone(), &filename);
+ fs::create_dir_all(path)?; //XXX
+
+ fs::File::create(filename_with_path)
+}
+
+pub(crate) fn write_to_new_file<D: DiskWriteable>(path: PathBuf, filename: &str, data: &D) -> std::io::Result<()> {
+ let mut f = open_file(path, filename)?;
+ write_to_open_file(&mut f, data)
+}
+
#[allow(bare_trait_objects)]
pub(crate) fn write_to_file<D: DiskWriteable>(path: PathBuf, filename: String, data: &D) -> std::io::Result<()> {