Merge pull request #207 from ikatson/fix-persistence-bugs

Fix persistence bugs
This commit is contained in:
Igor Katson 2024-08-23 18:58:45 +01:00 committed by GitHub
commit e8bd7ca7e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 13 additions and 5 deletions

View file

@ -1152,6 +1152,7 @@ impl Session {
)); ));
let handle = Arc::new(ManagedTorrent { let handle = Arc::new(ManagedTorrent {
locked: RwLock::new(ManagedTorrentLocked { locked: RwLock::new(ManagedTorrentLocked {
paused: opts.paused,
state: ManagedTorrentState::Initializing(initializing), state: ManagedTorrentState::Initializing(initializing),
only_files, only_files,
}), }),
@ -1327,6 +1328,7 @@ impl Session {
} }
pub async fn pause(&self, handle: &ManagedTorrentHandle) -> anyhow::Result<()> { pub async fn pause(&self, handle: &ManagedTorrentHandle) -> anyhow::Result<()> {
handle.locked.write().paused = true;
handle.pause()?; handle.pause()?;
self.try_update_persistence_metadata(handle).await; self.try_update_persistence_metadata(handle).await;
Ok(()) Ok(())

View file

@ -8,7 +8,6 @@ use crate::{
storage::filesystem::FilesystemStorageFactory, storage::filesystem::FilesystemStorageFactory,
torrent_state::ManagedTorrentHandle, torrent_state::ManagedTorrentHandle,
type_aliases::BF, type_aliases::BF,
ManagedTorrentState,
}; };
use anyhow::{bail, Context}; use anyhow::{bail, Context};
use async_trait::async_trait; use async_trait::async_trait;
@ -86,6 +85,8 @@ impl JsonSessionPersistenceStore {
} }
async fn flush(&self) -> anyhow::Result<()> { async fn flush(&self) -> anyhow::Result<()> {
// we don't need the write lock technically, but we need to stop concurrent modifications
let db_content = self.db_content.write().await;
let tmp_filename = format!("{}.tmp", self.db_filename.to_str().unwrap()); let tmp_filename = format!("{}.tmp", self.db_filename.to_str().unwrap());
let mut tmp = tokio::fs::OpenOptions::new() let mut tmp = tokio::fs::OpenOptions::new()
.create(true) .create(true)
@ -97,8 +98,7 @@ impl JsonSessionPersistenceStore {
trace!(?tmp_filename, "opened temp file"); trace!(?tmp_filename, "opened temp file");
let mut buf = Vec::new(); let mut buf = Vec::new();
serde_json::to_writer(&mut buf, &*self.db_content.read().await) serde_json::to_writer(&mut buf, &*db_content).context("error serializing")?;
.context("error serializing")?;
trace!(?tmp_filename, "serialized DB as JSON"); trace!(?tmp_filename, "serialized DB as JSON");
tmp.write_all(&buf) tmp.write_all(&buf)
@ -146,7 +146,7 @@ impl JsonSessionPersistenceStore {
// we don't serialize this here, but to a file instead. // we don't serialize this here, but to a file instead.
torrent_bytes: Default::default(), torrent_bytes: Default::default(),
only_files: torrent.only_files().clone(), only_files: torrent.only_files().clone(),
is_paused: torrent.with_state(|s| matches!(s, ManagedTorrentState::Paused(_))), is_paused: torrent.is_paused(),
output_folder: torrent.shared().options.output_folder.clone(), output_folder: torrent.shared().options.output_folder.clone(),
}; };

View file

@ -85,6 +85,11 @@ impl ManagedTorrentState {
} }
pub(crate) struct ManagedTorrentLocked { pub(crate) struct ManagedTorrentLocked {
// The torrent might not be in "paused" state technically,
// but the intention might be for it to stay paused.
//
// This should change only on "unpause".
pub(crate) paused: bool,
pub(crate) state: ManagedTorrentState, pub(crate) state: ManagedTorrentState,
pub(crate) only_files: Option<Vec<usize>>, pub(crate) only_files: Option<Vec<usize>>,
} }
@ -218,6 +223,7 @@ impl ManagedTorrent {
.upgrade() .upgrade()
.context("session is dead, cannot start torrent")?; .context("session is dead, cannot start torrent")?;
let mut g = self.locked.write(); let mut g = self.locked.write();
g.paused = start_paused;
let cancellation_token = session.cancellation_token().child_token(); let cancellation_token = session.cancellation_token().child_token();
let spawn_fatal_errors_receiver = let spawn_fatal_errors_receiver =
@ -380,7 +386,7 @@ impl ManagedTorrent {
} }
pub fn is_paused(&self) -> bool { pub fn is_paused(&self) -> bool {
self.with_state(|s| matches!(s, ManagedTorrentState::Paused(..))) self.locked.read().paused
} }
/// Pause the torrent if it's live. /// Pause the torrent if it's live.