the file scanner should now be able to resume files downloaded by any client.
This commit is contained in:
parent
4c8a8d0a8c
commit
26b9900f91
191
src/storage.cpp
191
src/storage.cpp
|
@ -245,6 +245,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
*i = i - pieces.begin();
|
*i = i - pieces.begin();
|
||||||
}
|
}
|
||||||
|
std::srand((unsigned int)std::time(0));
|
||||||
std::vector<int> targets(pieces);
|
std::vector<int> targets(pieces);
|
||||||
std::random_shuffle(pieces.begin(), pieces.end());
|
std::random_shuffle(pieces.begin(), pieces.end());
|
||||||
std::random_shuffle(targets.begin(), targets.end());
|
std::random_shuffle(targets.begin(), targets.end());
|
||||||
|
@ -1104,7 +1105,7 @@ namespace libtorrent
|
||||||
|
|
||||||
// no piece matched the data in the slot
|
// no piece matched the data in the slot
|
||||||
if (matching_pieces.empty())
|
if (matching_pieces.empty())
|
||||||
return -1;
|
return unassigned;
|
||||||
|
|
||||||
// ------------------------------------------
|
// ------------------------------------------
|
||||||
// CHECK IF THE PIECE IS IN ITS CORRECT PLACE
|
// CHECK IF THE PIECE IS IN ITS CORRECT PLACE
|
||||||
|
@ -1167,7 +1168,7 @@ namespace libtorrent
|
||||||
|
|
||||||
// find a matching piece that hasn't
|
// find a matching piece that hasn't
|
||||||
// already been assigned
|
// already been assigned
|
||||||
int free_piece = -1;
|
int free_piece = unassigned;
|
||||||
for (std::vector<int>::iterator i = matching_pieces.begin();
|
for (std::vector<int>::iterator i = matching_pieces.begin();
|
||||||
i != matching_pieces.end();
|
i != matching_pieces.end();
|
||||||
++i)
|
++i)
|
||||||
|
@ -1187,8 +1188,8 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(free_piece == -1);
|
assert(free_piece == unassigned);
|
||||||
return -1;
|
return unassigned;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1258,7 +1259,6 @@ namespace libtorrent
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------
|
// ------------------------
|
||||||
// DO THE FULL CHECK
|
// DO THE FULL CHECK
|
||||||
// ------------------------
|
// ------------------------
|
||||||
|
@ -1299,60 +1299,192 @@ namespace libtorrent
|
||||||
, pieces
|
, pieces
|
||||||
, hash_to_piece);
|
, hash_to_piece);
|
||||||
|
|
||||||
if (piece_index >= 0)
|
assert(piece_index == unassigned || piece_index >= 0);
|
||||||
{
|
|
||||||
INVARIANT_CHECK;
|
|
||||||
|
|
||||||
if (m_slot_to_piece[piece_index] >= 0)
|
const bool this_should_move = piece_index >= 0 && m_slot_to_piece[piece_index] != unallocated;
|
||||||
{
|
const bool other_should_move = m_piece_to_slot[current_slot] != has_no_slot;
|
||||||
// the storage is unsorted, sorting.
|
|
||||||
assert(piece_index != current_slot);
|
// check if this piece should be swapped with any other slot
|
||||||
|
// this section will ensure that the storage is correctly sorted
|
||||||
|
// libtorrent will never leave the storage in a state that
|
||||||
|
// requires this sorting, but other clients may.
|
||||||
|
|
||||||
|
// example of worst case:
|
||||||
|
// | current_slot = 5
|
||||||
|
// V
|
||||||
|
// +---+- - - +---+- - - +---+- -
|
||||||
|
// | x | | 5 | | 3 | <- piece data in slots
|
||||||
|
// +---+- - - +---+- - - +---+- -
|
||||||
|
// 3 y 5 <- slot index
|
||||||
|
|
||||||
|
// in this example, the data in the current_slot (5)
|
||||||
|
// is piece 3. It has to be moved into slot 3. The data
|
||||||
|
// in slot y (piece 5) should be moved into the current_slot.
|
||||||
|
// and the data in slot 3 (piece x) should be moved to slot y.
|
||||||
|
|
||||||
|
// there are three possible cases.
|
||||||
|
// 1. There's another piece that should be placed into this slot
|
||||||
|
// 2. This piece should be placed into another slot.
|
||||||
|
// 3. There's another piece that should be placed into this slot
|
||||||
|
// and this piece should be placed into another slot
|
||||||
|
|
||||||
// swap piece_index with this slot
|
// swap piece_index with this slot
|
||||||
int other_piece = m_slot_to_piece[piece_index];
|
|
||||||
|
|
||||||
m_slot_to_piece[piece_index] = piece_index;
|
// case 1
|
||||||
|
if (this_should_move && !other_should_move)
|
||||||
|
{
|
||||||
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
assert(piece_index != current_slot);
|
||||||
|
|
||||||
|
const int other_slot = piece_index;
|
||||||
|
assert(other_slot >= 0);
|
||||||
|
int other_piece = m_slot_to_piece[other_slot];
|
||||||
|
|
||||||
|
m_slot_to_piece[other_slot] = piece_index;
|
||||||
m_slot_to_piece[current_slot] = other_piece;
|
m_slot_to_piece[current_slot] = other_piece;
|
||||||
|
|
||||||
m_piece_to_slot[piece_index] = piece_index;
|
m_piece_to_slot[piece_index] = piece_index;
|
||||||
m_piece_to_slot[other_piece] = current_slot;
|
if (other_piece >= 0) m_piece_to_slot[other_piece] = current_slot;
|
||||||
|
|
||||||
const int slot1_size = m_info.piece_size(current_slot);
|
if (other_piece == unassigned)
|
||||||
const int slot2_size = m_info.piece_size(piece_index);
|
{
|
||||||
|
std::vector<int>::iterator i =
|
||||||
|
std::find(m_free_slots.begin(), m_free_slots.end(), other_slot);
|
||||||
|
assert(i != m_free_slots.end());
|
||||||
|
m_free_slots.erase(i);
|
||||||
|
m_free_slots.push_back(current_slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int slot1_size = m_info.piece_size(piece_index);
|
||||||
|
const int slot2_size = other_piece >= 0 ? m_info.piece_size(other_piece) : 0;
|
||||||
std::vector<char> buf1(slot1_size);
|
std::vector<char> buf1(slot1_size);
|
||||||
std::vector<char> buf2(slot2_size);
|
|
||||||
m_storage.read(&buf1[0], current_slot, 0, slot1_size);
|
m_storage.read(&buf1[0], current_slot, 0, slot1_size);
|
||||||
|
if (slot2_size > 0)
|
||||||
|
{
|
||||||
|
std::vector<char> buf2(slot2_size);
|
||||||
m_storage.read(&buf2[0], piece_index, 0, slot2_size);
|
m_storage.read(&buf2[0], piece_index, 0, slot2_size);
|
||||||
m_storage.write(&buf2[0], current_slot, 0, slot2_size);
|
m_storage.write(&buf2[0], current_slot, 0, slot2_size);
|
||||||
|
}
|
||||||
m_storage.write(&buf1[0], piece_index, 0, slot1_size);
|
m_storage.write(&buf1[0], piece_index, 0, slot1_size);
|
||||||
|
assert(m_slot_to_piece[current_slot] == unassigned
|
||||||
|
|| m_piece_to_slot[m_slot_to_piece[current_slot]] == current_slot);
|
||||||
}
|
}
|
||||||
else
|
// case 2
|
||||||
|
else if (!this_should_move && other_should_move)
|
||||||
{
|
{
|
||||||
assert(m_slot_to_piece[current_slot] == unallocated);
|
INVARIANT_CHECK;
|
||||||
assert(m_piece_to_slot[piece_index] == has_no_slot);
|
|
||||||
|
|
||||||
// the slot was identified as piece 'piece_index'
|
assert(piece_index != current_slot);
|
||||||
m_piece_to_slot[piece_index] = current_slot;
|
|
||||||
|
|
||||||
m_slot_to_piece[current_slot] = piece_index;
|
const int other_piece = current_slot;
|
||||||
|
const int other_slot = m_piece_to_slot[other_piece];
|
||||||
|
assert(other_slot >= 0);
|
||||||
|
|
||||||
|
m_slot_to_piece[current_slot] = other_piece;
|
||||||
|
m_slot_to_piece[other_slot] = piece_index;
|
||||||
|
m_piece_to_slot[other_piece] = current_slot;
|
||||||
|
if (piece_index >= 0) m_piece_to_slot[piece_index] = other_slot;
|
||||||
|
|
||||||
|
if (piece_index == unassigned)
|
||||||
|
{
|
||||||
|
m_free_slots.push_back(other_slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const int slot1_size = m_info.piece_size(other_piece);
|
||||||
|
const int slot2_size = piece_index >= 0 ? m_info.piece_size(piece_index) : 0;
|
||||||
|
std::vector<char> buf1(slot1_size);
|
||||||
|
m_storage.read(&buf1[0], other_slot, 0, slot1_size);
|
||||||
|
if (slot2_size > 0)
|
||||||
|
{
|
||||||
|
std::vector<char> buf2(slot2_size);
|
||||||
|
m_storage.read(&buf2[0], current_slot, 0, slot2_size);
|
||||||
|
m_storage.write(&buf2[0], other_slot, 0, slot2_size);
|
||||||
|
}
|
||||||
|
m_storage.write(&buf1[0], current_slot, 0, slot1_size);
|
||||||
|
assert(m_slot_to_piece[current_slot] == unassigned
|
||||||
|
|| m_piece_to_slot[m_slot_to_piece[current_slot]] == current_slot);
|
||||||
|
}
|
||||||
|
else if (this_should_move && other_should_move)
|
||||||
|
{
|
||||||
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
assert(piece_index != current_slot);
|
||||||
|
assert(piece_index >= 0);
|
||||||
|
|
||||||
|
const int piece1 = m_slot_to_piece[piece_index];
|
||||||
|
const int piece2 = current_slot;
|
||||||
|
const int slot1 = piece_index;
|
||||||
|
const int slot2 = m_piece_to_slot[piece2];
|
||||||
|
|
||||||
|
assert(slot1 >= 0);
|
||||||
|
assert(slot2 >= 0);
|
||||||
|
assert(piece2 >= 0);
|
||||||
|
|
||||||
|
// movement diagram:
|
||||||
|
// +---------------------------------------+
|
||||||
|
// | |
|
||||||
|
// +--> slot1 --> slot2 --> current_slot --+
|
||||||
|
|
||||||
|
m_slot_to_piece[slot1] = piece_index;
|
||||||
|
m_slot_to_piece[slot2] = piece1;
|
||||||
|
m_slot_to_piece[current_slot] = piece2;
|
||||||
|
|
||||||
|
m_piece_to_slot[piece_index] = slot1;
|
||||||
|
m_piece_to_slot[current_slot] = piece2;
|
||||||
|
if (piece1 >= 0) m_piece_to_slot[piece1] = slot2;
|
||||||
|
|
||||||
|
if (piece1 == unassigned)
|
||||||
|
{
|
||||||
|
std::vector<int>::iterator i =
|
||||||
|
std::find(m_free_slots.begin(), m_free_slots.end(), slot1);
|
||||||
|
assert(i != m_free_slots.end());
|
||||||
|
m_free_slots.erase(i);
|
||||||
|
m_free_slots.push_back(slot2);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int slot1_size = piece1 >= 0 ? m_info.piece_size(piece1) : 0;
|
||||||
|
const int slot2_size = m_info.piece_size(piece2);
|
||||||
|
const int slot3_size = m_info.piece_size(piece_index);
|
||||||
|
|
||||||
|
std::vector<char> buf1(m_info.piece_length());
|
||||||
|
std::vector<char> buf2(m_info.piece_length());
|
||||||
|
|
||||||
|
m_storage.read(&buf2[0], current_slot, 0, slot3_size);
|
||||||
|
m_storage.read(&buf1[0], slot2, 0, slot2_size);
|
||||||
|
m_storage.write(&buf1[0], current_slot, 0, slot2_size);
|
||||||
|
if (slot1_size > 0)
|
||||||
|
{
|
||||||
|
m_storage.read(&buf1[0], slot1, 0, slot1_size);
|
||||||
|
m_storage.write(&buf1[0], slot2, 0, slot1_size);
|
||||||
|
}
|
||||||
|
m_storage.write(&buf2[0], slot1, 0, slot3_size);
|
||||||
|
assert(m_slot_to_piece[current_slot] == unassigned
|
||||||
|
|| m_piece_to_slot[m_slot_to_piece[current_slot]] == current_slot);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
// the data in the slot was not recognized
|
assert(m_piece_to_slot[current_slot] == has_no_slot || piece_index != current_slot);
|
||||||
// consider the slot free
|
|
||||||
assert(m_slot_to_piece[current_slot] == unallocated);
|
assert(m_slot_to_piece[current_slot] == unallocated);
|
||||||
m_slot_to_piece[current_slot] = unassigned;
|
assert(piece_index == unassigned || m_piece_to_slot[piece_index] == has_no_slot);
|
||||||
|
|
||||||
|
// the slot was identified as piece 'piece_index'
|
||||||
|
if (piece_index != unassigned)
|
||||||
|
m_piece_to_slot[piece_index] = current_slot;
|
||||||
|
else
|
||||||
m_free_slots.push_back(current_slot);
|
m_free_slots.push_back(current_slot);
|
||||||
|
|
||||||
|
m_slot_to_piece[current_slot] = piece_index;
|
||||||
|
|
||||||
|
assert(m_slot_to_piece[current_slot] == unassigned
|
||||||
|
|| m_piece_to_slot[m_slot_to_piece[current_slot]] == current_slot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (file_error&)
|
catch (file_error&)
|
||||||
{
|
{
|
||||||
// this means the slot wasn't allocated
|
// this means the slot wasn't allocated
|
||||||
assert(m_slot_to_piece[current_slot] == unallocated);
|
assert(m_slot_to_piece[current_slot] == unallocated);
|
||||||
// m_slot_to_piece[current_slot] = unallocated;
|
|
||||||
m_unallocated_slots.push_back(current_slot);
|
m_unallocated_slots.push_back(current_slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1364,6 +1496,7 @@ namespace libtorrent
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO: sort m_free_slots and m_unallocated_slots?
|
||||||
}
|
}
|
||||||
|
|
||||||
void piece_manager::check_pieces(
|
void piece_manager::check_pieces(
|
||||||
|
|
Loading…
Reference in New Issue