diff --git a/include/libtorrent/storage.hpp b/include/libtorrent/storage.hpp index 74c81b883..1a4f46539 100755 --- a/include/libtorrent/storage.hpp +++ b/include/libtorrent/storage.hpp @@ -32,11 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_STORAGE_HPP_INCLUDE #define TORRENT_STORAGE_HPP_INCLUDE -/* -#include -#include -#include -#include */ + #include #include @@ -45,18 +41,8 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/entry.hpp" #include "libtorrent/torrent_info.hpp" -//#include "libtorrent/socket.hpp" -//#include "libtorrent/policy.hpp" #include "libtorrent/opaque_value_ptr.hpp" -/* - * This file declares the following functions: - * - *---------------------------------- - * - * - */ - namespace libtorrent { namespace detail @@ -72,143 +58,7 @@ namespace libtorrent virtual ~file_allocation_failed() throw() {} std::string m_msg; }; -/* - // wraps access to pieces with a file-like interface - class piece_file - { - friend class storage; - public: - piece_file(): m_piece_index(-1), m_storage(0) {} - ~piece_file() - { - if (m_piece_index >= 0) close(); - } - - enum open_mode { in, out }; - - // opens a piece with the given index from storage s - void open(storage* s, int index, open_mode m, int seek_offset = 0, bool lock_ = true); - void close() - { - //std::cout << std::clock() << "close " << m_piece_index << "\n"; - m_file.close(); - m_piece_index = -1; - m_storage = 0; - } - - void write(const char* buf, int size, bool lock_ = true); - int read(char* buf, int size, bool lock_ = true); - void seek_forward(int step, bool lock_ = true); - - // tells the position in the file - int tell() const { return m_piece_offset; } - int left() const { return m_piece_size - m_piece_offset; } - - int index() const { return m_piece_index; } - void lock(bool lock_ = true); - - private: - - void reopen(); - - // the file itself - boost::filesystem::fstream m_file; - - // the mode with which this file was opened - open_mode m_mode; - - // the mode the fstream object was opened in - std::ios_base::openmode m_file_mode; - - // file we're currently reading from/writing to - std::vector::const_iterator m_file_iter; - - // the global position - entry::integer_type m_position; - - // the position we're at in the current file - std::size_t m_file_offset; - - // the byte offset in the current piece - std::size_t m_piece_offset; - - // the size of the current piece - int m_piece_size; - - // the index of the piece, -1 means the piece isn't open - int m_piece_index; - - storage* m_storage; - - }; - - class storage - { - friend class piece_file; - friend class piece_sorter; - public: - typedef entry::integer_type size_type; - - void initialize_pieces(torrent* t, - const boost::filesystem::path& path, - detail::piece_checker_data* data, - boost::mutex& mutex); - - int bytes_left() const { return m_bytes_left; } - - unsigned int num_pieces() const { return m_torrent_file->num_pieces(); } - bool have_piece(unsigned int index) const { return m_have_piece[index]; } - - bool verify_piece(piece_file& index); - - const std::vector& pieces() const { return m_have_piece; } - - entry::integer_type piece_storage(int piece); - void allocate_pieces(int num); - - size_type read(char* buf, int slot, size_type offset, size_type size); - void write(const char* buf, int slot, size_type offset, size_type size); - - private: - - void libtorrent::storage::invariant() const; - - // total number of bytes left to be downloaded - entry::integer_type m_bytes_left; - - // the location where the downloaded file should be stored - boost::filesystem::path m_save_path; - - // a bitmask representing the pieces we have - std::vector m_have_piece; - - const torrent_info* m_torrent_file; - - // allocated pieces in file - std::vector m_allocated_pieces; - // unallocated blocks at the end of files - std::vector m_free_blocks; - // allocated blocks whose checksum doesn't match - std::vector m_free_pieces; - - // index here is a slot number in the file - // -1 : the slot is unallocated - // -2 : the slot is allocated but not assigned to a piece - // * : the slot is assigned to this piece - std::vector m_slot_to_piece; - - // synchronization - boost::mutex m_locked_pieces_monitor; - boost::condition m_unlocked_pieces; - std::vector m_locked_pieces; - - mutable boost::recursive_mutex m_mutex; - - torrent* m_torrent; - }; -*/ - // provides thread safe read/write operations on a torrent storage class storage { public: @@ -252,38 +102,6 @@ namespace libtorrent private: struct impl; opaque_value_ptr m_pimpl; -/* - storage m_storage; - - // total number of bytes left to be downloaded - size_type m_bytes_left; - - // a bitmask representing the pieces we have - std::vector m_have_piece; - - const torrent_info& m_info; - - // maps piece index to slot index. -1 means the piece - // doesn't exist - std::vector m_piece_to_slot; - // slots that hasn't had any file storage allocated - std::vector m_unallocated_slots; - // slots that has file storage, but isn't assigned to a piece - std::vector m_free_slots; - - // index here is a slot number in the file - // -1 : the slot is unallocated - // -2 : the slot is allocated but not assigned to a piece - // * : the slot is assigned to this piece - std::vector m_slot_to_piece; - - boost::filesystem::path m_save_path; - - mutable boost::recursive_mutex m_mutex; - - bool m_allocating; - boost::mutex m_allocating_monitor; - boost::condition m_allocating_condition;*/ }; } diff --git a/src/storage.cpp b/src/storage.cpp index 967bd64d1..2faaec2a9 100755 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -55,429 +55,9 @@ POSSIBILITY OF SUCH DAMAGE. #if defined(_MSC_VER) #define for if (false) {} else for #endif -/* -using namespace libtorrent; - -//#define SUPER_VERBOSE_LOGGING -#define NO_THREAD_SAFE_PIECE_FILE namespace { - struct defered_action_base {}; - - template - struct defered_value_impl : defered_action_base - { - defered_value_impl(T ref_, U enter, U exit_) - : exit(exit_) - , ref(ref_) - { - ref = enter; - } - - ~defered_value_impl() - { - ref = exit; - } - - mutable U exit; - T ref; - }; - - template - defered_value_impl defered_value(T& x, const U& enter, const U& exit) - { - return defered_value_impl(x, enter, exit); - } - - template - struct defered_action_impl : defered_action_base - { - defered_action_impl(const Fn& fn_) - : fn(fn_) - {} - - ~defered_action_impl() - { - fn(); - } - - Fn fn; - }; - - template - defered_action_impl defered_action(const Fn& fn) - { - return defered_action_impl(fn); - } - - typedef const defered_action_base& defered; - - struct defered_bitvector_value : defered_action_base - { - defered_bitvector_value(std::vector& v, std::size_t n_, bool entry_, bool exit_) - : vec(v) - , n(n_) - , onexit(exit_) - { - vec[n] = entry_; - } - - ~defered_bitvector_value() - { - vec[n] = onexit; - } - - std::vector& vec; - std::size_t n; - bool onexit; - }; - -} // namespace unnamed - - -void libtorrent::piece_file::reopen() -{ - m_position = m_storage->piece_storage(m_piece_index); - - entry::integer_type global_pos = m_position + m_piece_offset; - - assert(global_pos >= 0 - && global_pos < m_storage->m_torrent_file->total_size()); - - for (m_file_iter = m_storage->m_torrent_file->begin_files(); - global_pos >= m_file_iter->size; ++m_file_iter) - { - global_pos -= m_file_iter->size; - } - - m_file_offset = global_pos; - - namespace fs = boost::filesystem; - - fs::path path = m_storage->m_save_path / - m_file_iter->path / m_file_iter->filename; - - m_file.close(); - m_file.clear(); - - m_file.open(path, m_file_mode); - - if (m_mode == in) m_file.seekg(m_file_offset, std::ios_base::beg); - else m_file.seekp(m_file_offset, std::ios_base::beg); -} - -void libtorrent::piece_file::lock(bool lock_) -{ -#ifndef NO_THREAD_SAFE_PIECE_FILE - boost::mutex::scoped_lock lock(m_storage->m_locked_pieces_monitor); - - if (lock_) - { - while (m_storage->m_locked_pieces[m_piece_index]) - m_storage->m_unlocked_pieces.wait(lock); - m_storage->m_locked_pieces[m_piece_index] = true; - } - else - { - m_storage->m_locked_pieces[m_piece_index] = false; - m_storage->m_unlocked_pieces.notify_all(); - } -#endif -} - -void libtorrent::piece_file::open(storage* s, int index, open_mode o, int seek_offset, bool lock_) -{ - // do this here so that blocks can be allocated before we lock the piece - m_position = s->piece_storage(index); - - // synchronization ------------------------------------------------------ - - m_storage = s; - m_piece_index = index; - - lock(); - defered unlock = defered_action( - boost::bind( - &piece_file::lock - , this - , false)); - - // ---------------------------------------------------------------------- - - assert(index >= 0 && index < s->m_torrent_file->num_pieces() && "internal error"); - - m_mode = o; - m_piece_size = m_storage->m_torrent_file->piece_size(m_piece_index); - m_position = s->piece_storage(index); - - m_piece_offset = seek_offset; - - entry::integer_type global_pos = m_position + m_piece_offset; - - assert(global_pos >= 0 && global_pos < s->m_torrent_file->total_size()); - - for (m_file_iter = m_storage->m_torrent_file->begin_files(); - global_pos >= m_file_iter->size; ++m_file_iter) - { - global_pos -= m_file_iter->size; - } - - m_file_offset = global_pos; - - std::ios_base::openmode m; - if (m_mode == out) m = std::ios_base::out | std::ios_base::in | std::ios_base::binary; - else m = std::ios_base::in | std::ios_base::binary; - - namespace fs = boost::filesystem; - - fs::path path = m_storage->m_save_path / - m_file_iter->path / m_file_iter->filename; - - m_file.close(); - m_file.clear(); - - m_file_mode = m; - m_file.open(path, m_file_mode); - - if (m_mode == in) m_file.seekg(m_file_offset, std::ios_base::beg); - else m_file.seekp(m_file_offset, std::ios_base::beg); -} - -int libtorrent::piece_file::read(char* buf, int size, bool lock_) -{ - assert(m_mode == in); - assert(!m_file.fail()); - assert(m_file.is_open()); - - // synchronization ------------------------------------------------------ - lock(); - defered unlock = defered_action( - boost::bind( - &piece_file::lock - , this - , false)); - // ---------------------------------------------------------------------- - - if (m_storage->piece_storage(m_piece_index) != m_position) - { - reopen(); - } - - int left_to_read = size; - - if (m_piece_offset + left_to_read > m_piece_size) - left_to_read = m_piece_size - m_piece_offset; - - int result = left_to_read; - int buf_pos = 0; - - while (left_to_read > 0) - { - int read_bytes = left_to_read; - if (m_file_offset + read_bytes > m_file_iter->size) - read_bytes = m_file_iter->size - m_file_offset; - assert(read_bytes > 0); - - m_file.read(buf + buf_pos, read_bytes); - - assert(read_bytes == m_file.gcount()); - - left_to_read -= read_bytes; - buf_pos += read_bytes; - assert(buf_pos >= 0); - m_file_offset += read_bytes; - m_piece_offset += read_bytes; - - if (left_to_read > 0) - { - ++m_file_iter; - boost::filesystem::path path = m_storage->m_save_path / - m_file_iter->path / m_file_iter->filename; - - m_file_offset = 0; - m_file.close(); - m_file.clear(); - m_file.open(path, m_file_mode); - } - } - - return result; -} - -void libtorrent::piece_file::write(const char* buf, int size, bool lock_) -{ - assert(m_mode == out); - assert(!m_file.fail()); - assert(m_file.is_open()); - - // synchronization ------------------------------------------------------ - lock(); - defered unlock = defered_action( - boost::bind( - &piece_file::lock - , this - , false)); - - // ---------------------------------------------------------------------- - - if (m_storage->piece_storage(m_piece_index) != m_position) - { - reopen(); - } - - int left_to_write = size; - - if (m_piece_offset + left_to_write > m_piece_size) - left_to_write = m_piece_size - m_piece_offset; - - int buf_pos = 0; - - while (left_to_write > 0) - { - int write_bytes = left_to_write; - if (m_file_offset + write_bytes > m_file_iter->size) - { - assert(m_file_iter->size > m_file_offset); - write_bytes = m_file_iter->size - m_file_offset; - } - - assert(buf_pos >= 0); - assert(write_bytes > 0); - m_file.write(buf + buf_pos, write_bytes); - - left_to_write -= write_bytes; - buf_pos += write_bytes; - assert(buf_pos >= 0); - m_file_offset += write_bytes; - assert(m_file_offset <= m_file_iter->size); - m_piece_offset += write_bytes; - - if (left_to_write > 0) - { - ++m_file_iter; - - assert(m_file_iter != m_storage->m_torrent_file->end_files()); - - boost::filesystem::path path = m_storage->m_save_path / - m_file_iter->path / m_file_iter->filename; - - m_file_offset = 0; - m_file.close(); - m_file.clear(); - m_file.open(path, m_file_mode); - } - } -} - -void libtorrent::piece_file::seek_forward(int step, bool lock_) -{ - lock(); - defered unlock = defered_action( - boost::bind( - &piece_file::lock - , this - , false)); - - assert(step >= 0 && "you cannot seek backwards in piece files"); - assert(m_file_offset == (long)m_file.tellg() && "internal error"); - if (step == 0) return; - - int left_to_seek = step; - - // make sure we don't read more than what belongs to this piece - assert(m_piece_offset + step <= m_piece_size); - - assert(m_file_iter != m_storage->m_torrent_file->end_files() && "internal error, please report!"); - bool reopen = false; - while (m_file_iter->size - m_file_offset < left_to_seek) - { - left_to_seek -= m_file_iter->size - m_file_offset; - m_piece_offset += m_file_iter->size - m_file_offset; - m_file_offset = 0; - ++m_file_iter; - reopen = true; - assert(m_file_iter != m_storage->m_torrent_file->end_files() && "internal error, please report!"); - } - - if (reopen) - { - boost::filesystem::path path = m_storage->m_save_path; - path /= m_file_iter->path; - path /= m_file_iter->filename; - - m_file.close(); - m_file.open(path, std::ios_base::in | std::ios_base::binary); - } - - m_file_offset += left_to_seek; - m_piece_offset +=left_to_seek; - - if (m_mode == in) - { - m_file.seekg(left_to_seek, std::ios_base::cur); - assert(m_file_offset == (long)m_file.tellg() && "internal error"); - } - else - { - m_file.seekp(left_to_seek, std::ios_base::cur); - assert(m_file_offset == (long)m_file.tellp() && "internal error"); - } - -} - - -bool libtorrent::storage::verify_piece(piece_file& file) -{ - int index = file.index(); - assert(index >= 0 && index < m_have_piece.size()); - if (m_have_piece[index]) return true; - - std::vector buffer(m_torrent_file->piece_size(index)); - - file.open(this, index, piece_file::in); - int read = file.read(&buffer[0], buffer.size()); - - assert(read == m_torrent_file->piece_size(index)); - - // calculate hash for piece - hasher h; - h.update(&buffer[0], read); - sha1_hash digest = h.final(); - - if (std::equal(digest.begin(), digest.end(), m_torrent_file->hash_for_piece(index).begin())) - { - // tell all peer_connections to announce that - // this piece is available - m_bytes_left -= read; - - // mark it as available - m_have_piece[index] = true; - -#ifndef NDEBUG - int real_bytes_left = 0; - for (int i = 0; i < m_torrent_file->num_pieces(); ++i) - { - if (!m_have_piece[i]) real_bytes_left += m_torrent_file->piece_size(i); - } - assert(real_bytes_left == m_bytes_left); -#endif - - return true; - } - return false; -} -*/ -namespace { -/* - struct equal_hash - { - bool operator()(const sha1_hash& lhs, const sha1_hash& rhs) const - { - return std::equal(lhs.begin(), lhs.end(), rhs.begin()); - } - }; -*/ struct lazy_hash { mutable libtorrent::sha1_hash digest; @@ -511,774 +91,6 @@ namespace { } } // namespace unnamed -/* -void libtorrent::storage::allocate_pieces(int num) -{ - // synchronization ------------------------------------------------------ - boost::recursive_mutex::scoped_lock lock(m_mutex); - // ---------------------------------------------------------------------- - - namespace fs = boost::filesystem; - - std::cout << "allocating pieces...\n"; - - std::vector::iterator iter - = m_free_blocks.begin(); - std::vector::iterator end_iter - = m_free_blocks.end(); - - const entry::integer_type piece_size = m_torrent_file->piece_length(); - - std::vector zeros(piece_size, 0); - - int last_piece_index = -1; - - for (int i = 0; i < num; ++i, ++iter) - { - if (iter == end_iter) - break; - - entry::integer_type pos = *iter; - entry::integer_type piece_pos = pos; - - const bool last_piece = - pos == m_torrent_file->total_size() - - m_torrent_file->piece_size( - m_torrent_file->num_pieces() - 1); - - if (last_piece) - last_piece_index = i; - - torrent_info::file_iterator file_iter; - - for (file_iter = m_torrent_file->begin_files(); - pos > file_iter->size; ++file_iter) - { - pos -= file_iter->size; - } - - entry::integer_type bytes_left = last_piece - ? m_torrent_file->piece_size(m_torrent_file->num_pieces() - 1) - : piece_size; - - while (bytes_left > 0) - { - fs::path path(m_save_path / file_iter->path / file_iter->filename); - - fs::ofstream out; - - if (fs::exists(path)) - out.open(path, std::ios_base::binary | std::ios_base::in); - else - out.open(path, std::ios_base::binary); - - out.seekp(pos, std::ios_base::beg); - - assert((entry::integer_type)out.tellp() == pos); - - entry::integer_type bytes_to_write = bytes_left; - - if (pos + bytes_to_write >= file_iter->size) - { - bytes_to_write = file_iter->size - pos; - } - - out.write(&zeros[0], bytes_to_write); - - bytes_left -= bytes_to_write; - ++file_iter; - pos = 0; - } - - m_free_pieces.push_back(piece_pos); - m_slot_to_piece[piece_pos / piece_size] = -2; - } - - m_free_blocks.erase(m_free_blocks.begin(), iter); - - // move last slot to the end - if (last_piece_index != -1) - std::swap(m_free_pieces[last_piece_index], m_free_pieces.front()); - - std::cout << "\tfree pieces: " << m_free_pieces.size() << "\n"; - std::cout << "\tfree blocks: " << m_free_blocks.size() << "\n"; -} - -#include - -entry::integer_type libtorrent::storage::piece_storage(int piece) -{ - // synchronization ------------------------------------------------------ - boost::recursive_mutex::scoped_lock lock(m_mutex); - // ---------------------------------------------------------------------- - - assert(piece >= 0 && piece < m_allocated_pieces.size()); - - entry::integer_type result; - - result = m_allocated_pieces[piece]; - - if (result != -1) - { - return result; - } - - if (m_free_pieces.empty()) - { - allocate_pieces(5); - assert(!m_free_pieces.empty()); - } - - entry::integer_type wanted_pos = piece * m_torrent_file->piece_length(); - - int n = m_free_pieces.size(); - int m = m_free_blocks.size(); - - std::vector::iterator iter( - std::find( - m_free_pieces.begin() - , m_free_pieces.end() - , wanted_pos)); - - if (iter == m_free_pieces.end()) - iter = m_free_pieces.end() - 1; - - result = *iter; - m_free_pieces.erase(iter); - -// assert(m_slot_to_piece[result / m_torrent_file->piece_length()] < 0); - - m_slot_to_piece[result / m_torrent_file->piece_length()] = piece; - m_allocated_pieces[piece] = result; - - // the last slot can only be given to the last piece! - // if this is the last slot, swap position with the last piece - const int last_piece = m_torrent_file->num_pieces() - 1; - const bool last_slot = result == - m_torrent_file->total_size() - m_torrent_file->piece_size(last_piece); - - if (last_slot && piece != last_piece) - { - assert(m_allocated_pieces[last_piece] != -1); - - piece_file f; - - f.open(this, last_piece, piece_file::in); - std::vector buf(m_torrent_file->piece_size(last_piece)); - f.read(&buf[0], m_torrent_file->piece_size(last_piece)); - f.close(); - - f.open(this, piece, piece_file::out); - f.write(&buf[0], m_torrent_file->piece_size(last_piece)); - f.close(); - - std::swap( - m_slot_to_piece[m_allocated_pieces[piece] / m_torrent_file->piece_length()] - , m_slot_to_piece[m_allocated_pieces[last_piece] / m_torrent_file->piece_length()] - ); - - std::swap(m_allocated_pieces[piece], m_allocated_pieces[last_piece]); - result = m_allocated_pieces[piece]; - } - else - { - int my_slot = result / m_torrent_file->piece_length(); - int other_piece = m_slot_to_piece[piece]; - - if (piece == my_slot) - return result; - - // the slot that we want is available and - // some other piece want slot - if (m_allocated_pieces[my_slot] >= 0 // another piece wants this position - && other_piece >= 0 - && m_slot_to_piece[piece] != my_slot) // .. and we want another piece position) - { - piece_file f; - - std::vector buf1(m_torrent_file->piece_length()); - std::vector buf2(m_torrent_file->piece_length()); - -#ifdef SUPER_VERBOSE_LOGGING - std::stringstream s; - - s << "double move!\n"; - - s << "allocating for piece #" << piece << " at slot " << my_slot << "\n"; - s << " piece at my wanted storage: " << other_piece << "\n"; - s << " slot that wants my storage: " << - m_allocated_pieces[my_slot] / m_torrent_file->piece_length() << "\n"; - - for (int i = 0; i < m_torrent_file->num_pieces(); ++i) - { - if (m_slot_to_piece[i] == i) - s << i << " is in correct position\n"; - else if (m_slot_to_piece[i] < 0) - s << i << " is not used\n"; - else - s << i << " is in wrong position (" << m_slot_to_piece[i] << ")\n"; - } -#endif - - // m_allocated_pieces[my_slot] -> piece - // other_piece -> m_allocated_pieces[my_slot] - // piece -> other_piece - - // read piece that wants my storage - f.open(this, my_slot, piece_file::in); - f.read(&buf1[0], m_torrent_file->piece_length()); - f.close(); - - // read piece that should be moved away - f.open(this, other_piece, piece_file::in); - f.read(&buf2[0], m_torrent_file->piece_length()); - f.close(); - - // write piece that wants my storage - f.open(this, piece, piece_file::out); - f.write(&buf1[0], m_torrent_file->piece_length()); - f.close(); - - // write piece that should be moved away - f.open(this, my_slot, piece_file::out); - f.write(&buf2[0], m_torrent_file->piece_length()); - f.close(); - - entry::integer_type pos[3] = { - m_allocated_pieces[piece] // me - , m_allocated_pieces[my_slot] // piece that wants my storage - , m_allocated_pieces[other_piece] // piece that is moved away - }; - - int slots[3] = { - my_slot //me - , m_allocated_pieces[my_slot] / m_torrent_file->piece_length() - // piece that wants my storage - , piece // piece that is moved away - }; - - m_slot_to_piece[my_slot] = my_slot; - m_slot_to_piece[piece] = piece; - m_slot_to_piece[ - m_allocated_pieces[my_slot] / m_torrent_file->piece_length() - ] = other_piece; - - m_allocated_pieces[piece] = pos[2]; - m_allocated_pieces[my_slot] = pos[0]; - m_allocated_pieces[other_piece] = pos[1]; - -#ifdef SUPER_VERBOSE_LOGGING - s << "i want slot : #" << piece << "\n"; - s << "occupied by piece : #" << other_piece << "\n"; - s << "wants my slot : #" << my_slot << "\n"; - - for (int i = 0; i < m_torrent_file->num_pieces(); ++i) - { - if (m_slot_to_piece[i] == i) - s << i << " is in correct position\n"; - else if (m_slot_to_piece[i] < 0) - s << i << " is not used\n"; - else - s << i << " is in wrong position (" << m_slot_to_piece[i] << ")\n"; - } - - m_torrent->debug_log(s.str()); -#endif - - return m_allocated_pieces[piece]; - } - - // there's another piece that wans my slot, swap positions - if (m_allocated_pieces[my_slot] > 0 && m_slot_to_piece[piece] != my_slot) - { - piece_file f; -#ifdef SUPER_VERBOSE_LOGGING - std::stringstream s; - - s << "single move!\n"; - - s << "allocating for piece #" << piece << " at slot " << my_slot << "\n"; - s << " slot that wants my storage: " << - m_allocated_pieces[my_slot] / m_torrent_file->piece_length() << "\n"; - - for (int i = 0; i < m_torrent_file->num_pieces(); ++i) - { - if (m_slot_to_piece[i] == i) - s << i << " is in correct position\n"; - else if (m_slot_to_piece[i] < 0) - s << i << " is not used\n"; - else - s << i << " is in wrong position (" << m_slot_to_piece[i] << ")\n"; - } -#endif - f.open(this, my_slot, piece_file::in); - std::vector buf(m_torrent_file->piece_length()); - f.read(&buf[0], m_torrent_file->piece_length()); - f.close(); - - f.open(this, piece, piece_file::out); - f.write(&buf[0], m_torrent_file->piece_length()); - f.close(); - - std::swap( - m_slot_to_piece[my_slot] - , m_slot_to_piece[m_allocated_pieces[my_slot] / m_torrent_file->piece_length()] - ); - - std::swap(m_allocated_pieces[piece], m_allocated_pieces[my_slot]); -#ifdef SUPER_VERBOSE_LOGGING - s << "-------------\n"; - - for (int i = 0; i < m_torrent_file->num_pieces(); ++i) - { - if (m_slot_to_piece[i] == i) - s << i << " is in correct position\n"; - else if (m_slot_to_piece[i] < 0) - s << i << " is not used\n"; - else - s << i << " is in wrong position (" << m_slot_to_piece[i] << ")\n"; - } - - m_torrent->debug_log(s.str()); -#endif - return m_allocated_pieces[piece]; - } - - if (other_piece >= 0 && other_piece != piece) - { - piece_file f; - - f.open(this, other_piece, piece_file::in); - std::vector buf(m_torrent_file->piece_length()); - f.read(&buf[0], m_torrent_file->piece_length()); - f.close(); - - f.open(this, piece, piece_file::out); - f.write(&buf[0], m_torrent_file->piece_length()); - f.close(); - - std::swap( - m_slot_to_piece[piece] - , m_slot_to_piece[result / m_torrent_file->piece_length()] - ); - - std::swap(m_allocated_pieces[piece], m_allocated_pieces[other_piece]); - -#ifdef SUPER_VERBOSE_LOGGING - std::stringstream s; - - s << "\nswapping #" << piece << " into place\n"; - s << "moved #" << other_piece << " doing it..\n"; - - for (int i = 0; i < m_torrent_file->num_pieces(); ++i) - { - if (m_slot_to_piece[i] == i) - s << i << " is in correct position\n"; - else if (m_slot_to_piece[i] < 0) - s << i << " is not used\n"; - else - s << i << " is in wrong position (" << m_slot_to_piece[i] << ")\n"; - } - - m_torrent->debug_log(s.str()); -#endif - return m_allocated_pieces[piece]; - } - - } - - return result; -} - -void libtorrent::storage::initialize_pieces(torrent* t, - const boost::filesystem::path& path, - detail::piece_checker_data* data, - boost::mutex& mutex) -{ - // synchronization ------------------------------------------------------ - boost::recursive_mutex::scoped_lock lock(m_mutex); - // ---------------------------------------------------------------------- - - namespace fs = boost::filesystem; - - m_torrent = t; - - m_save_path = path; - m_torrent_file = &t->torrent_file(); - - // free up some memory - std::vector( - m_torrent_file->num_pieces(), false - ).swap(m_have_piece); - - std::vector( - m_torrent_file->num_pieces(), -1 - ).swap(m_allocated_pieces); - - std::vector( - m_torrent_file->num_pieces(), false - ).swap(m_locked_pieces); - - std::vector( - m_torrent_file->num_pieces(), -1 - ).swap(m_slot_to_piece); - - std::vector().swap(m_free_blocks); - std::vector().swap(m_free_pieces); - - m_bytes_left = m_torrent_file->total_size(); - - const std::size_t piece_size = m_torrent_file->piece_length(); - const std::size_t last_piece_size = m_torrent_file->piece_size( - m_torrent_file->num_pieces() - 1); - - bool changed_file = true; - fs::ifstream in; - - std::vector piece_data(m_torrent_file->piece_length()); - std::size_t piece_offset = 0; - - std::size_t current_piece = 0; - std::size_t bytes_to_read = piece_size; - std::size_t bytes_current_read = 0; - std::size_t seek_into_next = 0; - entry::integer_type filesize = 0; - entry::integer_type start_of_read = 0; - entry::integer_type start_of_file = 0; - - { - boost::mutex::scoped_lock lock(mutex); - data->progress = 0.f; - } - - for (torrent_info::file_iterator file_iter = m_torrent_file->begin_files(), - end_iter = m_torrent_file->end_files(); - file_iter != end_iter;) - { - { - boost::mutex::scoped_lock lock(mutex); - - data->progress = (float)current_piece / m_torrent_file->num_pieces(); - if (data->abort) - return; - } - - fs::path path(m_save_path / file_iter->path); - - // if the path doesn't exist, create the - // entire directory tree - if (!fs::exists(path)) - fs::create_directories(path); - - path /= file_iter->filename; - - if (changed_file) - { - in.close(); - in.clear(); - in.open(path, std::ios_base::binary); - - changed_file = false; - - bytes_current_read = seek_into_next; - - if (!in) - { - filesize = 0; - } - else - { - in.seekg(0, std::ios_base::end); - filesize = in.tellg(); - in.seekg(seek_into_next, std::ios_base::beg); - } - } - - // we are at the start of a new piece - // so we store the start of the piece - if (bytes_to_read == m_torrent_file->piece_size(current_piece)) - start_of_read = current_piece * piece_size; - - std::size_t bytes_read = 0; - - if (filesize > 0) - { - in.read(&piece_data[piece_offset], bytes_to_read); - bytes_read = in.gcount(); - } - - bytes_current_read += bytes_read; - bytes_to_read -= bytes_read; - - assert(bytes_to_read >= 0); - - // bytes left to read, go on with next file - if (bytes_to_read > 0) - { - if (bytes_current_read != file_iter->size) - { - entry::integer_type pos; - entry::integer_type file_end = start_of_file + file_iter->size; - - for (pos = start_of_read; pos < file_end; - pos += piece_size) - { - m_free_blocks.push_back(pos); - ++current_piece; - } - - seek_into_next = pos - file_end; - bytes_to_read = piece_size; - piece_offset = 0; - } - else - { - seek_into_next = 0; - piece_offset += bytes_read; - } - - changed_file = true; - start_of_file += file_iter->size; - ++file_iter; - continue; - } - - // done with piece, move on to next - piece_offset = 0; - ++current_piece; - - // we need to take special actions if this is - // the last piece, since that piece might actually - // be smaller than piece_size. - - lazy_hash large_digest(&piece_data[0], piece_size); - lazy_hash small_digest(&piece_data[0], last_piece_size); - - const lazy_hash* digest[2] = { - &large_digest, &small_digest - }; - - bool found = false; - - for (int i = 0; i < m_torrent_file->num_pieces(); ++i) - { - if (m_have_piece[i]) - continue; - - const sha1_hash& hash = digest[ - i == m_torrent_file->num_pieces() - 1]->get(); - - if (equal_hash()(hash, m_torrent_file->hash_for_piece(i))) - { - m_bytes_left -= m_torrent_file->piece_size(i); - - m_allocated_pieces[i] = start_of_read; - m_slot_to_piece[start_of_read / piece_size] = i; - m_have_piece[i] = true; - found = true; - break; - } - } - - if (!found) - { - m_slot_to_piece[start_of_read / piece_size] = -2; - - entry::integer_type last_pos = - m_torrent_file->total_size() - - m_torrent_file->piece_size( - m_torrent_file->num_pieces() - 1); - - // treat the last slot as unallocated space - // this means that when we get to the last - // slot we are either allocating space for - // the last piece, or the last piece has already - // been allocated - if (start_of_read == last_pos) - m_free_blocks.push_back(start_of_read); - else - m_free_pieces.push_back(start_of_read); - } - - bytes_to_read = m_torrent_file->piece_size(current_piece); - } - - std::cout << " free pieces: " << m_free_pieces.size() << "\n"; - std::cout << " free blocks: " << m_free_blocks.size() << "\n"; - std::cout << " num pieces: " << m_torrent_file->num_pieces() << "\n"; - - std::cout << " have_pieces: "; - print_bitmask(m_have_piece); - std::cout << "\n"; - std::cout << std::count(m_have_piece.begin(), m_have_piece.end(), true) << "\n"; - - invariant(); -} - -void libtorrent::storage::invariant() const -{ - // synchronization ------------------------------------------------------ - boost::recursive_mutex::scoped_lock lock(m_mutex); - // ---------------------------------------------------------------------- - - for (int i = 0; i < m_torrent_file->num_pieces(); ++i) - { - if (m_allocated_pieces[i] != m_torrent_file->piece_length() * i) - assert(m_slot_to_piece[i] < 0); - } -} - -libtorrent::storage::size_type libtorrent::storage::read( - char* buf - , int slot - , size_type offset - , size_type size) -{ - namespace fs = boost::filesystem; - - size_type start = slot * m_torrent_file->piece_length() + offset; - - // find the file iterator and file offset - size_type file_offset = start; - std::vector::const_iterator file_iter; - - for (file_iter = m_torrent_file->begin_files();;) - { - if (file_offset < file_iter->size) - break; - - file_offset -= file_iter->size; - ++file_iter; - } - - fs::ifstream in( - m_save_path / file_iter->path / file_iter->filename - , std::ios_base::binary - ); - - assert(file_offset < file_iter->size); - - in.seekg(std::ios_base::beg, file_offset); - - size_type left_to_read = size; - size_type slot_size = m_torrent_file->piece_size(slot); - - if (offset + left_to_read > slot_size) - left_to_read = slot_size - offset; - - assert(left_to_read >= 0); - - int result = left_to_read; - int buf_pos = 0; - - while (left_to_read > 0) - { - int read_bytes = left_to_read; - if (file_offset + read_bytes > file_iter->size) - read_bytes = file_iter->size - offset; - - assert(read_bytes > 0); - - in.read(buf + buf_pos, read_bytes); - - assert(read_bytes == in.gcount()); - - left_to_read -= read_bytes; - buf_pos += read_bytes; - assert(buf_pos >= 0); - file_offset += read_bytes; - - if (left_to_read > 0) - { - ++file_iter; - fs::path path = m_save_path /file_iter->path / file_iter->filename; - - file_offset = 0; - in.close(); - in.clear(); - in.open(path, std::ios_base::binary); - } - } - - return result; -} - -void libtorrent::storage::write(const char* buf, int slot, size_type offset, size_type size) -{ - namespace fs = boost::filesystem; - - size_type start = slot * m_torrent_file->piece_length() + offset; - - // find the file iterator and file offset - size_type file_offset = start; - std::vector::const_iterator file_iter; - - for (file_iter = m_torrent_file->begin_files();;) - { - if (file_offset < file_iter->size) - break; - - file_offset -= file_iter->size; - ++file_iter; - } - - fs::ofstream out( - m_save_path / file_iter->path / file_iter->filename - , std::ios_base::in | std::ios_base::binary - ); - - assert(file_offset < file_iter->size); - - out.seekp(std::ios_base::beg, file_offset); - - size_type left_to_write = size; - size_type slot_size = m_torrent_file->piece_size(slot); - - if (offset + left_to_write > slot_size) - left_to_write = slot_size - offset; - - assert(left_to_write >= 0); - - int buf_pos = 0; - - while (left_to_write > 0) - { - int write_bytes = left_to_write; - if (file_offset + write_bytes > file_iter->size) - { - assert(file_iter->size > file_offset); - write_bytes = file_iter->size - file_offset; - } - - assert(buf_pos >= 0); - assert(write_bytes > 0); - out.write(buf + buf_pos, write_bytes); - - left_to_write -= write_bytes; - buf_pos += write_bytes; - assert(buf_pos >= 0); - file_offset += write_bytes; - assert(file_offset <= file_iter->size); - - if (left_to_write > 0) - { - ++file_iter; - - assert(file_iter != m_torrent_file->end_files()); - - fs::path path = m_save_path / file_iter->path / file_iter->filename; - - file_offset = 0; - out.close(); - out.clear(); - out.open(path, std::ios_base::in | std::ios_base::binary); - } - } -} -*/ - - -// -- new storage abstraction ----------------------------------------------- namespace fs = boost::filesystem; @@ -2070,6 +882,6 @@ namespace libtorrent { print_to_log(s.str()); } - + } // namespace libtorrent