Improve performance for large numbers of deletions

This commit is contained in:
Thomas Goyne 2016-03-29 16:41:50 -07:00
parent 8623aa6c6b
commit ae9516dbb7
1 changed files with 24 additions and 33 deletions

View File

@ -284,52 +284,43 @@ void CollectionChangeBuilder::move_over(size_t row_ndx, size_t last_row)
else else
modifications.remove(row_ndx); modifications.remove(row_ndx);
bool row_is_insertion = insertions.contains(row_ndx);
bool last_is_insertion = !insertions.empty() && prev(insertions.end())->second == last_row + 1;
REALM_ASSERT_DEBUG(insertions.empty() || prev(insertions.end())->second <= last_row + 1);
bool updated_existing_move = false; bool updated_existing_move = false;
for (size_t i = 0; i < moves.size(); ++i) { if (row_is_insertion || last_is_insertion) {
auto& move = moves[i]; for (size_t i = 0; i < moves.size(); ++i) {
// Remove moves to the row being deleted auto& move = moves[i];
if (move.to == row_ndx) { // Remove moves to the row being deleted
moves.erase(moves.begin() + i); if (move.to == row_ndx) {
--i; moves.erase(moves.begin() + i);
continue; --i;
continue;
}
if (move.to != last_row)
continue;
REALM_ASSERT(!updated_existing_move);
// Collapse A -> B, B -> C into a single A -> C move
move.to = row_ndx;
updated_existing_move = true;
} }
if (move.to != last_row)
continue;
REALM_ASSERT(!updated_existing_move);
// Collapse A -> B, B -> C into a single A -> C move
move.to = row_ndx;
updated_existing_move = true;
if (!insertions.empty()) {
REALM_ASSERT(std::prev(insertions.end())->second - 1 <= last_row);
insertions.remove(last_row);
}
// Don't mark the moved-over row as deleted if it was a new insertion
if (!insertions.contains(row_ndx)) {
deletions.add_shifted(insertions.unshift(row_ndx));
insertions.add(row_ndx);
}
// Because this is a move, the unshifted source row has already been marked as deleted
} }
if (updated_existing_move)
return;
// Don't report deletions/moves if last_row is newly inserted // Don't report deletions/moves if last_row is newly inserted
if (!insertions.empty() && prev(insertions.end())->second == last_row + 1) { if (last_is_insertion) {
insertions.remove(last_row); insertions.remove(last_row);
} }
else { // If it was previously moved, the unshifted source row has already been marked as deleted
else if (!updated_existing_move) {
auto shifted_last_row = insertions.unshift(last_row); auto shifted_last_row = insertions.unshift(last_row);
shifted_last_row = deletions.add_shifted(shifted_last_row); shifted_last_row = deletions.add_shifted(shifted_last_row);
moves.push_back({shifted_last_row, row_ndx}); moves.push_back({shifted_last_row, row_ndx});
} }
// Don't mark the moved-over row as deleted if it was a new insertion // Don't mark the moved-over row as deleted if it was a new insertion
if (!insertions.contains(row_ndx)) { if (!row_is_insertion) {
deletions.add_shifted(insertions.unshift(row_ndx)); deletions.add_shifted(insertions.unshift(row_ndx));
insertions.add(row_ndx); insertions.add(row_ndx);
} }