3 Copyright (c) 2007, 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 #ifndef TORRENT_DISK_IO_THREAD
34 #define TORRENT_DISK_IO_THREAD
36 #ifdef TORRENT_DISK_STATS
40 #include "libtorrent/storage.hpp"
41 #include <boost/thread/thread.hpp>
42 #include <boost/function.hpp>
43 #include <boost/thread/mutex.hpp>
44 #include <boost/bind.hpp>
45 #include <boost/noncopyable.hpp>
46 #include <boost/shared_array.hpp>
48 #include "libtorrent/config.hpp"
49 #ifndef TORRENT_DISABLE_POOL_ALLOCATOR
50 #include <boost/pool/pool.hpp>
56 struct cached_piece_info
59 std::vector
<bool> blocks
;
61 enum kind_t
{ read_cache
= 0, write_cache
= 1 };
96 boost::intrusive_ptr
<piece_manager
> storage
;
97 // arguments used for read and write
99 // used for move_storage and rename_file. On errors, this is set
100 // to the error message
103 // on error, this is set to the path of the
104 // file the disk operation failed on
105 std::string error_file
;
107 // priority decides whether or not this
108 // job will skip entries in the queue or
109 // not. It always skips in front of entries
110 // with lower priority
113 boost::shared_ptr
<entry
> resume_data
;
115 // the error code from the file operation
118 // this is called when operation completes
119 boost::function
<void(int, disk_io_job
const&)> callback
;
134 // the number of 16kB blocks written
135 size_type blocks_written
;
136 // the number of write operations used
138 // (blocks_written - writes) / blocks_written represents the
139 // "cache hit" ratio in the write cache
140 // the number of blocks read
142 // the number of blocks passed back to the bittorrent engine
143 size_type blocks_read
;
144 // the number of blocks that was just copied from the read cache
145 size_type blocks_read_hit
;
146 // the number of read operations used
149 // the number of blocks in the cache (both read and write)
152 // the number of blocks in the cache used for read cache
156 // this is a singleton consisting of the thread and a queue
158 struct disk_io_thread
: boost::noncopyable
160 disk_io_thread(io_service
& ios
, int block_size
= 16 * 1024);
164 int disk_allocations() const
165 { return m_allocations
; }
170 // aborts read operations
171 void stop(boost::intrusive_ptr
<piece_manager
> s
);
172 void add_job(disk_io_job
const& j
173 , boost::function
<void(int, disk_io_job
const&)> const& f
174 = boost::function
<void(int, disk_io_job
const&)>());
176 // keep track of the number of bytes in the job queue
177 // at any given time. i.e. the sum of all buffer_size.
178 // this is used to slow down the download global download
179 // speed when the queue buffer size is too big.
180 size_type
queue_buffer_size() const
181 { return m_queue_buffer_size
; }
183 void get_cache_info(sha1_hash
const& ih
184 , std::vector
<cached_piece_info
>& ret
) const;
186 cache_status
status() const;
187 void set_cache_size(int s
);
188 void set_cache_expiry(int ex
);
193 bool is_disk_buffer(char* buffer
) const;
196 char* allocate_buffer();
197 void free_buffer(char* buf
);
200 void check_invariant() const;
205 struct cached_piece_entry
208 // storage this piece belongs to
209 boost::intrusive_ptr
<piece_manager
> storage
;
210 // the last time a block was writting to this piece
212 // the number of blocks in the cache for this piece
214 // the pointers to the block data
215 boost::shared_array
<char*> blocks
;
218 typedef boost::recursive_mutex mutex_t
;
219 typedef std::list
<cached_piece_entry
> cache_t
;
221 bool test_error(disk_io_job
& j
);
224 cache_t::iterator
find_cached_piece(
225 cache_t
& cache
, disk_io_job
const& j
226 , mutex_t::scoped_lock
& l
);
228 // write cache operations
229 void flush_oldest_piece(mutex_t::scoped_lock
& l
);
230 void flush_expired_pieces();
231 void flush_and_remove(cache_t::iterator i
, mutex_t::scoped_lock
& l
);
232 void flush(cache_t::iterator i
, mutex_t::scoped_lock
& l
);
233 void cache_block(disk_io_job
& j
, mutex_t::scoped_lock
& l
);
235 // read cache operations
236 bool clear_oldest_read_piece(cache_t::iterator ignore
237 , mutex_t::scoped_lock
& l
);
238 int read_into_piece(cached_piece_entry
& p
, int start_block
, mutex_t::scoped_lock
& l
);
239 int cache_read_block(disk_io_job
const& j
, mutex_t::scoped_lock
& l
);
240 void free_piece(cached_piece_entry
& p
, mutex_t::scoped_lock
& l
);
241 bool make_room(int num_blocks
242 , cache_t::iterator ignore
243 , mutex_t::scoped_lock
& l
);
244 int try_read_from_cache(disk_io_job
const& j
);
246 // this mutex only protects m_jobs, m_queue_buffer_size
248 mutable mutex_t m_queue_mutex
;
249 boost::condition m_signal
;
251 std::list
<disk_io_job
> m_jobs
;
252 size_type m_queue_buffer_size
;
254 // this protects the piece cache and related members
255 mutable mutex_t m_piece_mutex
;
260 cache_t m_read_pieces
;
262 // total number of blocks in use by both the read
263 // and the write cache. This is not supposed to
264 // exceed m_cache_size
265 cache_status m_cache_stats
;
266 int m_num_cached_blocks
;
271 // expiration time of cache entries in seconds
274 // if set to true, each piece flush will allocate
275 // one piece worth of temporary memory on the heap
276 // and copy the block data into it, and then perform
277 // a single write operation from that buffer.
278 // if memory is constrained, that temporary buffer
279 // might is avoided by setting this to false.
280 // in case the allocation fails, the piece flush
281 // falls back to writing each block separately.
282 bool m_coalesce_writes
;
283 bool m_coalesce_reads
;
284 bool m_use_read_cache
;
286 // this only protects the pool allocator
287 mutable mutex_t m_pool_mutex
;
288 #ifndef TORRENT_DISABLE_POOL_ALLOCATOR
289 // memory pool for read and write operations
291 boost::pool
<> m_pool
;
294 // number of bytes per block. The BitTorrent
295 // protocol defines the block size to 16 KiB.
298 #ifdef TORRENT_DISK_STATS
306 size_type m_blocks_written
;
310 // thread for performing blocking disk io operations
311 boost::thread m_disk_io_thread
;