Use separate thread for saving session data.

This commit is contained in:
Jari Sundell
2025-12-17 22:42:44 +01:00
committed by GitHub
parent 16ff32b88c
commit 8f644e65dd
21 changed files with 668 additions and 209 deletions
+9 -7
View File
@@ -17,6 +17,7 @@
#include "globals.h"
#include "manager.h"
#include "rpc/parse_commands.h"
#include "session/session_manager.h"
#define LT_LOG(log_fmt, ...) \
lt_log_print_subsystem(torrent::LOG_DHT_CONTROLLER, "dht_manager", log_fmt, __VA_ARGS__);
@@ -35,13 +36,13 @@ DhtManager::~DhtManager() {
void
DhtManager::load_dht_cache() {
if (m_start == dht_disable || !control->core()->download_store()->is_enabled()) {
if (m_start == dht_disable || !session_thread::manager()->is_used()) {
LT_LOG("ignoring cache file", 0);
return;
}
std::string cache_filename = control->core()->download_store()->path() + "rtorrent.dht_cache";
std::fstream cache_stream(cache_filename.c_str(), std::ios::in | std::ios::binary);
auto cache_filename = session_thread::manager()->path() + "rtorrent.dht_cache";
auto cache_stream = std::fstream(cache_filename.c_str(), std::ios::in | std::ios::binary);
torrent::Object cache = torrent::Object::create_map();
@@ -115,14 +116,15 @@ DhtManager::stop_dht() {
void
DhtManager::save_dht_cache() {
if (!control->core()->download_store()->is_enabled())
if (!session_thread::manager()->is_used())
return;
if (!torrent::runtime::network_manager()->is_dht_valid())
return;
std::string filename = control->core()->download_store()->path() + "rtorrent.dht_cache";
std::string filename_tmp = filename + ".new";
std::fstream cache_file(filename_tmp.c_str(), std::ios::out | std::ios::trunc);
auto filename = session_thread::manager()->path() + "rtorrent.dht_cache";
auto filename_tmp = filename + ".new";
auto cache_file = std::fstream(filename_tmp.c_str(), std::ios::out | std::ios::trunc);
if (!cache_file.is_open())
return;
+30 -108
View File
@@ -5,6 +5,7 @@
#include <fstream>
#include <stdio.h>
#include <fcntl.h>
#include <sstream>
#include <unistd.h>
#include <rak/error_number.h>
#include <rak/path.h>
@@ -16,104 +17,17 @@
#include <torrent/rate.h>
#include <torrent/object_stream.h>
#include "utils/directory.h"
#include "download.h"
#include "download_store.h"
#include "rpc/parse_commands.h"
#include "session/session_manager.h"
#include "utils/directory.h"
namespace core {
void
DownloadStore::enable(bool lock) {
if (is_enabled())
throw torrent::input_error("Session directory already enabled.");
if (m_path.empty())
return;
if (lock)
m_lockfile.set_path(m_path + "rtorrent.lock");
else
m_lockfile.set_path(std::string());
if (!m_lockfile.try_lock()) {
if (rak::error_number::current().is_bad_path())
throw torrent::input_error("Could not lock session directory: \"" + m_path + "\", " + rak::error_number::current().c_str());
else
throw torrent::input_error("Could not lock session directory: \"" + m_path + "\", held by \"" + m_lockfile.locked_by_as_string() + "\".");
}
}
void
DownloadStore::disable() {
if (!is_enabled())
return;
m_lockfile.unlock();
}
void
DownloadStore::set_path(const std::string& path) {
if (is_enabled())
throw torrent::input_error("Tried to change session directory while it is enabled.");
if (!path.empty() && *path.rbegin() != '/')
m_path = rak::path_expand(path + '/');
else
m_path = rak::path_expand(path);
}
bool
DownloadStore::write_bencode(const std::string& filename, const torrent::Object& obj, uint32_t skip_mask) {
int fd;
torrent::Object tmp;
std::fstream output(filename.c_str(), std::ios::out | std::ios::trunc);
if (!output.is_open())
goto download_store_save_error;
torrent::object_write_bencode(&output, &obj, skip_mask);
if (!output.good())
goto download_store_save_error;
output.close();
// Test the new file, to ensure it is a valid bencode string.
output.open(filename.c_str(), std::ios::in);
output >> tmp;
if (!output.good())
goto download_store_save_error;
output.close();
// Ensure that the new file is actually written to the disk
fd = ::open(filename.c_str(), O_WRONLY);
if (fd < 0)
goto download_store_save_error;
if (rpc::call_command_value("system.files.session.fdatasync")) {
#ifdef __APPLE__
fsync(fd);
#else
fdatasync(fd);
#endif
}
::close(fd);
return true;
download_store_save_error:
output.close();
return false;
}
bool
DownloadStore::save(Download* d, int flags) {
if (!is_enabled())
if (!session_thread::manager()->is_used())
return true;
torrent::Object* resume_base = &d->download()->bencode()->get_key("libtorrent_resume");
@@ -137,30 +51,38 @@ DownloadStore::save(Download* d, int flags) {
resume_base->set_flags(torrent::Object::flag_session_data);
rtorrent_base->set_flags(torrent::Object::flag_session_data);
std::string base_filename = create_filename(d);
auto download_stream = std::unique_ptr<std::stringstream>();
auto resume_stream = std::make_unique<std::stringstream>();
auto rtorrent_stream = std::make_unique<std::stringstream>();
if (!write_bencode(base_filename + ".libtorrent_resume.new", *resume_base, 0) ||
!write_bencode(base_filename + ".rtorrent.new", *rtorrent_base, 0))
if (!(flags & flag_skip_static)) {
download_stream = std::make_unique<std::stringstream>();
torrent::object_write_bencode(&*download_stream, d->bencode(), torrent::Object::flag_session_data);
if (!download_stream->good())
return false;
}
torrent::object_write_bencode(&*resume_stream, resume_base, 0);
// TODO: Add logging.
if (!resume_stream->good())
return false;
::rename((base_filename + ".libtorrent_resume.new").c_str(), (base_filename + ".libtorrent_resume").c_str());
::rename((base_filename + ".rtorrent.new").c_str(), (base_filename + ".rtorrent").c_str());
torrent::object_write_bencode(&*rtorrent_stream, rtorrent_base, 0);
if (!(flags & flag_skip_static) &&
write_bencode(base_filename + ".new", *d->bencode(), torrent::Object::flag_session_data))
::rename((base_filename + ".new").c_str(), base_filename.c_str());
if (!rtorrent_stream->good())
return false;
auto base_filename = create_filename(d);
session_thread::manager()->save_download(d, base_filename, std::move(download_stream), std::move(resume_stream), std::move(rtorrent_stream));
return true;
}
void
DownloadStore::remove(Download* d) {
if (!is_enabled())
return;
::unlink((create_filename(d) + ".libtorrent_resume").c_str());
::unlink((create_filename(d) + ".rtorrent").c_str());
::unlink(create_filename(d).c_str());
session_thread::manager()->remove_download(d, create_filename(d));
}
// This also needs to check that it isn't a directory.
@@ -171,13 +93,13 @@ not_correct_format(const utils::directory_entry& entry) {
utils::Directory
DownloadStore::get_formated_entries() {
if (!is_enabled())
if (!session_thread::manager()->is_used())
return utils::Directory();
utils::Directory d(m_path);
utils::Directory d(session_thread::manager()->path());
if (!d.update(utils::Directory::update_hide_dot))
throw torrent::storage_error("core::DownloadStore::update() could not open directory \"" + m_path + "\"");
throw torrent::storage_error("core::DownloadStore::update() could not open session directory: " + session_thread::manager()->path());
d.erase(std::remove_if(d.begin(), d.end(), [&](const utils::directory_entry& entry) { return not_correct_format(entry); }), d.end());
@@ -199,7 +121,7 @@ DownloadStore::is_correct_format(const std::string& f) {
std::string
DownloadStore::create_filename(Download* d) {
return m_path + rak::transform_hex(d->info()->hash().begin(), d->info()->hash().end()) + ".torrent";
return session_thread::manager()->path() + rak::transform_hex(d->info()->hash().begin(), d->info()->hash().end()) + ".torrent";
}
}
+1 -15
View File
@@ -2,8 +2,7 @@
#define RTORRENT_CORE_DOWNLOAD_STORE_H
#include <string>
#include "utils/lockfile.h"
#include <torrent/common.h>
namespace utils {
class Directory;
@@ -17,14 +16,6 @@ class DownloadStore {
public:
static const int flag_skip_static = 0x1;
bool is_enabled() { return m_lockfile.is_locked(); }
void enable(bool lock);
void disable();
const std::string& path() const { return m_path; }
void set_path(const std::string& path);
bool save(Download* d, int flags);
bool save_full(Download* d) { return save(d, 0); }
bool save_resume(Download* d) { return save(d, flag_skip_static); }
@@ -37,11 +28,6 @@ public:
private:
std::string create_filename(Download* d);
bool write_bencode(const std::string& filename, const torrent::Object& obj, uint32_t skip_mask);
std::string m_path;
utils::Lockfile m_lockfile;
};
}