fixes bug where priorities where lost when force-rechecking.
[libtorrent.git] / include / libtorrent / disk_io_thread.hpp
blob23e8dd349a18f4cd04f04f40a9119b1028081207
1 /*
3 Copyright (c) 2007, Arvid Norberg
4 All rights reserved.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
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 #ifndef TORRENT_DISK_IO_THREAD
34 #define TORRENT_DISK_IO_THREAD
36 #ifdef TORRENT_DISK_STATS
37 #include <fstream>
38 #endif
40 #include "libtorrent/storage.hpp"
41 #include <boost/thread/thread.hpp>
42 #include <boost/thread/mutex.hpp>
43 #include <boost/thread/condition.hpp>
44 #include <boost/function.hpp>
45 #include <boost/bind.hpp>
46 #include <boost/noncopyable.hpp>
47 #include <boost/shared_array.hpp>
48 #include <list>
49 #include "libtorrent/config.hpp"
50 #ifndef TORRENT_DISABLE_POOL_ALLOCATOR
51 #include <boost/pool/pool.hpp>
52 #endif
54 namespace libtorrent
57 struct cached_piece_info
59 int piece;
60 std::vector<bool> blocks;
61 ptime last_use;
62 enum kind_t { read_cache = 0, write_cache = 1 };
63 kind_t kind;
66 struct disk_io_job
68 disk_io_job()
69 : action(read)
70 , buffer(0)
71 , buffer_size(0)
72 , piece(0)
73 , offset(0)
74 , priority(0)
77 enum action_t
79 read
80 , write
81 , hash
82 , move_storage
83 , release_files
84 , delete_files
85 , check_fastresume
86 , check_files
87 , save_resume_data
88 , rename_file
89 , abort_thread
90 , clear_read_cache
93 action_t action;
95 char* buffer;
96 int buffer_size;
97 boost::intrusive_ptr<piece_manager> storage;
98 // arguments used for read and write
99 int piece, offset;
100 // used for move_storage and rename_file. On errors, this is set
101 // to the error message
102 std::string str;
104 // on error, this is set to the path of the
105 // file the disk operation failed on
106 std::string error_file;
108 // priority decides whether or not this
109 // job will skip entries in the queue or
110 // not. It always skips in front of entries
111 // with lower priority
112 int priority;
114 boost::shared_ptr<entry> resume_data;
116 // the error code from the file operation
117 error_code error;
119 // this is called when operation completes
120 boost::function<void(int, disk_io_job const&)> callback;
123 struct cache_status
125 cache_status()
126 : blocks_written(0)
127 , writes(0)
128 , blocks_read(0)
129 , blocks_read_hit(0)
130 , reads(0)
131 , cache_size(0)
132 , read_cache_size(0)
135 // the number of 16kB blocks written
136 size_type blocks_written;
137 // the number of write operations used
138 size_type writes;
139 // (blocks_written - writes) / blocks_written represents the
140 // "cache hit" ratio in the write cache
141 // the number of blocks read
143 // the number of blocks passed back to the bittorrent engine
144 size_type blocks_read;
145 // the number of blocks that was just copied from the read cache
146 size_type blocks_read_hit;
147 // the number of read operations used
148 size_type reads;
150 // the number of blocks in the cache (both read and write)
151 int cache_size;
153 // the number of blocks in the cache used for read cache
154 int read_cache_size;
157 // this is a singleton consisting of the thread and a queue
158 // of disk io jobs
159 struct disk_io_thread : boost::noncopyable
161 disk_io_thread(io_service& ios, int block_size = 16 * 1024);
162 ~disk_io_thread();
164 #ifdef TORRENT_STATS
165 int disk_allocations() const
166 { return m_allocations; }
167 #endif
169 void join();
171 // aborts read operations
172 void stop(boost::intrusive_ptr<piece_manager> s);
173 void add_job(disk_io_job const& j
174 , boost::function<void(int, disk_io_job const&)> const& f
175 = boost::function<void(int, disk_io_job const&)>());
177 // keep track of the number of bytes in the job queue
178 // at any given time. i.e. the sum of all buffer_size.
179 // this is used to slow down the download global download
180 // speed when the queue buffer size is too big.
181 size_type queue_buffer_size() const
182 { return m_queue_buffer_size; }
184 void get_cache_info(sha1_hash const& ih
185 , std::vector<cached_piece_info>& ret) const;
187 cache_status status() const;
188 void set_cache_size(int s);
189 void set_cache_expiry(int ex);
191 void operator()();
193 #ifndef NDEBUG
194 bool is_disk_buffer(char* buffer) const;
195 #endif
197 char* allocate_buffer();
198 void free_buffer(char* buf);
200 #ifndef NDEBUG
201 void check_invariant() const;
202 #endif
204 private:
206 struct cached_piece_entry
208 int piece;
209 // storage this piece belongs to
210 boost::intrusive_ptr<piece_manager> storage;
211 // the last time a block was writting to this piece
212 ptime last_use;
213 // the number of blocks in the cache for this piece
214 int num_blocks;
215 // the pointers to the block data
216 boost::shared_array<char*> blocks;
219 typedef boost::recursive_mutex mutex_t;
220 typedef std::list<cached_piece_entry> cache_t;
222 bool test_error(disk_io_job& j);
224 // cache operations
225 cache_t::iterator find_cached_piece(
226 cache_t& cache, disk_io_job const& j
227 , mutex_t::scoped_lock& l);
229 // write cache operations
230 void flush_oldest_piece(mutex_t::scoped_lock& l);
231 void flush_expired_pieces();
232 void flush_and_remove(cache_t::iterator i, mutex_t::scoped_lock& l);
233 void flush(cache_t::iterator i, mutex_t::scoped_lock& l);
234 void cache_block(disk_io_job& j, mutex_t::scoped_lock& l);
236 // read cache operations
237 bool clear_oldest_read_piece(cache_t::iterator ignore
238 , mutex_t::scoped_lock& l);
239 int read_into_piece(cached_piece_entry& p, int start_block, mutex_t::scoped_lock& l);
240 int cache_read_block(disk_io_job const& j, mutex_t::scoped_lock& l);
241 void free_piece(cached_piece_entry& p, mutex_t::scoped_lock& l);
242 bool make_room(int num_blocks
243 , cache_t::iterator ignore
244 , mutex_t::scoped_lock& l);
245 int try_read_from_cache(disk_io_job const& j);
247 // this mutex only protects m_jobs, m_queue_buffer_size
248 // and m_abort
249 mutable mutex_t m_queue_mutex;
250 boost::condition m_signal;
251 bool m_abort;
252 std::list<disk_io_job> m_jobs;
253 size_type m_queue_buffer_size;
255 // this protects the piece cache and related members
256 mutable mutex_t m_piece_mutex;
257 // write cache
258 cache_t m_pieces;
260 // read cache
261 cache_t m_read_pieces;
263 // total number of blocks in use by both the read
264 // and the write cache. This is not supposed to
265 // exceed m_cache_size
266 cache_status m_cache_stats;
267 int m_num_cached_blocks;
269 // in (16kB) blocks
270 int m_cache_size;
272 // expiration time of cache entries in seconds
273 int m_cache_expiry;
275 // if set to true, each piece flush will allocate
276 // one piece worth of temporary memory on the heap
277 // and copy the block data into it, and then perform
278 // a single write operation from that buffer.
279 // if memory is constrained, that temporary buffer
280 // might is avoided by setting this to false.
281 // in case the allocation fails, the piece flush
282 // falls back to writing each block separately.
283 bool m_coalesce_writes;
284 bool m_coalesce_reads;
285 bool m_use_read_cache;
287 // this only protects the pool allocator
288 mutable mutex_t m_pool_mutex;
289 #ifndef TORRENT_DISABLE_POOL_ALLOCATOR
290 // memory pool for read and write operations
291 // and disk cache
292 boost::pool<> m_pool;
293 #endif
295 // number of bytes per block. The BitTorrent
296 // protocol defines the block size to 16 KiB.
297 int m_block_size;
299 #ifdef TORRENT_DISK_STATS
300 std::ofstream m_log;
301 #endif
302 #ifdef TORRENT_STATS
303 int m_allocations;
304 #endif
306 size_type m_writes;
307 size_type m_blocks_written;
309 io_service& m_ios;
311 // thread for performing blocking disk io operations
312 boost::thread m_disk_io_thread;
317 #endif