From 0efa042414fe7e3d02a0e0782416d5d4e2b0eb4a Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Mon, 27 Jun 2005 22:04:34 +0000 Subject: [PATCH] made the file pool global instead of local per torrent --- src/storage.cpp | 118 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 87 insertions(+), 31 deletions(-) diff --git a/src/storage.cpp b/src/storage.cpp index cfeebf1c1..f3608a1e1 100755 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -53,6 +53,10 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include +#include +#include +#include #ifdef _MSC_VER #pragma warning(pop) @@ -86,6 +90,7 @@ bool operator<(boost::filesystem::path const& lhs using namespace boost::filesystem; namespace pt = boost::posix_time; using boost::bind; +using namespace ::boost::multi_index; namespace { @@ -98,12 +103,27 @@ namespace log.flush(); } + struct file_key + { + file_key(sha1_hash ih, path f): info_hash(ih), file_path(f) {} + file_key() {} + sha1_hash info_hash; + path file_path; + bool operator<(file_key const& fk) const + { + if (info_hash < fk.info_hash) return true; + if (fk.info_hash < info_hash) return false; + return file_path < fk.file_path; + } + }; + struct file_entry { - file_entry(boost::shared_ptr const& f_) - : f(f_) + file_entry(boost::shared_ptr const& f) + : file_ptr(f) , last_use(pt::second_clock::universal_time()) {} - boost::shared_ptr f; + mutable boost::shared_ptr file_ptr; + file_key key; pt::ptime last_use; file::open_mode mode; }; @@ -112,46 +132,74 @@ namespace { file_pool(int size): m_size(size) {} - boost::shared_ptr open_file(path const& p, file::open_mode m) + boost::shared_ptr open_file(sha1_hash const& info_hash, path const& p, file::open_mode m) { assert(p.is_complete()); - typedef std::map::iterator iterator; - iterator i = m_files.find(p); - if (i != m_files.end()) + typedef file_set::nth_index<0>::type path_view; + path_view& pt = m_files.get<0>(); + path_view::iterator i = pt.find(file_key(info_hash, p)); + if (i != pt.end()) { - i->second.last_use = pt::second_clock::universal_time(); - if ((i->second.mode & m) != m) + file_entry e = *i; + e.last_use = pt::second_clock::universal_time(); + if ((e.mode & m) != m) { // close the file before we open it with // the new read/write privilages - i->second.f.reset(); - i->second.f.reset(new file(p, m)); - i->second.mode = m; + e.file_ptr.reset(); + e.file_ptr.reset(new file(p, m)); + e.mode = m; } - return i->second.f; + pt.replace(i, e); + return e.file_ptr; } // the file is not in our cache if ((int)m_files.size() >= m_size) { - i = m_files.begin(); - for (iterator j = boost::next(m_files.begin()); j != m_files.end(); ++j) - if (j->second.last_use < i->second.last_use) i = j; - m_files.erase(i); + // the file cache is at its maximum size, close + // the least recently used (lru) file from it + typedef file_set::nth_index<1>::type lru_view; + lru_view& lt = m_files.get<1>(); + lru_view::iterator i = lt.begin(); + // the first entry in this view is the least recently used + assert(lt.size() == 1 || boost::next(i)->last_use > i->last_use); + lt.erase(i); } file_entry e(boost::shared_ptr(new file(p, m))); e.mode = m; - m_files.insert(std::make_pair(p, e)); - return e.f; + e.key.info_hash = info_hash; + e.key.file_path = p; + pt.insert(e); + return e.file_ptr; } - void release() + void release(sha1_hash const& info_hash) { - m_files.clear(); + using namespace boost::lambda; + using boost::lambda::_1; + + typedef file_set::nth_index<0>::type path_view; + path_view& pt = m_files.get<0>(); + file_key lower_key(info_hash, path()); + file_key upper_key(info_hash, path()); + upper_key.info_hash[19] += 1; + std::pair r + = pt.range(!(_1 < lower_key), _1 < upper_key); + pt.erase(r.first, r.second); } private: int m_size; - std::map m_files; + + typedef boost::multi_index_container< + file_entry, indexed_by< + ordered_unique > + , ordered_non_unique > + > + > file_set; + + file_set m_files; }; } @@ -270,7 +318,6 @@ namespace libtorrent impl(torrent_info const& info, path const& path) : thread_safe_storage(info.num_pieces()) , info(info) - , files(10) { save_path = complete(path); assert(save_path.is_complete()); @@ -280,14 +327,15 @@ namespace libtorrent : thread_safe_storage(x.info.num_pieces()) , info(x.info) , save_path(x.save_path) - , files(x.files) {} torrent_info const& info; path save_path; - file_pool files; + static file_pool files; }; + file_pool storage::impl::files(100); + storage::storage(const torrent_info& info, const path& path) : m_pimpl(new impl(info, path)) { @@ -296,7 +344,7 @@ namespace libtorrent void storage::release_files() { - m_pimpl->files.release(); + m_pimpl->files.release(m_pimpl->info.info_hash()); } void storage::swap(storage& other) @@ -317,7 +365,7 @@ namespace libtorrent else if(!is_directory(save_path)) return false; - m_pimpl->files.release(); + m_pimpl->files.release(m_pimpl->info.info_hash()); if (m_pimpl->info.num_files() == 1) { @@ -406,7 +454,8 @@ namespace libtorrent } boost::shared_ptr in(m_pimpl->files.open_file( - m_pimpl->save_path / file_iter->path + m_pimpl->info.info_hash() + , m_pimpl->save_path / file_iter->path , file::in)); assert(file_offset < file_iter->size); @@ -459,7 +508,9 @@ namespace libtorrent path path = m_pimpl->save_path / file_iter->path; file_offset = 0; - in = m_pimpl->files.open_file(path, file::in); + in = m_pimpl->files.open_file( + m_pimpl->info.info_hash() + , path, file::in); in->seek(0); } } @@ -499,7 +550,9 @@ namespace libtorrent } path p(m_pimpl->save_path / file_iter->path); - boost::shared_ptr out = m_pimpl->files.open_file(p, file::out | file::in); + boost::shared_ptr out = m_pimpl->files.open_file( + m_pimpl->info.info_hash() + , p, file::out | file::in); assert(file_offset < file_iter->size); @@ -556,7 +609,10 @@ namespace libtorrent assert(file_iter != m_pimpl->info.end_files()); path p = m_pimpl->save_path / file_iter->path; file_offset = 0; - out = m_pimpl->files.open_file(p, file::out | file::in); + out = m_pimpl->files.open_file( + m_pimpl->info.info_hash() + , p, file::out | file::in); + out->seek(0); } }