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:
parent
9bed3d1dd5
commit
cec6748e0c
|
@ -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
|
||||||
============
|
============
|
||||||
|
|
||||||
|
|
|
@ -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" |
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue