first pass of replacing coalesce writes and reads by writev and readv (no windows support yet)
This commit is contained in:
parent
b48049bb90
commit
f1d229aae6
@ -1,6 +1,7 @@
|
||||
nobase_include_HEADERS = libtorrent/alert.hpp \
|
||||
libtorrent/alert_types.hpp \
|
||||
libtorrent/assert.hpp \
|
||||
libtorrent/alloca.hpp \
|
||||
libtorrent/bandwidth_manager.hpp \
|
||||
libtorrent/bandwidth_limit.hpp \
|
||||
libtorrent/bandwidth_queue_entry.hpp \
|
||||
|
51
include/libtorrent/alloca.hpp
Normal file
51
include/libtorrent/alloca.hpp
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2008, Arvid Norberg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TORRENT_ALLOCA
|
||||
|
||||
#include "libtorrent/config.hpp"
|
||||
|
||||
#ifdef TORRENT_WINDOWS
|
||||
|
||||
#include <malloc.h>
|
||||
#define TORRENT_ALLOCA(t, n) static_cast<t*>(_alloca(sizeof(t) * n));
|
||||
|
||||
#else
|
||||
|
||||
#include <alloca.h>
|
||||
#define TORRENT_ALLOCA(t, n) static_cast<t*>(alloca(sizeof(t) * n));
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -58,6 +58,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "libtorrent/hasher.hpp"
|
||||
#include "libtorrent/config.hpp"
|
||||
#include "libtorrent/buffer.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
@ -123,6 +124,9 @@ namespace libtorrent
|
||||
// false return value indicates an error
|
||||
virtual bool initialize(bool allocate_files) = 0;
|
||||
|
||||
virtual int readv(file::iovec_t* bufs, int slot, int offset, int num_bufs);
|
||||
virtual int writev(file::iovec_t* buf, int slot, int offset, int num_bufs);
|
||||
|
||||
// negative return value indicates an error
|
||||
virtual int read(char* buf, int slot, int offset, int size) = 0;
|
||||
|
||||
@ -305,16 +309,16 @@ namespace libtorrent
|
||||
bool allocate_slots(int num_slots, bool abort_on_disk = false);
|
||||
|
||||
int read_impl(
|
||||
char* buf
|
||||
file::iovec_t* bufs
|
||||
, int piece_index
|
||||
, int offset
|
||||
, int size);
|
||||
, int num_bufs);
|
||||
|
||||
int write_impl(
|
||||
const char* buf
|
||||
file::iovec_t* bufs
|
||||
, int piece_index
|
||||
, int offset
|
||||
, int size);
|
||||
, int num_bufs);
|
||||
|
||||
// -1=error 0=ok 1=skip
|
||||
int check_one_piece(int& have_piece);
|
||||
|
@ -32,6 +32,7 @@ noinst_HEADERS = \
|
||||
$(top_srcdir)/include/libtorrent/alert.hpp \
|
||||
$(top_srcdir)/include/libtorrent/alert_types.hpp \
|
||||
$(top_srcdir)/include/libtorrent/assert.hpp \
|
||||
$(top_srcdir)/include/libtorrent/alloca.hpp \
|
||||
$(top_srcdir)/include/libtorrent/aux_/session_impl.hpp \
|
||||
$(top_srcdir)/include/libtorrent/bandwidth_manager.hpp \
|
||||
$(top_srcdir)/include/libtorrent/bandwidth_limit.hpp \
|
||||
|
@ -55,8 +55,17 @@ namespace libtorrent
|
||||
, m_queue_buffer_size(0)
|
||||
, m_cache_size(512) // 512 * 16kB = 8MB
|
||||
, m_cache_expiry(60) // 1 minute
|
||||
// the file class doesn't support proper writev
|
||||
// and readv on windows, so it's more efficient
|
||||
// to coalesce reads and writes into a bigger
|
||||
// buffer first
|
||||
#ifdef TORRENT_WINDOWS
|
||||
, m_coalesce_writes(true)
|
||||
, m_coalesce_reads(true)
|
||||
#else
|
||||
, m_coalesce_writes(false)
|
||||
, m_coalesce_reads(false)
|
||||
#endif
|
||||
, m_use_read_cache(true)
|
||||
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
|
||||
, m_pool(block_size)
|
||||
@ -322,29 +331,47 @@ namespace libtorrent
|
||||
, mutex_t::scoped_lock& l)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
// TODO: copy *e and unlink it before unlocking
|
||||
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);
|
||||
boost::scoped_array<char> buf;
|
||||
if (m_coalesce_writes) buf.reset(new (std::nothrow) char[piece_size]);
|
||||
|
||||
int blocks_in_piece = (piece_size + m_block_size - 1) / m_block_size;
|
||||
int buffer_size = 0;
|
||||
int offset = 0;
|
||||
|
||||
boost::scoped_array<char> buf;
|
||||
boost::scoped_array<file::iovec_t> iov;
|
||||
int iov_counter = 0;
|
||||
if (m_coalesce_writes) buf.reset(new (std::nothrow) char[piece_size]);
|
||||
// TOOD: replace with alloca
|
||||
else iov.reset(new file::iovec_t[blocks_in_piece]);
|
||||
|
||||
for (int i = 0; i <= blocks_in_piece; ++i)
|
||||
{
|
||||
if (i == blocks_in_piece || p.blocks[i] == 0)
|
||||
{
|
||||
if (buffer_size == 0) continue;
|
||||
TORRENT_ASSERT(buf);
|
||||
|
||||
TORRENT_ASSERT(buffer_size <= i * m_block_size);
|
||||
l.unlock();
|
||||
p.storage->write_impl(buf.get(), p.piece, (std::min)(
|
||||
i * m_block_size, piece_size) - buffer_size, buffer_size);
|
||||
if (iov)
|
||||
{
|
||||
TORRENT_ASSERT(iov);
|
||||
p.storage->write_impl(iov.get(), p.piece, (std::min)(
|
||||
i * m_block_size, piece_size) - buffer_size, iov_counter);
|
||||
iov_counter = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
TORRENT_ASSERT(buf);
|
||||
file::iovec_t b = { buf.get(), buffer_size };
|
||||
p.storage->write_impl(&b, p.piece, (std::min)(
|
||||
i * m_block_size, piece_size) - buffer_size, 1);
|
||||
}
|
||||
l.lock();
|
||||
++m_cache_stats.writes;
|
||||
// std::cerr << " flushing p: " << p.piece << " bytes: " << buffer_size << std::endl;
|
||||
@ -357,24 +384,29 @@ namespace libtorrent
|
||||
TORRENT_ASSERT(offset + block_size > 0);
|
||||
if (!buf)
|
||||
{
|
||||
l.unlock();
|
||||
p.storage->write_impl(p.blocks[i], p.piece, i * m_block_size, block_size);
|
||||
l.lock();
|
||||
++m_cache_stats.writes;
|
||||
iov[iov_counter].iov_base = p.blocks[i];
|
||||
iov[iov_counter].iov_len = block_size;
|
||||
++iov_counter;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::memcpy(buf.get() + offset, p.blocks[i], block_size);
|
||||
offset += m_block_size;
|
||||
buffer_size += block_size;
|
||||
}
|
||||
free_buffer(p.blocks[i]);
|
||||
p.blocks[i] = 0;
|
||||
buffer_size += block_size;
|
||||
TORRENT_ASSERT(p.num_blocks > 0);
|
||||
--p.num_blocks;
|
||||
++m_cache_stats.blocks_written;
|
||||
--m_cache_stats.cache_size;
|
||||
}
|
||||
|
||||
for (int i = 0; i < blocks_in_piece; ++i)
|
||||
{
|
||||
if (p.blocks[i] == 0) continue;
|
||||
free_buffer(p.blocks[i]);
|
||||
p.blocks[i] = 0;
|
||||
}
|
||||
|
||||
TORRENT_ASSERT(buffer_size == 0);
|
||||
// std::cerr << " flushing p: " << p.piece << " cached_blocks: " << m_cache_stats.cache_size << std::endl;
|
||||
#ifdef TORRENT_DEBUG
|
||||
@ -439,12 +471,17 @@ namespace libtorrent
|
||||
TORRENT_ASSERT(buffer_size <= piece_size);
|
||||
TORRENT_ASSERT(buffer_size + start_block * m_block_size <= piece_size);
|
||||
boost::scoped_array<char> buf;
|
||||
boost::scoped_array<file::iovec_t> iov;
|
||||
int iov_counter = 0;
|
||||
if (m_coalesce_reads) buf.reset(new (std::nothrow) char[buffer_size]);
|
||||
else iov.reset(new file::iovec_t[end_block - start_block]);
|
||||
|
||||
int ret = 0;
|
||||
if (buf)
|
||||
{
|
||||
l.unlock();
|
||||
ret += p.storage->read_impl(buf.get(), p.piece, start_block * m_block_size, buffer_size);
|
||||
file::iovec_t b = { buf.get(), buffer_size };
|
||||
ret += p.storage->read_impl(&b, p.piece, start_block * m_block_size, 1);
|
||||
l.lock();
|
||||
if (p.storage->error()) { return -1; }
|
||||
++m_cache_stats.reads;
|
||||
@ -465,15 +502,23 @@ namespace libtorrent
|
||||
}
|
||||
else
|
||||
{
|
||||
l.unlock();
|
||||
ret += p.storage->read_impl(p.blocks[i], p.piece, piece_offset, block_size);
|
||||
if (p.storage->error()) { return -1; }
|
||||
l.lock();
|
||||
++m_cache_stats.reads;
|
||||
iov[iov_counter].iov_base = p.blocks[i];
|
||||
iov[iov_counter].iov_len = block_size;
|
||||
++iov_counter;
|
||||
}
|
||||
offset += m_block_size;
|
||||
piece_offset += m_block_size;
|
||||
}
|
||||
|
||||
if (iov)
|
||||
{
|
||||
l.unlock();
|
||||
ret += p.storage->read_impl(iov.get(), p.piece, start_block * m_block_size, iov_counter);
|
||||
l.lock();
|
||||
if (p.storage->error()) { return -1; }
|
||||
++m_cache_stats.reads;
|
||||
}
|
||||
|
||||
TORRENT_ASSERT(ret <= buffer_size);
|
||||
return (ret != buffer_size) ? -1 : ret;
|
||||
}
|
||||
@ -913,8 +958,8 @@ namespace libtorrent
|
||||
}
|
||||
else if (ret == -2)
|
||||
{
|
||||
ret = j.storage->read_impl(j.buffer, j.piece, j.offset
|
||||
, j.buffer_size);
|
||||
file::iovec_t b = { j.buffer, j.buffer_size };
|
||||
ret = j.storage->read_impl(&b, j.piece, j.offset, 1);
|
||||
if (ret < 0)
|
||||
{
|
||||
test_error(j);
|
||||
@ -1182,7 +1227,8 @@ namespace libtorrent
|
||||
}
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
} catch (std::exception& e)
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
ret = -1;
|
||||
try
|
||||
|
@ -244,8 +244,9 @@ namespace libtorrent
|
||||
TORRENT_ASSERT(is_open());
|
||||
|
||||
#ifdef TORRENT_WINDOWS
|
||||
// TODO: Replace with ReadFileScatter if possible
|
||||
size_type ret = 0;
|
||||
for (iovec_t* i = bufs, end(bufs + num_bufs); i < end; ++i)
|
||||
for (iovec_t const* i = bufs, *end(bufs + num_bufs); i < end; ++i)
|
||||
{
|
||||
if (i->iov_len <= 0) continue;
|
||||
DWORD intermediate = 0;
|
||||
@ -271,8 +272,9 @@ namespace libtorrent
|
||||
TORRENT_ASSERT(is_open());
|
||||
|
||||
#ifdef TORRENT_WINDOWS
|
||||
// Replace by WriteFileGather if possible
|
||||
size_type ret = 0;
|
||||
for (iovec_* i = bufs, end(bufs + num_bufs); i < end; ++i)
|
||||
for (iovec_t const* i = bufs, *end(bufs + num_bufs); i < end; ++i)
|
||||
{
|
||||
if (i->iov_len <= 0) continue;
|
||||
DWORD intermediate = 0;
|
||||
|
263
src/storage.cpp
263
src/storage.cpp
@ -50,9 +50,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/multi_index/ordered_index.hpp>
|
||||
#include <boost/scoped_array.hpp>
|
||||
#if BOOST_VERSION >= 103500
|
||||
#include <boost/system/system_error.hpp>
|
||||
#endif
|
||||
@ -72,6 +70,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "libtorrent/file_pool.hpp"
|
||||
#include "libtorrent/aux_/session_impl.hpp"
|
||||
#include "libtorrent/disk_buffer_holder.hpp"
|
||||
#include "libtorrent/alloca.hpp"
|
||||
|
||||
//#define TORRENT_PARTIAL_HASH_LOG
|
||||
|
||||
@ -315,6 +314,86 @@ namespace libtorrent
|
||||
return true;
|
||||
}
|
||||
|
||||
// for backwards compatibility, let the default readv and
|
||||
// writev implementations be implemented in terms of the
|
||||
// old read and write
|
||||
int storage_interface::readv(file::iovec_t* bufs
|
||||
, int slot, int offset, int num_bufs)
|
||||
{
|
||||
int ret = 0;
|
||||
for (file::iovec_t const* i = bufs, *end(bufs + num_bufs); i < end; ++i)
|
||||
{
|
||||
int r = write((char const*)i->iov_base, slot, offset, i->iov_len);
|
||||
offset += i->iov_len;
|
||||
if (r == -1) return -1;
|
||||
ret += r;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int storage_interface::writev(file::iovec_t* bufs, int slot
|
||||
, int offset, int num_bufs)
|
||||
{
|
||||
int ret = 0;
|
||||
for (file::iovec_t const* i = bufs, *end(bufs + num_bufs); i < end; ++i)
|
||||
{
|
||||
int r = read((char*)i->iov_base, slot, offset, i->iov_len);
|
||||
offset += i->iov_len;
|
||||
if (r == -1) return -1;
|
||||
ret += r;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int copy_bufs(file::iovec_t const* bufs, int bytes, file::iovec_t* target)
|
||||
{
|
||||
int size = 0;
|
||||
int ret = 1;
|
||||
for (;;)
|
||||
{
|
||||
*target = *bufs;
|
||||
size += bufs->iov_len;
|
||||
if (size >= bytes)
|
||||
{
|
||||
target->iov_len -= size - bytes;
|
||||
return ret;
|
||||
}
|
||||
++bufs;
|
||||
++target;
|
||||
++ret;
|
||||
}
|
||||
}
|
||||
|
||||
void advance_bufs(file::iovec_t*& bufs, int bytes)
|
||||
{
|
||||
int size = 0;
|
||||
for (;;)
|
||||
{
|
||||
size += bufs->iov_len;
|
||||
if (size >= bytes)
|
||||
{
|
||||
((char*&)bufs->iov_base) += bufs->iov_len - (size - bytes);
|
||||
bufs->iov_len = size - bytes;
|
||||
return;
|
||||
}
|
||||
++bufs;
|
||||
}
|
||||
}
|
||||
|
||||
int bufs_size(file::iovec_t *bufs, int num_bufs)
|
||||
{
|
||||
int size = 0;
|
||||
for (file::iovec_t* i = bufs, *end(bufs + num_bufs); i < end; ++i)
|
||||
size += i->iov_len;
|
||||
return size;
|
||||
}
|
||||
|
||||
void clear_bufs(file::iovec_t *bufs, int num_bufs)
|
||||
{
|
||||
for (file::iovec_t* i = bufs, *end(bufs + num_bufs); i < end; ++i)
|
||||
std::memset(i->iov_base, 0, i->iov_len);
|
||||
}
|
||||
|
||||
class storage : public storage_interface, boost::noncopyable
|
||||
{
|
||||
public:
|
||||
@ -333,7 +412,9 @@ namespace libtorrent
|
||||
bool initialize(bool allocate_files);
|
||||
bool move_storage(fs::path save_path);
|
||||
int read(char* buf, int slot, int offset, int size);
|
||||
int write(const char* buf, int slot, int offset, int size);
|
||||
int write(char const* buf, int slot, int offset, int size);
|
||||
int readv(file::iovec_t* bufs, int slot, int offset, int num_bufs);
|
||||
int writev(file::iovec_t* buf, int slot, int offset, int num_bufs);
|
||||
bool move_slot(int src_slot, int dst_slot);
|
||||
bool swap_slots(int slot1, int slot2);
|
||||
bool swap_slots3(int slot1, int slot2, int slot3);
|
||||
@ -341,8 +422,6 @@ namespace libtorrent
|
||||
bool write_resume_data(entry& rd) const;
|
||||
sha1_hash hash_for_slot(int slot, partial_hash& ph, int piece_size);
|
||||
|
||||
int read_impl(char* buf, int slot, int offset, int size, bool fill_zero);
|
||||
|
||||
~storage()
|
||||
{ m_pool.release(this); }
|
||||
|
||||
@ -370,7 +449,7 @@ namespace libtorrent
|
||||
hasher whole;
|
||||
int slot_size1 = piece_size;
|
||||
m_scratch_buffer.resize(slot_size1);
|
||||
read_impl(&m_scratch_buffer[0], slot, 0, slot_size1, false);
|
||||
read(&m_scratch_buffer[0], slot, 0, slot_size1);
|
||||
if (error()) return sha1_hash(0);
|
||||
if (ph.offset > 0)
|
||||
partial.update(&m_scratch_buffer[0], ph.offset);
|
||||
@ -382,7 +461,7 @@ namespace libtorrent
|
||||
if (slot_size > 0)
|
||||
{
|
||||
m_scratch_buffer.resize(slot_size);
|
||||
read_impl(&m_scratch_buffer[0], slot, ph.offset, slot_size, false);
|
||||
read(&m_scratch_buffer[0], slot, ph.offset, slot_size);
|
||||
if (error()) return sha1_hash(0);
|
||||
ph.h.update(&m_scratch_buffer[0], slot_size);
|
||||
}
|
||||
@ -836,9 +915,11 @@ namespace libtorrent
|
||||
{
|
||||
int piece_size = m_files.piece_size(dst_slot);
|
||||
m_scratch_buffer.resize(piece_size);
|
||||
int ret1 = read_impl(&m_scratch_buffer[0], src_slot, 0, piece_size, true);
|
||||
int ret2 = write(&m_scratch_buffer[0], dst_slot, 0, piece_size);
|
||||
return ret1 != piece_size || ret2 != piece_size;
|
||||
int ret = read(&m_scratch_buffer[0], src_slot, 0, piece_size);
|
||||
if (ret != piece_size) return true;
|
||||
ret = write(&m_scratch_buffer[0], dst_slot, 0, piece_size);
|
||||
if (ret != piece_size) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool storage::swap_slots(int slot1, int slot2)
|
||||
@ -848,12 +929,15 @@ namespace libtorrent
|
||||
int piece1_size = m_files.piece_size(slot2);
|
||||
int piece2_size = m_files.piece_size(slot1);
|
||||
m_scratch_buffer.resize(piece_size * 2);
|
||||
int ret1 = read_impl(&m_scratch_buffer[0], slot1, 0, piece1_size, true);
|
||||
int ret2 = read_impl(&m_scratch_buffer[piece_size], slot2, 0, piece2_size, true);
|
||||
int ret3 = write(&m_scratch_buffer[0], slot2, 0, piece1_size);
|
||||
int ret4 = write(&m_scratch_buffer[piece_size], slot1, 0, piece2_size);
|
||||
return ret1 != piece1_size || ret2 != piece2_size
|
||||
|| ret3 != piece1_size || ret4 != piece2_size;
|
||||
int ret = read(&m_scratch_buffer[0], slot1, 0, piece1_size);
|
||||
if (ret != piece1_size) return true;
|
||||
ret = read(&m_scratch_buffer[piece_size], slot2, 0, piece2_size);
|
||||
if (ret != piece2_size) return true;
|
||||
ret = write(&m_scratch_buffer[0], slot2, 0, piece1_size);
|
||||
if (ret != piece1_size) return true;
|
||||
ret = write(&m_scratch_buffer[piece_size], slot1, 0, piece2_size);
|
||||
if (ret != piece2_size) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool storage::swap_slots3(int slot1, int slot2, int slot3)
|
||||
@ -864,37 +948,36 @@ namespace libtorrent
|
||||
int piece2_size = m_files.piece_size(slot3);
|
||||
int piece3_size = m_files.piece_size(slot1);
|
||||
m_scratch_buffer.resize(piece_size * 2);
|
||||
int ret1 = read_impl(&m_scratch_buffer[0], slot1, 0, piece1_size, true);
|
||||
int ret2 = read_impl(&m_scratch_buffer[piece_size], slot2, 0, piece2_size, true);
|
||||
int ret3 = write(&m_scratch_buffer[0], slot2, 0, piece1_size);
|
||||
int ret4 = read_impl(&m_scratch_buffer[0], slot3, 0, piece3_size, true);
|
||||
int ret5 = write(&m_scratch_buffer[piece_size], slot3, 0, piece2_size);
|
||||
int ret6 = write(&m_scratch_buffer[0], slot1, 0, piece3_size);
|
||||
return ret1 != piece1_size || ret2 != piece2_size
|
||||
|| ret3 != piece1_size || ret4 != piece3_size
|
||||
|| ret5 != piece2_size || ret6 != piece3_size;
|
||||
int ret = 0;
|
||||
ret = read(&m_scratch_buffer[0], slot1, 0, piece1_size);
|
||||
if (ret != piece1_size) return true;
|
||||
ret = read(&m_scratch_buffer[piece_size], slot2, 0, piece2_size);
|
||||
if (ret != piece2_size) return true;
|
||||
ret = write(&m_scratch_buffer[0], slot2, 0, piece1_size);
|
||||
if (ret != piece1_size) return true;
|
||||
ret = read(&m_scratch_buffer[0], slot3, 0, piece3_size);
|
||||
if (ret != piece3_size) return true;
|
||||
ret = write(&m_scratch_buffer[piece_size], slot3, 0, piece2_size);
|
||||
if (ret != piece2_size) return true;
|
||||
ret = write(&m_scratch_buffer[0], slot1, 0, piece3_size);
|
||||
if (ret != piece3_size) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int storage::read(
|
||||
char* buf
|
||||
int storage::readv(
|
||||
file::iovec_t* bufs
|
||||
, int slot
|
||||
, int offset
|
||||
, int size)
|
||||
, int num_bufs)
|
||||
{
|
||||
return read_impl(buf, slot, offset, size, false);
|
||||
}
|
||||
|
||||
int storage::read_impl(
|
||||
char* buf
|
||||
, int slot
|
||||
, int offset
|
||||
, int size
|
||||
, bool fill_zero)
|
||||
{
|
||||
TORRENT_ASSERT(buf != 0);
|
||||
TORRENT_ASSERT(bufs != 0);
|
||||
TORRENT_ASSERT(slot >= 0 && slot < m_files.num_pieces());
|
||||
TORRENT_ASSERT(offset >= 0);
|
||||
TORRENT_ASSERT(offset < m_files.piece_size(slot));
|
||||
TORRENT_ASSERT(num_bufs > 0);
|
||||
|
||||
int size = bufs_size(bufs, num_bufs);
|
||||
|
||||
TORRENT_ASSERT(size > 0);
|
||||
|
||||
#ifdef TORRENT_DEBUG
|
||||
@ -933,11 +1016,13 @@ namespace libtorrent
|
||||
TORRENT_ASSERT(left_to_read >= 0);
|
||||
|
||||
size_type result = left_to_read;
|
||||
TORRENT_ASSERT(left_to_read == size);
|
||||
|
||||
#ifdef TORRENT_DEBUG
|
||||
int counter = 0;
|
||||
#endif
|
||||
|
||||
file::iovec_t* current_buf = bufs;
|
||||
int read_bytes;
|
||||
for (;left_to_read > 0; ++file_iter, left_to_read -= read_bytes
|
||||
, buf_pos += read_bytes)
|
||||
@ -962,7 +1047,10 @@ namespace libtorrent
|
||||
|
||||
if (file_iter->pad_file)
|
||||
{
|
||||
std::memset(buf + buf_pos, 0, read_bytes);
|
||||
file::iovec_t* tmp_bufs = TORRENT_ALLOCA(file::iovec_t, num_bufs);
|
||||
int num_tmp_bufs = copy_bufs(current_buf, file_iter->size, tmp_bufs);
|
||||
clear_bufs(tmp_bufs, num_tmp_bufs);
|
||||
advance_bufs(current_buf, file_iter->size);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -978,30 +1066,23 @@ namespace libtorrent
|
||||
size_type pos = in->seek(file_iter->file_base + file_offset, file::begin, ec);
|
||||
if (pos != file_iter->file_base + file_offset || ec)
|
||||
{
|
||||
if (!fill_zero)
|
||||
{
|
||||
set_error(m_save_path / file_iter->path, ec);
|
||||
return -1;
|
||||
}
|
||||
std::memset(buf + buf_pos, 0, size - buf_pos);
|
||||
return size;
|
||||
set_error(m_save_path / file_iter->path, ec);
|
||||
return -1;
|
||||
}
|
||||
file_offset = 0;
|
||||
|
||||
int actual_read = int(in->read(buf + buf_pos, read_bytes, ec));
|
||||
file::iovec_t* tmp_bufs = TORRENT_ALLOCA(file::iovec_t, num_bufs);
|
||||
int num_tmp_bufs = copy_bufs(current_buf, read_bytes, tmp_bufs);
|
||||
int actual_read = int(in->readv(tmp_bufs, num_tmp_bufs, ec));
|
||||
|
||||
if (read_bytes != actual_read || ec)
|
||||
{
|
||||
// the file was not big enough
|
||||
if (actual_read > 0) buf_pos += actual_read;
|
||||
if (!fill_zero)
|
||||
{
|
||||
set_error(m_save_path / file_iter->path, ec);
|
||||
return -1;
|
||||
}
|
||||
std::memset(buf + buf_pos, 0, size - buf_pos);
|
||||
return size;
|
||||
set_error(m_save_path / file_iter->path, ec);
|
||||
return -1;
|
||||
}
|
||||
advance_bufs(current_buf, actual_read);
|
||||
|
||||
}
|
||||
return result;
|
||||
@ -1013,10 +1094,33 @@ namespace libtorrent
|
||||
, int offset
|
||||
, int size)
|
||||
{
|
||||
TORRENT_ASSERT(buf != 0);
|
||||
file::iovec_t b = { (void*)buf, size };
|
||||
return writev(&b, slot, offset, 1);
|
||||
}
|
||||
|
||||
int storage::read(
|
||||
char* buf
|
||||
, int slot
|
||||
, int offset
|
||||
, int size)
|
||||
{
|
||||
file::iovec_t b = { (void*)buf, size };
|
||||
return readv(&b, slot, offset, 1);
|
||||
}
|
||||
|
||||
int storage::writev(
|
||||
file::iovec_t* bufs
|
||||
, int slot
|
||||
, int offset
|
||||
, int num_bufs)
|
||||
{
|
||||
TORRENT_ASSERT(bufs != 0);
|
||||
TORRENT_ASSERT(slot >= 0);
|
||||
TORRENT_ASSERT(slot < m_files.num_pieces());
|
||||
TORRENT_ASSERT(offset >= 0);
|
||||
TORRENT_ASSERT(num_bufs > 0);
|
||||
|
||||
int size = bufs_size(bufs, num_bufs);
|
||||
TORRENT_ASSERT(size > 0);
|
||||
|
||||
#ifdef TORRENT_DEBUG
|
||||
@ -1058,6 +1162,7 @@ namespace libtorrent
|
||||
int counter = 0;
|
||||
#endif
|
||||
|
||||
file::iovec_t* current_buf = bufs;
|
||||
int write_bytes;
|
||||
for (;left_to_write > 0; ++file_iter, left_to_write -= write_bytes
|
||||
, buf_pos += write_bytes)
|
||||
@ -1100,8 +1205,10 @@ namespace libtorrent
|
||||
}
|
||||
file_offset = 0;
|
||||
|
||||
int actual_written = int(out->write(buf + buf_pos, write_bytes, ec));
|
||||
|
||||
file::iovec_t* tmp_bufs = TORRENT_ALLOCA(file::iovec_t, num_bufs);
|
||||
int num_tmp_bufs = copy_bufs(current_buf, write_bytes, tmp_bufs);
|
||||
int actual_written = int(out->writev(tmp_bufs, num_tmp_bufs, ec));
|
||||
|
||||
if (write_bytes != actual_written || ec)
|
||||
{
|
||||
// the file was not big enough
|
||||
@ -1109,7 +1216,7 @@ namespace libtorrent
|
||||
set_error(m_save_path / file_iter->path, ec);
|
||||
return -1;
|
||||
}
|
||||
|
||||
advance_bufs(current_buf, actual_written);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
@ -1366,31 +1473,35 @@ namespace libtorrent
|
||||
}
|
||||
|
||||
int piece_manager::read_impl(
|
||||
char* buf
|
||||
file::iovec_t* bufs
|
||||
, int piece_index
|
||||
, int offset
|
||||
, int size)
|
||||
, int num_bufs)
|
||||
{
|
||||
TORRENT_ASSERT(buf);
|
||||
TORRENT_ASSERT(bufs);
|
||||
TORRENT_ASSERT(offset >= 0);
|
||||
TORRENT_ASSERT(size > 0);
|
||||
TORRENT_ASSERT(num_bufs > 0);
|
||||
int slot = slot_for(piece_index);
|
||||
return m_storage->read(buf, slot, offset, size);
|
||||
return m_storage->readv(bufs, slot, offset, num_bufs);
|
||||
}
|
||||
|
||||
int piece_manager::write_impl(
|
||||
const char* buf
|
||||
file::iovec_t* bufs
|
||||
, int piece_index
|
||||
, int offset
|
||||
, int size)
|
||||
, int num_bufs)
|
||||
{
|
||||
TORRENT_ASSERT(buf);
|
||||
TORRENT_ASSERT(bufs);
|
||||
TORRENT_ASSERT(offset >= 0);
|
||||
TORRENT_ASSERT(size > 0);
|
||||
TORRENT_ASSERT(num_bufs > 0);
|
||||
TORRENT_ASSERT(piece_index >= 0 && piece_index < m_files.num_pieces());
|
||||
|
||||
int size = bufs_size(bufs, num_bufs);
|
||||
|
||||
file::iovec_t* iov = TORRENT_ALLOCA(file::iovec_t, num_bufs);
|
||||
std::copy(bufs, bufs + num_bufs, iov);
|
||||
int slot = allocate_slot_for_piece(piece_index);
|
||||
int ret = m_storage->write(buf, slot, offset, size);
|
||||
int ret = m_storage->writev(bufs, slot, offset, num_bufs);
|
||||
// only save the partial hash if the write succeeds
|
||||
if (ret != size) return ret;
|
||||
|
||||
@ -1403,7 +1514,10 @@ namespace libtorrent
|
||||
partial_hash& ph = m_piece_hasher[piece_index];
|
||||
TORRENT_ASSERT(ph.offset == 0);
|
||||
ph.offset = size;
|
||||
ph.h.update(buf, size);
|
||||
|
||||
for (file::iovec_t* i = iov, *end(iov + num_bufs); i < end; ++i)
|
||||
ph.h.update((char const*)i->iov_base, i->iov_len);
|
||||
|
||||
#ifdef TORRENT_PARTIAL_HASH_LOG
|
||||
out << time_now_string() << " NEW ["
|
||||
" s: " << this
|
||||
@ -1435,8 +1549,11 @@ namespace libtorrent
|
||||
<< " entries: " << m_piece_hasher.size()
|
||||
<< " ]" << std::endl;
|
||||
#endif
|
||||
i->second.offset += size;
|
||||
i->second.h.update(buf, size);
|
||||
for (file::iovec_t* b = iov, *end(iov + num_bufs); b < end; ++b)
|
||||
{
|
||||
i->second.h.update((char const*)b->iov_base, b->iov_len);
|
||||
i->second.offset += b->iov_len;
|
||||
}
|
||||
}
|
||||
#ifdef TORRENT_PARTIAL_HASH_LOG
|
||||
else
|
||||
|
Loading…
x
Reference in New Issue
Block a user