Skip to content

Commit

Permalink
Fix bug in tombstone resurrection
Browse files Browse the repository at this point in the history
While iterating through a tombstones backlink columns it may be erased
underneath if the last backlink was removed. In this case the iteration
must be aborted.
  • Loading branch information
jedelbo committed Dec 10, 2020
1 parent 74821eb commit 9c891f7
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 1 deletion.
7 changes: 6 additions & 1 deletion src/realm/obj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1444,8 +1444,13 @@ void Obj::assign_pk_and_backlinks(const ConstObj& other)
Mixed val = other.get_any(col_pk);
this->set(col_pk, val);
}
auto nb_tombstones = m_table->m_tombstones->size();

auto copy_links = [this, &other](ColKey col) {
auto copy_links = [this, &other, nb_tombstones](ColKey col) {
if (nb_tombstones != m_table->m_tombstones->size()) {
// Object has been deleted - we are done
return true;
}
auto t = m_table->get_opposite_table(col);
auto c = m_table->get_opposite_column(col);
auto backlinks = other.get_all_backlinks(col);
Expand Down
34 changes: 34 additions & 0 deletions test/test_unresolved_links.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -453,4 +453,38 @@ TEST(Unresolved_CondensedIndices)
CHECK_EQUAL(list2.size(), 1);
}

TEST(Unresolved_Recursive)
{
Group g;
auto table = g.add_table_with_primary_key("RecursiveNode", type_ObjectId, "_id");
// Create two link columns. This will create two backlink columns in the target table
// When a tombstone is resurrected, and a backlink in the first backlink column is
// removed and the tombstone is thereby deleted, we should not attempt to find backlinks
// in the second backlink column.
auto col_next = table->add_column_link(type_Link, "NextNode", *table);
auto col_children = table->add_column_link(type_LinkList, "children", *table);

auto key = table->get_objkey_from_primary_key(ObjectId("5fc929bac4a3964b6d603f4e"));
key = table->create_object_with_primary_key(ObjectId("5fc929bac4a3964b6d603f4d")).set(col_next, key).get_key();

table->create_object_with_primary_key(ObjectId("5fc929bac4a3964b6d603f4c")).set(col_next, key);

// This will delete the tombstone for "5fc929bac4a3964b6d603f4e"
table->create_object_with_primary_key(ObjectId("5fc929bac4a3964b6d603f4e"));

// The following will ensure that objects will be turned into tombstones when invalidated
auto obj = table->create_object_with_primary_key(ObjectId("5fc929bac4a3964b6d603f4b"));
auto ll = obj.get_linklist(col_children);
ll.add(table->get_objkey_from_primary_key(ObjectId("5fc929bac4a3964b6d603f4c")));
ll.add(table->get_objkey_from_primary_key(ObjectId("5fc929bac4a3964b6d603f4d")));
ll.add(table->get_objkey_from_primary_key(ObjectId("5fc929bac4a3964b6d603f4e")));

g.verify();
CHECK_EQUAL(table->nb_unresolved(), 0);
table->get_object_with_primary_key(ObjectId("5fc929bac4a3964b6d603f4c")).invalidate();
table->get_object_with_primary_key(ObjectId("5fc929bac4a3964b6d603f4d")).invalidate();
CHECK_EQUAL(table->nb_unresolved(), 2);
g.verify();
}

#endif

0 comments on commit 9c891f7

Please sign in to comment.