remove the concept of slots, and just talk about pieces (since we don't do compact allocation anymore). Remove the section about compact allocation

This commit is contained in:
arvidn 2015-11-19 01:38:04 -05:00
parent 9bed3d1dd5
commit cec6748e0c
4 changed files with 35 additions and 93 deletions

View File

@ -394,10 +394,6 @@ The file format is a bencoded dictionary containing the following fields:
| | means it is free, that there's no piece there. If it is -1, | | | means it is free, that there's no piece there. If it is -1, |
| | means the slot isn't allocated on disk yet. The pieces have | | | means the slot isn't allocated on disk yet. The pieces have |
| | to meet the following requirement: | | | to meet the following requirement: |
| | |
| | If there's a slot at the position of the piece index, |
| | the piece must be located in that slot. |
| | |
+--------------------------+--------------------------------------------------------------+ +--------------------------+--------------------------------------------------------------+
| ``total_uploaded`` | integer. The number of bytes that have been uploaded in | | ``total_uploaded`` | integer. The number of bytes that have been uploaded in |
| | total for this torrent. | | | total for this torrent. |
@ -579,61 +575,6 @@ The benefits of this mode are:
* No risk of a download failing because of a full disk during download, once * No risk of a download failing because of a full disk during download, once
all files have been created. all files have been created.
compact allocation
------------------
.. note::
Support for compact allocation has been removed from libttorrent
The compact allocation will only allocate as much storage as it needs to keep
the pieces downloaded so far. This means that pieces will be moved around to be
placed at their final position in the files while downloading (to make sure the
completed download has all its pieces in the correct place). So, the main
drawbacks are:
* More disk operations while downloading since pieces are moved around.
* Potentially more fragmentation in the filesystem.
* Cannot be used while having files with priority 0.
The benefits though, are:
* No startup delay, since the files don't need allocating.
* The download will not use unnecessary disk space.
* Disk caches perform much better than in full allocation and raises the
download speed limit imposed by the disk.
* Works well on filesystems that don't support sparse files.
The algorithm that is used when allocating pieces and slots isn't very
complicated. For the interested, a description follows.
storing a piece:
1. let **A** be a newly downloaded piece, with index **n**.
2. let **s** be the number of slots allocated in the file we're
downloading to. (the number of pieces it has room for).
3. if **n** >= **s** then allocate a new slot and put the piece there.
4. if **n** < **s** then allocate a new slot, move the data at
slot **n** to the new slot and put **A** in slot **n**.
allocating a new slot:
1. if there's an unassigned slot (a slot that doesn't
contain any piece), return that slot index.
2. append the new slot at the end of the file (or find an unused slot).
3. let **i** be the index of newly allocated slot
4. if we have downloaded piece index **i** already (to slot **j**) then
1. move the data at slot **j** to slot **i**.
2. return slot index **j** as the newly allocated free slot.
5. return **i** as the newly allocated slot.
HTTP seeding HTTP seeding
============ ============

View File

@ -7,7 +7,7 @@
v v
+--------------------------+ +--------------------------+
| "piece_manager" | | "piece_manager" |
| "(maps pieces to slots)" | | "disk job fence logic" |
+--------------------------+ +--------------------------+
^ ^
| |
@ -15,13 +15,13 @@
/----------------------------\ +-------------------+ /----------------------------\ +-------------------+
| "storage" |<---->| "file_pool" | | "storage" |<---->| "file_pool" |
| | | "open file cache" | | | | "open file cache" |
| "(maps slots to file and" | +-------------------+ | "(maps pieces to file and" | +-------------------+
| "offset. reads and writes" | | "offset. reads and writes" |
| "to disk)" | +--------------------+ | "to disk)" | +---------------------+
| |<-----+ "file_storage" | | |<-----+ "file_storage" |
\----------------------------/ | "standard slot to" | \----------------------------/ | "standard piece to" |
^ | "file mapping" | ^ | "file mapping" |
| +--------------------+ | +---------------------+
v v
+--------------------------+ +--------------------------+
| "file" | | "file" |

View File

@ -90,9 +90,9 @@ POSSIBILITY OF SUCH DAMAGE.
// temp_storage(file_storage const& fs) : m_files(fs) {} // temp_storage(file_storage const& fs) : m_files(fs) {}
// virtual bool initialize(storage_error& se) { return false; } // virtual bool initialize(storage_error& se) { return false; }
// virtual bool has_any_file() { return false; } // virtual bool has_any_file() { return false; }
// virtual int read(char* buf, int slot, int offset, int size) // virtual int read(char* buf, int piece, int offset, int size)
// { // {
// std::map<int, std::vector<char> >::const_iterator i = m_file_data.find(slot); // std::map<int, std::vector<char> >::const_iterator i = m_file_data.find(piece);
// if (i == m_file_data.end()) return 0; // if (i == m_file_data.end()) return 0;
// int available = i->second.size() - offset; // int available = i->second.size() - offset;
// if (available <= 0) return 0; // if (available <= 0) return 0;
@ -100,9 +100,9 @@ POSSIBILITY OF SUCH DAMAGE.
// memcpy(buf, &i->second[offset], available); // memcpy(buf, &i->second[offset], available);
// return available; // return available;
// } // }
// virtual int write(const char* buf, int slot, int offset, int size) // virtual int write(const char* buf, int piece, int offset, int size)
// { // {
// std::vector<char>& data = m_file_data[slot]; // std::vector<char>& data = m_file_data[piece];
// if (data.size() < offset + size) data.resize(offset + size); // if (data.size() < offset + size) data.resize(offset + size);
// std::memcpy(&data[offset], buf, size); // std::memcpy(&data[offset], buf, size);
// return size; // return size;
@ -114,15 +114,15 @@ POSSIBILITY OF SUCH DAMAGE.
// , std::vector<std::string> const* links // , std::vector<std::string> const* links
// , storage_error& error) { return false; } // , storage_error& error) { return false; }
// virtual bool write_resume_data(entry& rd) const { return false; } // virtual bool write_resume_data(entry& rd) const { return false; }
// virtual boost::int64_t physical_offset(int slot, int offset) // virtual boost::int64_t physical_offset(int piece, int offset)
// { return slot * m_files.piece_length() + offset; }; // { return piece * m_files.piece_length() + offset; };
// virtual sha1_hash hash_for_slot(int slot, partial_hash& ph, int piece_size) // virtual sha1_hash hash_for_slot(int piece, partial_hash& ph, int piece_size)
// { // {
// int left = piece_size - ph.offset; // int left = piece_size - ph.offset;
// assert(left >= 0); // assert(left >= 0);
// if (left > 0) // if (left > 0)
// { // {
// std::vector<char>& data = m_file_data[slot]; // std::vector<char>& data = m_file_data[piece];
// // if there are padding files, those blocks will be considered // // if there are padding files, those blocks will be considered
// // completed even though they haven't been written to the storage. // // completed even though they haven't been written to the storage.
// // in this case, just extend the piece buffer to its full size // // in this case, just extend the piece buffer to its full size
@ -202,9 +202,10 @@ namespace libtorrent
// but modifies some particular behavior, for instance encrypting the data // but modifies some particular behavior, for instance encrypting the data
// before it's written to disk, and decrypting it when it's read again. // before it's written to disk, and decrypting it when it's read again.
// //
// The storage interface is based on slots, each slot is 'piece_size' number // The storage interface is based on pieces. Avery read and write operation
// happens in the piece-space. Each piece fits 'piece_size' number
// of bytes. All access is done by writing and reading whole or partial // of bytes. All access is done by writing and reading whole or partial
// slots. One slot is one piece in the torrent. // pieces.
// //
// libtorrent comes with two built-in storage implementations; // libtorrent comes with two built-in storage implementations;
// ``default_storage`` and ``disabled_storage``. Their constructor functions // ``default_storage`` and ``disabled_storage``. Their constructor functions
@ -466,7 +467,7 @@ namespace libtorrent
}; };
void delete_one_file(std::string const& p, error_code& ec); void delete_one_file(std::string const& p, error_code& ec);
int readwritev(file::iovec_t const* bufs, int slot, int offset int readwritev(file::iovec_t const* bufs, int piece, int offset
, int num_bufs, fileop const& op, storage_error& ec); , int num_bufs, fileop const& op, storage_error& ec);
void need_partfile(); void need_partfile();
@ -477,7 +478,7 @@ namespace libtorrent
// in order to avoid calling stat() on each file multiple times // in order to avoid calling stat() on each file multiple times
// during startup, cache the results in here, and clear it all // during startup, cache the results in here, and clear it all
// out once the torrent starts (to avoid getting stale results) // out once the torrent starts (to avoid getting stale results)
// each slot represents the size and timestamp of the file // each entry represents the size and timestamp of the file
mutable stat_cache m_stat_cache; mutable stat_cache m_stat_cache;
// helper function to open a file in the file pool with the right mode // helper function to open a file in the file pool with the right mode

View File

@ -714,12 +714,12 @@ namespace libtorrent
} }
} }
int default_storage::sparse_end(int slot) const int default_storage::sparse_end(int piece) const
{ {
TORRENT_ASSERT(slot >= 0); TORRENT_ASSERT(piece >= 0);
TORRENT_ASSERT(slot < files().num_pieces()); TORRENT_ASSERT(piece < files().num_pieces());
boost::int64_t file_offset = boost::int64_t(slot) * files().piece_length(); boost::int64_t file_offset = boost::int64_t(piece) * files().piece_length();
int file_index = 0; int file_index = 0;
for (;;) for (;;)
@ -734,7 +734,7 @@ namespace libtorrent
error_code ec; error_code ec;
file_handle handle = open_file_impl(file_index, file::read_only, ec); file_handle handle = open_file_impl(file_index, file::read_only, ec);
if (ec) return slot; if (ec) return piece;
boost::int64_t data_start = handle->sparse_end(file_offset); boost::int64_t data_start = handle->sparse_end(file_offset);
return int((data_start + files().piece_length() - 1) / files().piece_length()); return int((data_start + files().piece_length() - 1) / files().piece_length());
@ -1096,7 +1096,7 @@ namespace libtorrent
} }
int default_storage::readv(file::iovec_t const* bufs, int num_bufs int default_storage::readv(file::iovec_t const* bufs, int num_bufs
, int slot, int offset, int flags, storage_error& ec) , int piece, int offset, int flags, storage_error& ec)
{ {
fileop op = { &file::readv fileop op = { &file::readv
, file::read_only | flags }; , file::read_only | flags };
@ -1104,15 +1104,15 @@ namespace libtorrent
boost::thread::sleep(boost::get_system_time() boost::thread::sleep(boost::get_system_time()
+ boost::posix_time::milliseconds(1000)); + boost::posix_time::milliseconds(1000));
#endif #endif
return readwritev(bufs, slot, offset, num_bufs, op, ec); return readwritev(bufs, piece, offset, num_bufs, op, ec);
} }
int default_storage::writev(file::iovec_t const* bufs, int num_bufs int default_storage::writev(file::iovec_t const* bufs, int num_bufs
, int slot, int offset, int flags, storage_error& ec) , int piece, int offset, int flags, storage_error& ec)
{ {
fileop op = { &file::writev fileop op = { &file::writev
, file::read_write | flags }; , file::read_write | flags };
return readwritev(bufs, slot, offset, num_bufs, op, ec); return readwritev(bufs, piece, offset, num_bufs, op, ec);
} }
// much of what needs to be done when reading and writing // much of what needs to be done when reading and writing
@ -1121,12 +1121,12 @@ namespace libtorrent
// is a template, and the fileop decides what to do with the // is a template, and the fileop decides what to do with the
// file and the buffers. // file and the buffers.
int default_storage::readwritev(file::iovec_t const* const bufs int default_storage::readwritev(file::iovec_t const* const bufs
, const int slot, const int offset , const int piece, const int offset
, const int num_bufs, fileop const& op, storage_error& ec) , const int num_bufs, fileop const& op, storage_error& ec)
{ {
TORRENT_ASSERT(bufs != 0); TORRENT_ASSERT(bufs != 0);
TORRENT_ASSERT(slot >= 0); TORRENT_ASSERT(piece >= 0);
TORRENT_ASSERT(slot < m_files.num_pieces()); TORRENT_ASSERT(piece < m_files.num_pieces());
TORRENT_ASSERT(offset >= 0); TORRENT_ASSERT(offset >= 0);
TORRENT_ASSERT(num_bufs > 0); TORRENT_ASSERT(num_bufs > 0);
@ -1135,7 +1135,7 @@ namespace libtorrent
TORRENT_ASSERT(files().is_loaded()); TORRENT_ASSERT(files().is_loaded());
// find the file iterator and file offset // find the file iterator and file offset
boost::uint64_t torrent_offset = slot * boost::uint64_t(m_files.piece_length()) + offset; boost::uint64_t torrent_offset = piece * boost::uint64_t(m_files.piece_length()) + offset;
int file_index = files().file_index_at_offset(torrent_offset); int file_index = files().file_index_at_offset(torrent_offset);
TORRENT_ASSERT(torrent_offset >= files().file_offset(file_index)); TORRENT_ASSERT(torrent_offset >= files().file_offset(file_index));
TORRENT_ASSERT(torrent_offset < files().file_offset(file_index) + files().file_size(file_index)); TORRENT_ASSERT(torrent_offset < files().file_offset(file_index) + files().file_size(file_index));
@ -1229,13 +1229,13 @@ namespace libtorrent
// the fileop object. // the fileop object.
// write // write
bytes_transferred = m_part_file->writev(tmp_bufs, num_tmp_bufs bytes_transferred = m_part_file->writev(tmp_bufs, num_tmp_bufs
, slot, offset, e); , piece, offset, e);
} }
else else
{ {
// read // read
bytes_transferred = m_part_file->readv(tmp_bufs, num_tmp_bufs bytes_transferred = m_part_file->readv(tmp_bufs, num_tmp_bufs
, slot, offset, e); , piece, offset, e);
} }
if (e) if (e)
{ {