diff --git a/docs/manual.html b/docs/manual.html index db1f018f8..4a0f33df8 100644 --- a/docs/manual.html +++ b/docs/manual.html @@ -2591,6 +2591,7 @@ struct session_settings int send_buffer_watermark; bool auto_upload_slots; int cache_size; + int cache_expiry; };

user_agent this is the client identification to the tracker. @@ -2715,6 +2716,8 @@ less than what has been set by se current number of upload slots, see session_status::allowed_upload_slots.

cache_size is the disk write cache. It is specified in units of 16 KiB blocks. It defaults to 128 (= 2 MB).

+

cache_expiry is the number of seconds from the last cached write to a piece +in the write cache, to when it's forcefully flushed to disk. Default is 60 second.

pe_settings

diff --git a/docs/manual.rst b/docs/manual.rst index af2b964f4..7964f45da 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -2580,6 +2580,7 @@ that will be sent to the tracker. The user-agent is a good way to identify your int send_buffer_watermark; bool auto_upload_slots; int cache_size; + int cache_expiry; }; ``user_agent`` this is the client identification to the tracker. @@ -2733,6 +2734,10 @@ current number of upload slots, see ``session_status::allowed_upload_slots``. ``cache_size`` is the disk write cache. It is specified in units of 16 KiB blocks. It defaults to 128 (= 2 MB). +``cache_expiry`` is the number of seconds from the last cached write to a piece +in the write cache, to when it's forcefully flushed to disk. Default is 60 second. + + pe_settings =========== diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 6ba87f44f..d1c0136d0 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -389,7 +389,7 @@ void print_peer_info(std::ostream& out, std::vector const } else { - out << progress_bar(0.f, 15); + out << progress_bar(0.f, 14); } #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES @@ -1197,7 +1197,9 @@ int main(int ac, char* av[]) #endif } char* piece_state[4] = {"", "slow", "medium", "fast"}; - out << "] " << piece_state[i->piece_state] << "\n"; + out << "] " << piece_state[i->piece_state]; + if (cp) out << (i->piece_state > 0?" | ":"") << "cache age: " << total_seconds(time_now() - cp->last_write); + out << "\n"; } out << "___________________________________\n"; diff --git a/include/libtorrent/disk_io_thread.hpp b/include/libtorrent/disk_io_thread.hpp index 17238ef3c..417be5943 100644 --- a/include/libtorrent/disk_io_thread.hpp +++ b/include/libtorrent/disk_io_thread.hpp @@ -146,6 +146,7 @@ namespace libtorrent cache_status status() const; void set_cache_size(int s); + void set_cache_expiry(int ex); void operator()(); @@ -175,6 +176,7 @@ namespace libtorrent std::vector::iterator find_cached_piece( disk_io_job const& j, mutex_t::scoped_lock& l); void flush_oldest_piece(mutex_t::scoped_lock& l); + void flush_expired_pieces(mutex_t::scoped_lock& l); void flush_and_remove(std::vector::iterator i, mutex_t::scoped_lock& l); void flush(std::vector::iterator i, mutex_t::scoped_lock& l); void cache_block(disk_io_job& j, mutex_t::scoped_lock& l); @@ -189,6 +191,8 @@ namespace libtorrent int m_num_cached_blocks; // in (16kB) blocks int m_cache_size; + // expiration time of cache entries in seconds + int m_cache_expiry; // memory pool for read and write operations // and disk cache diff --git a/include/libtorrent/session_settings.hpp b/include/libtorrent/session_settings.hpp index c19f0b2bb..c5ae781de 100644 --- a/include/libtorrent/session_settings.hpp +++ b/include/libtorrent/session_settings.hpp @@ -121,6 +121,7 @@ namespace libtorrent , send_buffer_watermark(80 * 1024) , auto_upload_slots(true) , cache_size(512) + , cache_expiry(60) {} // this is the user agent that will be sent to the tracker @@ -320,8 +321,13 @@ namespace libtorrent bool auto_upload_slots; // the disk write cache, specified in 16 KiB blocks. - // defaul is 512 (= 8 MB) + // default is 512 (= 8 MB) int cache_size; + + // the number of seconds a write cache entry sits + // idle in the cache before it's forcefully flushed + // to disk. Default is 60 seconds. + int cache_expiry; }; #ifndef TORRENT_DISABLE_DHT diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index 4638410e1..f0f6782ad 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -51,6 +51,7 @@ namespace libtorrent , m_queue_buffer_size(0) , m_num_cached_blocks(0) , m_cache_size(512) // 512 * 16kB = 8MB + , m_cache_expiry(60) // 1 minute , m_pool(block_size) #ifndef NDEBUG , m_block_size(block_size) @@ -146,6 +147,13 @@ namespace libtorrent m_cache_size = s; } + void disk_io_thread::set_cache_expiry(int ex) + { + mutex_t::scoped_lock l(m_mutex); + TORRENT_ASSERT(ex > 0); + m_cache_expiry = ex; + } + // aborts read operations void disk_io_thread::stop(boost::intrusive_ptr s) { @@ -210,6 +218,23 @@ namespace libtorrent return m_pieces.end(); } + void disk_io_thread::flush_expired_pieces(mutex_t::scoped_lock& l) + { + ptime now = time_now(); + + TORRENT_ASSERT(l.locked()); + for (;;) + { + std::vector::iterator i = std::min_element( + m_pieces.begin(), m_pieces.end() + , bind(&cached_piece_entry::last_write, _1) + < bind(&cached_piece_entry::last_write, _1)); + if (i == m_pieces.end()) return; + if (total_seconds(now - i->last_write) < m_cache_expiry) return; + flush_and_remove(i, l); + } + } + void disk_io_thread::flush_oldest_piece(mutex_t::scoped_lock& l) { TORRENT_ASSERT(l.locked()); @@ -234,6 +259,9 @@ namespace libtorrent TORRENT_ASSERT(l.locked()); cached_piece_entry& p = *e; int piece_size = p.storage->info()->piece_size(p.piece); +#ifdef TORRENT_DISK_STATS + m_log << log_time() << " flushing " << piece_size << std::endl; +#endif TORRENT_ASSERT(piece_size > 0); // char* buf = (char*)alloca(piece_size); std::vector temp(piece_size); @@ -425,6 +453,8 @@ namespace libtorrent disk_io_job j = m_jobs.front(); m_jobs.pop_front(); m_queue_buffer_size -= j.buffer_size; + + flush_expired_pieces(l); l.unlock(); int ret = 0; @@ -457,9 +487,6 @@ namespace libtorrent } ret = j.storage->read_impl(j.buffer, j.piece, j.offset , j.buffer_size); - - // simulates slow drives - // usleep(300); break; case disk_io_job::write: { @@ -479,9 +506,6 @@ namespace libtorrent ++m_num_cached_blocks; ++p->num_blocks; p->last_write = time_now(); -// std::cerr << " adding cache entry for p: " << j.piece -// << " block: " << block -// << " cached_blocks: " << m_num_cached_blocks << std::endl; } else { @@ -490,9 +514,6 @@ namespace libtorrent free_current_buffer = false; if (m_num_cached_blocks >= m_cache_size) flush_oldest_piece(l); - - // simulates a slow drive - // usleep(300); break; } case disk_io_job::hash: diff --git a/src/session_impl.cpp b/src/session_impl.cpp index af0327362..cc4feaa41 100755 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -811,6 +811,8 @@ namespace detail TORRENT_ASSERT(s.unchoke_interval >= 5); if (m_settings.cache_size != s.cache_size) m_disk_thread.set_cache_size(s.cache_size); + if (m_settings.cache_expiry != s.cache_expiry) + m_disk_thread.set_cache_size(s.cache_expiry); m_settings = s; m_files.resize(m_settings.file_pool_size); if (!s.auto_upload_slots) m_allowed_upload_slots = m_max_uploads;