From f5c4476ce3e78c99a5ee0f4a63504106eb93a8c0 Mon Sep 17 00:00:00 2001 From: Daniel Wallin Date: Sun, 7 Dec 2003 16:26:16 +0000 Subject: [PATCH] made storage thread safe --- include/libtorrent/storage.hpp | 14 +++-- src/storage.cpp | 99 +++++++++++++++++++++++++++++----- 2 files changed, 97 insertions(+), 16 deletions(-) diff --git a/include/libtorrent/storage.hpp b/include/libtorrent/storage.hpp index 9cf1cc172..db40de37b 100755 --- a/include/libtorrent/storage.hpp +++ b/include/libtorrent/storage.hpp @@ -211,6 +211,7 @@ namespace libtorrent torrent* m_torrent; }; */ + // provides thread safe read/write operations on a torrent storage class storage { public: @@ -218,17 +219,24 @@ namespace libtorrent const torrent_info& info , const boost::filesystem::path& path); + ~storage(); + + storage(const storage&); + void operator=(const storage&); + + void swap(storage&); + typedef entry::integer_type size_type; size_type read(char* buf, int slot, size_type offset, size_type size); void write(const char* buf, int slot, size_type offset, size_type size); private: - const torrent_info& m_info; - const boost::filesystem::path m_save_path; + struct pimpl; + std::auto_ptr m_pimpl; }; - class piece_manager + class piece_manager : boost::noncopyable { public: diff --git a/src/storage.cpp b/src/storage.cpp index ecff7852a..3ed1dac04 100755 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -1294,13 +1294,82 @@ namespace { namespace libtorrent { + struct thread_safe_storage + { + thread_safe_storage(std::size_t n) + : slots(n, false) + {} + + boost::mutex mutex; + boost::condition condition; + std::vector slots; + }; + + struct slot_lock + { + slot_lock(thread_safe_storage& s, int slot_) + : storage_(s) + , slot(slot_) + { + boost::mutex::scoped_lock lock(storage_.mutex); + + while (storage_.slots[slot]) + storage_.condition.wait(lock); + storage_.slots[slot] = true; + } + + ~slot_lock() + { + storage_.slots[slot] = false; + storage_.condition.notify_all(); + } + + thread_safe_storage& storage_; + int slot; + }; + + struct storage::pimpl : thread_safe_storage + { + pimpl(const torrent_info& info, const fs::path& path) + : thread_safe_storage(info.num_pieces()) + , info(info) + , save_path(path) + {} + + pimpl(const pimpl& x) + : thread_safe_storage(x.info.num_pieces()) + , info(x.info) + , save_path(x.save_path) + {} + + const torrent_info& info; + const boost::filesystem::path save_path; + }; + storage::storage(const torrent_info& info, const fs::path& path) - : m_info(info) - , m_save_path(path) + : m_pimpl(new pimpl(info, path)) { assert(info.begin_files() != info.end_files()); } + storage::~storage() + {} + + storage::storage(const storage& other) + : m_pimpl(new pimpl(*other.m_pimpl)) + {} + + void storage::swap(storage& other) + { + std::swap(m_pimpl, other.m_pimpl); + } + + void storage::operator=(const storage& other) + { + storage tmp(other); + tmp.swap(*this); + } + storage::size_type storage::read( char* buf , int slot @@ -1308,14 +1377,16 @@ namespace libtorrent { , size_type size) { assert(size > 0); + + slot_lock lock(*m_pimpl, slot); - size_type start = slot * m_info.piece_length() + offset; + size_type start = slot * m_pimpl->info.piece_length() + offset; // find the file iterator and file offset size_type file_offset = start; std::vector::const_iterator file_iter; - for (file_iter = m_info.begin_files();;) + for (file_iter = m_pimpl->info.begin_files();;) { if (file_offset < file_iter->size) break; @@ -1325,7 +1396,7 @@ namespace libtorrent { } fs::ifstream in( - m_save_path / file_iter->path / file_iter->filename + m_pimpl->save_path / file_iter->path / file_iter->filename , std::ios_base::binary ); @@ -1336,7 +1407,7 @@ namespace libtorrent { assert(size_type(in.tellg()) == file_offset); size_type left_to_read = size; - size_type slot_size = m_info.piece_size(slot); + size_type slot_size = m_pimpl->info.piece_size(slot); if (offset + left_to_read > slot_size) left_to_read = slot_size - offset; @@ -1366,7 +1437,7 @@ namespace libtorrent { if (left_to_read > 0) { ++file_iter; - fs::path path = m_save_path / file_iter->path / file_iter->filename; + fs::path path = m_pimpl->save_path / file_iter->path / file_iter->filename; file_offset = 0; in.close(); @@ -1382,13 +1453,15 @@ namespace libtorrent { { assert(size > 0); - size_type start = slot * m_info.piece_length() + offset; + slot_lock lock(*m_pimpl, slot); + + size_type start = slot * m_pimpl->info.piece_length() + offset; // find the file iterator and file offset size_type file_offset = start; std::vector::const_iterator file_iter; - for (file_iter = m_info.begin_files();;) + for (file_iter = m_pimpl->info.begin_files();;) { if (file_offset < file_iter->size) break; @@ -1397,7 +1470,7 @@ namespace libtorrent { ++file_iter; } - fs::path path(m_save_path / file_iter->path / file_iter->filename); + fs::path path(m_pimpl->save_path / file_iter->path / file_iter->filename); fs::ofstream out; if (fs::exists(path)) @@ -1412,7 +1485,7 @@ namespace libtorrent { assert(file_offset == out.tellp()); size_type left_to_write = size; - size_type slot_size = m_info.piece_size(slot); + size_type slot_size = m_pimpl->info.piece_size(slot); if (offset + left_to_write > slot_size) left_to_write = slot_size - offset; @@ -1446,9 +1519,9 @@ namespace libtorrent { { ++file_iter; - assert(file_iter != m_info.end_files()); + assert(file_iter != m_pimpl->info.end_files()); - fs::path path = m_save_path / file_iter->path / file_iter->filename; + fs::path path = m_pimpl->save_path / file_iter->path / file_iter->filename; file_offset = 0; out.close();