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.
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;