3 Copyright (c) 2006, Arvid Norberg
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the distribution.
15 * Neither the name of the author nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
33 #include <boost/version.hpp>
34 #include "libtorrent/pch.hpp"
35 #include "libtorrent/file_pool.hpp"
36 #include "libtorrent/error_code.hpp"
42 using boost::multi_index::nth_index
;
43 using boost::multi_index::get
;
45 #if BOOST_VERSION >= 103500
46 struct file_pool_error_category
: boost::system::error_category
48 virtual const char* name() const { return "file pool error"; }
49 virtual std::string
message(int ev
) const
51 static char const* msgs
[] =
52 { "no error", "torrent file collides with file from another torrent" };
53 if (ev
< 0 || ev
>= sizeof(msgs
)/sizeof(msgs
[0]))
54 return "Unknown error";
57 virtual boost::system::error_condition
default_error_condition(int ev
) const
59 return boost::system::error_condition(ev
, *this);
61 virtual bool equivalent(int code
, boost::system::error_condition
const& condition
) const
63 return default_error_condition(code
) == condition
;
65 virtual bool equivalent(boost::system::error_code
const& code
, int condition
) const
67 return *this == code
.category() && code
.value() == condition
;
71 file_pool_error_category file_pool_category
;
75 boost::shared_ptr
<file
> file_pool::open_file(void* st
, fs::path
const& p
76 , file::open_mode m
, error_code
& ec
)
78 TORRENT_ASSERT(st
!= 0);
79 TORRENT_ASSERT(p
.is_complete());
80 TORRENT_ASSERT(m
== file::in
|| m
== (file::in
| file::out
));
81 boost::mutex::scoped_lock
l(m_mutex
);
82 typedef nth_index
<file_set
, 0>::type path_view
;
83 path_view
& pt
= get
<0>(m_files
);
84 path_view::iterator i
= pt
.find(p
);
87 lru_file_entry e
= *i
;
88 e
.last_use
= time_now();
92 // this means that another instance of the storage
93 // is using the exact same file.
94 #if BOOST_VERSION >= 103500
95 ec
= error_code(1, file_pool_category
);
97 return boost::shared_ptr
<file
>();
101 if ((e
.mode
& m
) != m
)
103 // close the file before we open it with
104 // the new read/write privilages
106 TORRENT_ASSERT(e
.file_ptr
.unique());
108 if (!e
.file_ptr
->open(p
, m
, ec
))
111 return boost::shared_ptr
<file
>();
118 // the file is not in our cache
119 if ((int)m_files
.size() >= m_size
)
121 // the file cache is at its maximum size, close
122 // the least recently used (lru) file from it
123 typedef nth_index
<file_set
, 1>::type lru_view
;
124 lru_view
& lt
= get
<1>(m_files
);
125 lru_view::iterator i
= lt
.begin();
126 // the first entry in this view is the least recently used
127 TORRENT_ASSERT(lt
.size() == 1 || (i
->last_use
<= boost::next(i
)->last_use
));
131 e
.file_ptr
.reset(new (std::nothrow
)file
);
134 ec
= error_code(ENOMEM
, get_posix_category());
137 if (!e
.file_ptr
->open(p
, m
, ec
))
138 return boost::shared_ptr
<file
>();
146 void file_pool::release(fs::path
const& p
)
148 boost::mutex::scoped_lock
l(m_mutex
);
150 typedef nth_index
<file_set
, 0>::type path_view
;
151 path_view
& pt
= get
<0>(m_files
);
152 path_view::iterator i
= pt
.find(p
);
153 if (i
!= pt
.end()) pt
.erase(i
);
156 void file_pool::release(void* st
)
158 boost::mutex::scoped_lock
l(m_mutex
);
159 TORRENT_ASSERT(st
!= 0);
162 typedef nth_index
<file_set
, 2>::type key_view
;
163 key_view
& kt
= get
<2>(m_files
);
165 key_view::iterator start
, end
;
166 tie(start
, end
) = kt
.equal_range(st
);
167 kt
.erase(start
, end
);
170 void file_pool::resize(int size
)
172 TORRENT_ASSERT(size
> 0);
173 if (size
== m_size
) return;
174 boost::mutex::scoped_lock
l(m_mutex
);
176 if (int(m_files
.size()) <= m_size
) return;
178 // close the least recently used files
179 typedef nth_index
<file_set
, 1>::type lru_view
;
180 lru_view
& lt
= get
<1>(m_files
);
181 lru_view::iterator i
= lt
.begin();
182 while (int(m_files
.size()) > m_size
)
184 // the first entry in this view is the least recently used
185 TORRENT_ASSERT(lt
.size() == 1 || (i
->last_use
<= boost::next(i
)->last_use
));