Skip to content

Commit

Permalink
Fix issue with resurrection of tombstones (#4180)
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 authored Dec 10, 2020
1 parent aad2915 commit 30e5474
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 2 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

### Fixed
* <How to hit and notice issue? what was the impact?> ([#????](https://github.com/realm/realm-core/issues/????), since v?.?.?)
* None.
* You may get assertion "n != realm::npos" when integrating changesets from the server. ([#4180](https://github.com/realm/realm-core/pull/4180), since v10.0.0)

### Breaking changes
* None.
Expand Down
3 changes: 3 additions & 0 deletions src/realm/cluster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2168,6 +2168,9 @@ Obj ClusterTree::insert(ObjKey k, const FieldValues& values)

bool ClusterTree::is_valid(ObjKey k) const
{
if (m_size == 0)
return false;

ClusterNode::State state;
return m_root->try_get(k, state);
}
Expand Down
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 30e5474

Please sign in to comment.