Merge branch 'RC_1_1'
This commit is contained in:
commit
b16f43132b
|
@ -53,29 +53,6 @@ namespace libtorrent
|
|||
#endif
|
||||
};
|
||||
|
||||
struct TORRENT_EXTRA_EXPORT aligned_holder
|
||||
{
|
||||
aligned_holder(): m_buf(0) {}
|
||||
aligned_holder(int size): m_buf(page_aligned_allocator::malloc(size)) {}
|
||||
~aligned_holder() { if (m_buf) page_aligned_allocator::free(m_buf); }
|
||||
char* get() const { return m_buf; }
|
||||
void reset(char* buf = 0)
|
||||
{
|
||||
if (m_buf) page_aligned_allocator::free(m_buf);
|
||||
m_buf = buf;
|
||||
}
|
||||
void swap(aligned_holder& h)
|
||||
{
|
||||
char* tmp = m_buf;
|
||||
m_buf = h.m_buf;
|
||||
h.m_buf = tmp;
|
||||
}
|
||||
private:
|
||||
aligned_holder(aligned_holder const&);
|
||||
aligned_holder& operator=(aligned_holder const&);
|
||||
char* m_buf;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -133,10 +133,7 @@ namespace libtorrent
|
|||
|
||||
// this job is currently being performed, or it's hanging
|
||||
// on a cache piece that may be flushed soon
|
||||
in_progress = 0x20,
|
||||
|
||||
// turns into file::coalesce_buffers in the file operation
|
||||
coalesce_buffers = 0x40
|
||||
in_progress = 0x20
|
||||
};
|
||||
|
||||
// for write jobs, returns true if its block
|
||||
|
|
|
@ -271,10 +271,6 @@ namespace libtorrent
|
|||
// leaving running applications in the page cache
|
||||
no_cache = 0x40,
|
||||
|
||||
// this corresponds to Linux' O_DIRECT flag
|
||||
// and may impose alignment restrictions
|
||||
direct_io = 0x80,
|
||||
|
||||
// this is only used for readv/writev flags
|
||||
coalesce_buffers = 0x100,
|
||||
|
||||
|
|
|
@ -131,12 +131,12 @@ namespace libtorrent
|
|||
#endif
|
||||
}
|
||||
|
||||
int file_flags_for_job(disk_io_job* j)
|
||||
int file_flags_for_job(disk_io_job* j
|
||||
, bool const coalesce_buffers)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!(j->flags & disk_io_job::sequential_access)) ret |= file::random_access;
|
||||
if (j->flags & disk_io_job::coalesce_buffers) ret |= file::coalesce_buffers;
|
||||
if (coalesce_buffers) ret |= file::coalesce_buffers;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -639,6 +639,9 @@ namespace libtorrent
|
|||
DLOG("]\n");
|
||||
#endif
|
||||
|
||||
int const file_flags = m_settings.get_bool(settings_pack::coalesce_writes)
|
||||
? file::coalesce_buffers : 0;
|
||||
|
||||
// issue the actual write operation
|
||||
file::iovec_t const* iov_start = iov;
|
||||
int flushing_start = 0;
|
||||
|
@ -652,7 +655,7 @@ namespace libtorrent
|
|||
, i - flushing_start
|
||||
, piece + flushing[flushing_start] / blocks_in_piece
|
||||
, (flushing[flushing_start] % blocks_in_piece) * block_size
|
||||
, 0, error);
|
||||
, file_flags, error);
|
||||
if (ret < 0 || error) failed = true;
|
||||
iov_start = &iov[i];
|
||||
flushing_start = i;
|
||||
|
@ -1187,7 +1190,8 @@ namespace libtorrent
|
|||
|
||||
time_point start_time = clock_type::now();
|
||||
|
||||
int file_flags = file_flags_for_job(j);
|
||||
int const file_flags = file_flags_for_job(j
|
||||
, m_settings.get_bool(settings_pack::coalesce_reads));
|
||||
file::iovec_t b = { j->buffer.disk_block, size_t(j->d.io.buffer_size) };
|
||||
|
||||
int ret = j->storage->get_storage_impl()->readv(&b, 1
|
||||
|
@ -1261,7 +1265,8 @@ namespace libtorrent
|
|||
// can remove them. We can now release the cache mutex and dive into the
|
||||
// disk operations.
|
||||
|
||||
int file_flags = file_flags_for_job(j);
|
||||
int const file_flags = file_flags_for_job(j
|
||||
, m_settings.get_bool(settings_pack::coalesce_reads));
|
||||
time_point start_time = clock_type::now();
|
||||
|
||||
ret = j->storage->get_storage_impl()->readv(iov, iov_len
|
||||
|
@ -1269,7 +1274,7 @@ namespace libtorrent
|
|||
|
||||
if (!j->error.ec)
|
||||
{
|
||||
boost::uint32_t read_time = total_microseconds(clock_type::now() - start_time);
|
||||
boost::uint32_t const read_time = total_microseconds(clock_type::now() - start_time);
|
||||
m_read_time.add_sample(read_time / iov_len);
|
||||
|
||||
m_stats_counters.inc_stats_counter(counters::num_blocks_read, iov_len);
|
||||
|
@ -1418,8 +1423,9 @@ namespace libtorrent
|
|||
{
|
||||
time_point start_time = clock_type::now();
|
||||
|
||||
file::iovec_t b = { j->buffer.disk_block, size_t(j->d.io.buffer_size) };
|
||||
int file_flags = file_flags_for_job(j);
|
||||
file::iovec_t const b = { j->buffer.disk_block, size_t(j->d.io.buffer_size) };
|
||||
int const file_flags = file_flags_for_job(j
|
||||
, m_settings.get_bool(settings_pack::coalesce_writes));
|
||||
|
||||
m_stats_counters.inc_stats_counter(counters::num_writing_threads, 1);
|
||||
|
||||
|
@ -2214,7 +2220,8 @@ namespace libtorrent
|
|||
int const piece_size = j->storage->files()->piece_size(j->piece);
|
||||
int const block_size = m_disk_cache.block_size();
|
||||
int const blocks_in_piece = (piece_size + block_size - 1) / block_size;
|
||||
int const file_flags = file_flags_for_job(j);
|
||||
int const file_flags = file_flags_for_job(j
|
||||
, m_settings.get_bool(settings_pack::coalesce_reads));
|
||||
|
||||
file::iovec_t iov;
|
||||
iov.iov_base = m_disk_cache.allocate_buffer("hashing");
|
||||
|
@ -2260,7 +2267,8 @@ namespace libtorrent
|
|||
INVARIANT_CHECK;
|
||||
|
||||
int const piece_size = j->storage->files()->piece_size(j->piece);
|
||||
int const file_flags = file_flags_for_job(j);
|
||||
int const file_flags = file_flags_for_job(j
|
||||
, m_settings.get_bool(settings_pack::coalesce_reads));
|
||||
|
||||
mutex::scoped_lock l(m_cache_mutex);
|
||||
|
||||
|
@ -2594,7 +2602,8 @@ namespace libtorrent
|
|||
|| m_settings.get_bool(settings_pack::use_read_cache) == false)
|
||||
return 0;
|
||||
|
||||
int file_flags = file_flags_for_job(j);
|
||||
int const file_flags = file_flags_for_job(j
|
||||
, m_settings.get_bool(settings_pack::coalesce_reads));
|
||||
|
||||
mutex::scoped_lock l(m_cache_mutex);
|
||||
|
||||
|
|
57
src/file.cpp
57
src/file.cpp
|
@ -538,7 +538,7 @@ namespace libtorrent
|
|||
// TODO: 3 find out what error code is reported when the filesystem
|
||||
// does not support hard links.
|
||||
DWORD error = GetLastError();
|
||||
if (error != ERROR_NOT_SUPPORTED || error != ERROR_ACCESS_DENIED)
|
||||
if (error != ERROR_NOT_SUPPORTED && error != ERROR_ACCESS_DENIED)
|
||||
{
|
||||
// it's possible CreateHardLink will copy the file internally too,
|
||||
// if the filesystem does not support it.
|
||||
|
@ -1408,7 +1408,6 @@ namespace libtorrent
|
|||
DWORD flags = ((mode & random_access) ? 0 : FILE_FLAG_SEQUENTIAL_SCAN)
|
||||
| (a ? a : FILE_ATTRIBUTE_NORMAL)
|
||||
| FILE_FLAG_OVERLAPPED
|
||||
| ((mode & direct_io) ? FILE_FLAG_NO_BUFFERING : 0)
|
||||
| ((mode & no_cache) ? FILE_FLAG_WRITE_THROUGH : 0);
|
||||
|
||||
handle_type handle = CreateFile_(file_path.c_str(), m.rw_mode
|
||||
|
@ -1456,16 +1455,13 @@ namespace libtorrent
|
|||
#ifdef O_NOATIME
|
||||
| ((mode & no_atime) ? O_NOATIME : 0)
|
||||
#endif
|
||||
#ifdef O_DIRECT
|
||||
| ((mode & direct_io) ? O_DIRECT : 0)
|
||||
#endif
|
||||
#ifdef O_SYNC
|
||||
| ((mode & no_cache) ? O_SYNC: 0)
|
||||
#endif
|
||||
;
|
||||
|
||||
handle_type handle = ::open(convert_to_native(path).c_str()
|
||||
, mode_array[mode & rw_mask] | open_mode
|
||||
handle_type handle = ::open(convert_to_native(path).c_str()
|
||||
, mode_array[mode & rw_mask] | open_mode
|
||||
, permissions);
|
||||
|
||||
#ifdef O_NOATIME
|
||||
|
@ -1668,12 +1664,11 @@ typedef struct _FILE_ALLOCATED_RANGE_BUFFER {
|
|||
}
|
||||
|
||||
#if !TORRENT_USE_PREADV
|
||||
bool coalesce_read_buffers(file::iovec_t const*& bufs, int& num_bufs, file::iovec_t* tmp)
|
||||
bool coalesce_read_buffers(file::iovec_t const*& bufs, int& num_bufs
|
||||
, file::iovec_t* tmp)
|
||||
{
|
||||
int buf_size = bufs_size(bufs, num_bufs);
|
||||
// this is page aligned since it's used in APIs which
|
||||
// are likely to require that (depending on OS)
|
||||
char* buf = static_cast<char*>(page_aligned_allocator::malloc(buf_size));
|
||||
int const buf_size = bufs_size(bufs, num_bufs);
|
||||
char* buf = static_cast<char*>(malloc(buf_size));
|
||||
if (!buf) return false;
|
||||
tmp->iov_base = buf;
|
||||
tmp->iov_len = buf_size;
|
||||
|
@ -1682,20 +1677,18 @@ typedef struct _FILE_ALLOCATED_RANGE_BUFFER {
|
|||
return true;
|
||||
}
|
||||
|
||||
void coalesce_read_buffers_end(file::iovec_t const* bufs, int num_bufs, char* buf, bool copy)
|
||||
void coalesce_read_buffers_end(file::iovec_t const* bufs, int const num_bufs
|
||||
, char* const buf, bool const copy)
|
||||
{
|
||||
if (copy) scatter_copy(bufs, num_bufs, buf);
|
||||
page_aligned_allocator::free(buf);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
bool coalesce_write_buffers(file::iovec_t const*& bufs, int& num_bufs, file::iovec_t* tmp)
|
||||
bool coalesce_write_buffers(file::iovec_t const*& bufs, int& num_bufs
|
||||
, file::iovec_t* tmp)
|
||||
{
|
||||
// coalesce buffers means allocate a temporary buffer and
|
||||
// issue a single write operation instead of using a vector
|
||||
// operation
|
||||
int buf_size = 0;
|
||||
for (int i = 0; i < num_bufs; ++i) buf_size += bufs[i].iov_len;
|
||||
char* buf = static_cast<char*>(page_aligned_allocator::malloc(buf_size));
|
||||
int const buf_size = bufs_size(bufs, num_bufs);
|
||||
char* buf = static_cast<char*>(malloc(buf_size));
|
||||
if (!buf) return false;
|
||||
gather_copy(bufs, num_bufs, buf);
|
||||
tmp->iov_base = buf;
|
||||
|
@ -1834,8 +1827,16 @@ typedef struct _FILE_ALLOCATED_RANGE_BUFFER {
|
|||
int ret = iov(&::preadv, native_handle(), file_offset, bufs, num_bufs, ec);
|
||||
#else
|
||||
|
||||
// there's no point in coalescing single buffer writes
|
||||
if (num_bufs == 1)
|
||||
{
|
||||
flags &= ~file::coalesce_buffers;
|
||||
}
|
||||
|
||||
file::iovec_t tmp;
|
||||
if (flags & file::coalesce_buffers)
|
||||
file::iovec_t const* const orig_bufs = bufs;
|
||||
int const orig_num_bufs = num_bufs;
|
||||
if ((flags & file::coalesce_buffers))
|
||||
{
|
||||
if (!coalesce_read_buffers(bufs, num_bufs, &tmp))
|
||||
// ok, that failed, don't coalesce this read
|
||||
|
@ -1848,8 +1849,8 @@ typedef struct _FILE_ALLOCATED_RANGE_BUFFER {
|
|||
int ret = iov(&::read, native_handle(), file_offset, bufs, num_bufs, ec);
|
||||
#endif
|
||||
|
||||
if (flags & file::coalesce_buffers)
|
||||
coalesce_read_buffers_end(bufs, num_bufs
|
||||
if ((flags & file::coalesce_buffers))
|
||||
coalesce_read_buffers_end(orig_bufs, orig_num_bufs
|
||||
, static_cast<char*>(tmp.iov_base), !ec);
|
||||
|
||||
#endif
|
||||
|
@ -1884,6 +1885,12 @@ typedef struct _FILE_ALLOCATED_RANGE_BUFFER {
|
|||
int ret = iov(&::pwritev, native_handle(), file_offset, bufs, num_bufs, ec);
|
||||
#else
|
||||
|
||||
// there's no point in coalescing single buffer writes
|
||||
if (num_bufs == 1)
|
||||
{
|
||||
flags &= ~file::coalesce_buffers;
|
||||
}
|
||||
|
||||
file::iovec_t tmp;
|
||||
if (flags & file::coalesce_buffers)
|
||||
{
|
||||
|
@ -2243,7 +2250,7 @@ typedef struct _FILE_ALLOCATED_RANGE_BUFFER {
|
|||
|
||||
// return the offset to the next allocated region
|
||||
return buffer.FileOffset.QuadPart;
|
||||
|
||||
|
||||
#elif defined SEEK_DATA
|
||||
// this is supported on solaris
|
||||
boost::int64_t ret = lseek(native_handle(), start, SEEK_DATA);
|
||||
|
|
|
@ -2212,6 +2212,9 @@ namespace libtorrent
|
|||
m_counters.inc_stats_counter(counters::piece_requests);
|
||||
|
||||
#ifndef TORRENT_DISABLE_LOGGING
|
||||
const bool valid_piece_index
|
||||
= r.piece >= 0 && r.piece < int(t->torrent_file().num_pieces());
|
||||
|
||||
peer_log(peer_log_alert::incoming_message, "REQUEST"
|
||||
, "piece: %d s: %x l: %x", r.piece, r.start, r.length);
|
||||
#endif
|
||||
|
@ -2222,9 +2225,6 @@ namespace libtorrent
|
|||
m_counters.inc_stats_counter(counters::invalid_piece_requests);
|
||||
++m_num_invalid_requests;
|
||||
#ifndef TORRENT_DISABLE_LOGGING
|
||||
const bool valid_piece_index
|
||||
= r.piece >= 0 && r.piece < int(t->torrent_file().num_pieces());
|
||||
|
||||
peer_log(peer_log_alert::info, "INVALID_REQUEST", "piece not superseeded "
|
||||
"i: %d t: %d n: %d h: %d ss1: %d ss2: %d"
|
||||
, m_peer_interested
|
||||
|
@ -2306,7 +2306,8 @@ namespace libtorrent
|
|||
#ifndef TORRENT_DISABLE_LOGGING
|
||||
peer_log(peer_log_alert::info, "INVALID_REQUEST", "peer is not interested "
|
||||
" t: %d n: %d block_limit: %d"
|
||||
, int(t->torrent_file().piece_size(r.piece))
|
||||
, valid_piece_index
|
||||
? int(t->torrent_file().piece_size(r.piece)) : -1
|
||||
, t->torrent_file().num_pieces()
|
||||
, t->block_size());
|
||||
peer_log(peer_log_alert::info, "INTERESTED", "artificial incoming INTERESTED message");
|
||||
|
@ -2346,7 +2347,8 @@ namespace libtorrent
|
|||
peer_log(peer_log_alert::info, "INVALID_REQUEST"
|
||||
, "i: %d t: %d n: %d h: %d block_limit: %d"
|
||||
, m_peer_interested
|
||||
, int(t->torrent_file().piece_size(r.piece))
|
||||
, valid_piece_index
|
||||
? int(t->torrent_file().piece_size(r.piece)) : -1
|
||||
, t->torrent_file().num_pieces()
|
||||
, t->has_piece_passed(r.piece)
|
||||
, t->block_size());
|
||||
|
|
|
@ -230,7 +230,9 @@ namespace libtorrent
|
|||
, m_flags(flags)
|
||||
{}
|
||||
|
||||
int file_op(int file_index, boost::int64_t file_offset, int size
|
||||
int file_op(int const file_index
|
||||
, boost::int64_t const file_offset
|
||||
, int const size
|
||||
, file::iovec_t const* bufs, storage_error& ec)
|
||||
TORRENT_OVERRIDE TORRENT_FINAL
|
||||
{
|
||||
|
@ -314,12 +316,14 @@ namespace libtorrent
|
|||
|
||||
struct read_fileop : fileop
|
||||
{
|
||||
read_fileop(default_storage& st, int flags)
|
||||
read_fileop(default_storage& st, int const flags)
|
||||
: m_storage(st)
|
||||
, m_flags(flags)
|
||||
{}
|
||||
|
||||
int file_op(int file_index, boost::int64_t file_offset, int size
|
||||
int file_op(int const file_index
|
||||
, boost::int64_t const file_offset
|
||||
, int const size
|
||||
, file::iovec_t const* bufs, storage_error& ec)
|
||||
TORRENT_OVERRIDE TORRENT_FINAL
|
||||
{
|
||||
|
@ -396,7 +400,7 @@ namespace libtorrent
|
|||
|
||||
private:
|
||||
default_storage& m_storage;
|
||||
int m_flags;
|
||||
int const m_flags;
|
||||
};
|
||||
|
||||
default_storage::default_storage(storage_params const& params)
|
||||
|
|
|
@ -360,3 +360,35 @@ TORRENT_TEST(hard_link)
|
|||
fprintf(stderr, "remove failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
|
||||
}
|
||||
|
||||
TORRENT_TEST(coalesce_buffer)
|
||||
{
|
||||
error_code ec;
|
||||
file f;
|
||||
TEST_CHECK(f.open("test_file", file::read_write, ec));
|
||||
if (ec)
|
||||
fprintf(stderr, "open failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
|
||||
TEST_EQUAL(ec, error_code());
|
||||
if (ec) fprintf(stderr, "%s\n", ec.message().c_str());
|
||||
file::iovec_t b[2] = {{(void*)"test", 4}, {(void*)"foobar", 6}};
|
||||
TEST_EQUAL(f.writev(0, b, 2, ec, file::coalesce_buffers), 4 + 6);
|
||||
if (ec)
|
||||
fprintf(stderr, "writev failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
|
||||
TEST_CHECK(!ec);
|
||||
char test_buf1[5] = {0};
|
||||
char test_buf2[7] = {0};
|
||||
b[0].iov_base = test_buf1;
|
||||
b[0].iov_len = 4;
|
||||
b[1].iov_base = test_buf2;
|
||||
b[1].iov_len = 6;
|
||||
TEST_EQUAL(f.readv(0, b, 2, ec), 4 + 6);
|
||||
if (ec)
|
||||
{
|
||||
fprintf(stderr, "readv failed: [%s] %s\n"
|
||||
, ec.category().name(), ec.message().c_str());
|
||||
}
|
||||
TEST_EQUAL(ec, error_code());
|
||||
TEST_CHECK(strcmp(test_buf1, "test") == 0);
|
||||
TEST_CHECK(strcmp(test_buf2, "foobar") == 0);
|
||||
f.close();
|
||||
}
|
||||
|
||||
|
|
|
@ -171,7 +171,7 @@ typedef boost::shared_array<char> buf_ptr;
|
|||
|
||||
buf_ptr new_piece(int size)
|
||||
{
|
||||
buf_ptr ret(page_aligned_allocator::malloc(size), &page_aligned_allocator::free);
|
||||
buf_ptr ret(static_cast<char*>(malloc(size)), &free);
|
||||
std::generate(ret.get(), ret.get() + size, random_byte);
|
||||
return ret;
|
||||
}
|
||||
|
@ -211,7 +211,7 @@ void run_storage_tests(boost::shared_ptr<torrent_info> info
|
|||
, unbuffered ? settings_pack::disable_os_cache
|
||||
: settings_pack::enable_os_cache);
|
||||
|
||||
char* piece = page_aligned_allocator::malloc(piece_size);
|
||||
char* piece = static_cast<char*>(malloc(piece_size));
|
||||
|
||||
{ // avoid having two storages use the same files
|
||||
file_pool fp;
|
||||
|
@ -292,7 +292,7 @@ void run_storage_tests(boost::shared_ptr<torrent_info> info
|
|||
s->release_files(ec);
|
||||
}
|
||||
|
||||
page_aligned_allocator::free(piece);
|
||||
free(piece);
|
||||
}
|
||||
|
||||
void test_remove(std::string const& test_path, bool unbuffered)
|
||||
|
|
|
@ -228,7 +228,7 @@ void test_transfer(int proxy_type, settings_pack const& sett
|
|||
|
||||
create_directory("tmp1_transfer", ec);
|
||||
std::ofstream file("tmp1_transfer/temporary");
|
||||
boost::shared_ptr<torrent_info> t = ::create_torrent(&file, "temporary", 16 * 1024, 13, false);
|
||||
boost::shared_ptr<torrent_info> t = ::create_torrent(&file, "temporary", 32 * 1024, 13, false);
|
||||
file.close();
|
||||
|
||||
TEST_CHECK(exists(combine_path("tmp1_transfer", "temporary")));
|
||||
|
@ -421,6 +421,30 @@ TORRENT_TEST(allow_fast)
|
|||
cleanup();
|
||||
}
|
||||
|
||||
TORRENT_TEST(coalesce_reads)
|
||||
{
|
||||
using namespace libtorrent;
|
||||
// test allowed fast
|
||||
settings_pack p;
|
||||
p.set_int(settings_pack::read_cache_line_size, 16);
|
||||
p.set_bool(settings_pack::coalesce_reads, true);
|
||||
test_transfer(0, p, false);
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
TORRENT_TEST(coalesce_writes)
|
||||
{
|
||||
using namespace libtorrent;
|
||||
// test allowed fast
|
||||
settings_pack p;
|
||||
p.set_bool(settings_pack::coalesce_writes, true);
|
||||
test_transfer(0, p, false);
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
|
||||
TORRENT_TEST(allocate)
|
||||
{
|
||||
using namespace libtorrent;
|
||||
|
|
Loading…
Reference in New Issue