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/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>
49 #include "libtorrent/config.hpp"
50 #ifndef TORRENT_DISABLE_POOL_ALLOCATOR
51 #include <boost/pool/pool.hpp>
57 struct cached_piece_info
60 std::vector
<bool> blocks
;
62 enum kind_t
{ read_cache
= 0, write_cache
= 1 };
97 boost::intrusive_ptr
<piece_manager
> storage
;
98 // arguments used for read and write
100 // used for move_storage and rename_file. On errors, this is set
101 // to the error message
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
114 boost::shared_ptr
<entry
> resume_data
;
116 // the error code from the file operation
119 // this is called when operation completes
120 boost::function
<void(int, disk_io_job
const&)> callback
;
135 // the number of 16kB blocks written
136 size_type blocks_written
;
137 // the number of write operations used
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
150 // the number of blocks in the cache (both read and write)
153 // the number of blocks in the cache used for read cache
157 // this is a singleton consisting of the thread and a queue
159 struct disk_io_thread
: boost::noncopyable
161 disk_io_thread(io_service
& ios
, int block_size
= 16 * 1024);
165 int disk_allocations() const
166 { return m_allocations
; }
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
);
194 bool is_disk_buffer(char* buffer
) const;
197 char* allocate_buffer();
198 void free_buffer(char* buf
);
201 void check_invariant() const;
206 struct cached_piece_entry
209 // storage this piece belongs to
210 boost::intrusive_ptr
<piece_manager
> storage
;
211 // the last time a block was writting to this piece
213 // the number of blocks in the cache for this piece
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
);
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
249 mutable mutex_t m_queue_mutex
;
250 boost::condition m_signal
;
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
;
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
;
272 // expiration time of cache entries in seconds
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
292 boost::pool
<> m_pool
;
295 // number of bytes per block. The BitTorrent
296 // protocol defines the block size to 16 KiB.
299 #ifdef TORRENT_DISK_STATS
307 size_type m_blocks_written
;
311 // thread for performing blocking disk io operations
312 boost::thread m_disk_io_thread
;