33
33
#include <boost/version.hpp>
34
#include <boost/bind.hpp>
34
35
#include "libtorrent/pch.hpp"
35
36
#include "libtorrent/file_pool.hpp"
36
37
#include "libtorrent/error_code.hpp"
40
39
namespace libtorrent
42
using boost::multi_index::nth_index;
43
using boost::multi_index::get;
45
41
boost::shared_ptr<file> file_pool::open_file(void* st, fs::path const& p
46
, file::open_mode m, error_code& ec)
42
, int m, error_code& ec)
48
44
TORRENT_ASSERT(st != 0);
49
45
TORRENT_ASSERT(p.is_complete());
50
TORRENT_ASSERT(m == file::in || m == (file::in | file::out));
46
TORRENT_ASSERT((m & file::rw_mask) == file::read_only
47
|| (m & file::rw_mask) == file::read_write);
51
48
boost::mutex::scoped_lock l(m_mutex);
52
typedef nth_index<file_set, 0>::type path_view;
53
path_view& pt = get<0>(m_files);
54
path_view::iterator i = pt.find(p);
49
file_set::iterator i = m_files.find(p.string());
50
if (i != m_files.end())
57
lru_file_entry e = *i;
52
lru_file_entry& e = i->second;
58
53
e.last_use = time_now();
60
if (e.key != st && (e.mode != file::in
55
if (e.key != st && ((e.mode & file::rw_mask) != file::read_only
56
|| (m & file::rw_mask) != file::read_only))
63
58
// this means that another instance of the storage
64
59
// is using the exact same file.
65
60
#if BOOST_VERSION >= 103500
66
ec = error_code(errors::file_collision, libtorrent_category);
61
ec = errors::file_collision;
68
63
return boost::shared_ptr<file>();
72
if ((e.mode & m) != m)
67
// if we asked for a file in write mode,
68
// and the cached file is is not opened in
69
// write mode, re-open it
71
if ((((e.mode & file::rw_mask) != file::read_write)
72
&& ((m & file::rw_mask) == file::read_write))
73
|| (e.mode & file::no_buffer) != (m & file::no_buffer))
74
75
// close the file before we open it with
75
76
// the new read/write privilages
77
77
TORRENT_ASSERT(e.file_ptr.unique());
78
78
e.file_ptr->close();
79
79
if (!e.file_ptr->open(p, m, ec))
82
82
return boost::shared_ptr<file>();
84
#ifdef TORRENT_WINDOWS
85
// file prio is supported on vista and up
86
#if _WIN32_WINNT >= 0x0600
89
FILE_IO_PRIORITY_HINT_INFO priorityHint;
90
priorityHint.PriorityHint = IoPriorityHintLow;
91
SetFileInformationByHandle(e.file_ptr->native_handle(),
92
FileIoPriorityHintInfo, &priorityHint, sizeof(PriorityHint));
84
96
TORRENT_ASSERT(e.file_ptr->is_open());
99
TORRENT_ASSERT((e.mode & file::no_buffer) == (m & file::no_buffer));
88
100
return e.file_ptr;
90
102
// the file is not in our cache
93
105
// the file cache is at its maximum size, close
94
106
// the least recently used (lru) file from it
95
typedef nth_index<file_set, 1>::type lru_view;
96
lru_view& lt = get<1>(m_files);
97
lru_view::iterator i = lt.begin();
98
// the first entry in this view is the least recently used
99
TORRENT_ASSERT(lt.size() == 1 || (i->last_use <= boost::next(i)->last_use));
102
109
lru_file_entry e;
103
110
e.file_ptr.reset(new (std::nothrow)file);
110
117
return boost::shared_ptr<file>();
120
m_files.insert(std::make_pair(p.string(), e));
115
121
TORRENT_ASSERT(e.file_ptr->is_open());
116
122
return e.file_ptr;
125
void file_pool::remove_oldest()
127
file_set::iterator i = std::min_element(m_files.begin(), m_files.end()
128
, boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _1))
129
< boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _2)));
130
if (i == m_files.end()) return;
119
134
void file_pool::release(fs::path const& p)
121
136
boost::mutex::scoped_lock l(m_mutex);
123
typedef nth_index<file_set, 0>::type path_view;
124
path_view& pt = get<0>(m_files);
125
path_view::iterator i = pt.find(p);
126
if (i != pt.end()) pt.erase(i);
138
file_set::iterator i = m_files.find(p.string());
139
if (i != m_files.end()) m_files.erase(i);
142
// closes files belonging to the specified
143
// storage. If 0 is passed, all files are closed
129
144
void file_pool::release(void* st)
131
146
boost::mutex::scoped_lock l(m_mutex);
132
TORRENT_ASSERT(st != 0);
135
typedef nth_index<file_set, 2>::type key_view;
136
key_view& kt = get<2>(m_files);
138
key_view::iterator start, end;
139
tie(start, end) = kt.equal_range(st);
140
kt.erase(start, end);
153
for (file_set::iterator i = m_files.begin();
156
if (i->second.key == st)
143
163
void file_pool::resize(int size)
149
169
if (int(m_files.size()) <= m_size) return;
151
171
// close the least recently used files
152
typedef nth_index<file_set, 1>::type lru_view;
153
lru_view& lt = get<1>(m_files);
154
lru_view::iterator i = lt.begin();
155
172
while (int(m_files.size()) > m_size)
157
// the first entry in this view is the least recently used
158
TORRENT_ASSERT(lt.size() == 1 || (i->last_use <= boost::next(i)->last_use));