@@ -89,7 +89,7 @@ const Table* ClusterNode::get_owning_table() const noexcept
8989
9090void ClusterNode::get (ObjKey k, ClusterNode::State& state) const
9191{
92- if (!k || !try_get (k , state)) {
92+ if (!k || !try_get (RowKey (k) , state)) {
9393 throw KeyNotFound (util::format (" No object with key '%1' in '%2'" , k.value , get_owning_table ()->get_name ()));
9494 }
9595}
@@ -225,7 +225,7 @@ void Cluster::update_from_parent() noexcept
225225 }
226226}
227227
228- MemRef Cluster::ensure_writeable (ObjKey )
228+ MemRef Cluster::ensure_writeable (RowKey )
229229{
230230 // By specifying the minimum size, we ensure that the array has a capacity
231231 // to hold m_size 64 bit refs.
@@ -234,7 +234,7 @@ MemRef Cluster::ensure_writeable(ObjKey)
234234 return get_mem ();
235235}
236236
237- void Cluster::update_ref_in_parent (ObjKey , ref_type)
237+ void Cluster::update_ref_in_parent (RowKey , ref_type)
238238{
239239 REALM_UNREACHABLE ();
240240}
@@ -362,13 +362,13 @@ inline void Cluster::do_insert_link(size_t ndx, ColKey col_key, Mixed init_val,
362362 }
363363}
364364
365- void Cluster::insert_row (size_t ndx, ObjKey k , const FieldValues& init_values)
365+ void Cluster::insert_row (size_t ndx, RowKey row_key , const FieldValues& init_values)
366366{
367367 // Ensure the cluster array is big enough to hold 64 bit values.
368368 copy_on_write (m_size * 8 );
369369
370370 if (m_keys.is_attached ()) {
371- m_keys.insert (ndx, k .value );
371+ m_keys.insert (ndx, row_key .value );
372372 }
373373 else {
374374 Array::set (s_key_ref_or_size_index, Array::get (s_key_ref_or_size_index) + 2 ); // Increments size by 1
@@ -396,6 +396,7 @@ void Cluster::insert_row(size_t ndx, ObjKey k, const FieldValues& init_values)
396396 }
397397
398398 bool nullable = attr.test (col_attr_Nullable);
399+ ObjKey obj_key (int64_t (row_key.value + get_offset ()));
399400 switch (type) {
400401 case col_type_Int:
401402 if (attr.test (col_attr_Nullable)) {
@@ -421,7 +422,7 @@ void Cluster::insert_row(size_t ndx, ObjKey k, const FieldValues& init_values)
421422 do_insert_row<ArrayBinary>(ndx, col_key, init_value, nullable);
422423 break ;
423424 case col_type_Mixed: {
424- do_insert_mixed (ndx, col_key, init_value, ObjKey (k. value + get_offset ()) );
425+ do_insert_mixed (ndx, col_key, init_value, obj_key );
425426 break ;
426427 }
427428 case col_type_Timestamp:
@@ -437,10 +438,10 @@ void Cluster::insert_row(size_t ndx, ObjKey k, const FieldValues& init_values)
437438 do_insert_row<ArrayUUIDNull>(ndx, col_key, init_value, nullable);
438439 break ;
439440 case col_type_Link:
440- do_insert_key (ndx, col_key, init_value, ObjKey (k. value + get_offset ()) );
441+ do_insert_key (ndx, col_key, init_value, obj_key );
441442 break ;
442443 case col_type_TypedLink:
443- do_insert_link (ndx, col_key, init_value, ObjKey (k. value + get_offset ()) );
444+ do_insert_link (ndx, col_key, init_value, obj_key );
444445 break ;
445446 case col_type_BackLink: {
446447 ArrayBacklink arr (m_alloc);
@@ -685,7 +686,7 @@ void Cluster::remove_column(ColKey col_key)
685686 Array::set (idx, 0 );
686687}
687688
688- ref_type Cluster::insert (ObjKey k , const FieldValues& init_values, ClusterNode::State& state)
689+ ref_type Cluster::insert (RowKey row_key , const FieldValues& init_values, ClusterNode::State& state)
689690{
690691 int64_t current_key_value = -1 ;
691692 size_t sz;
@@ -694,34 +695,34 @@ ref_type Cluster::insert(ObjKey k, const FieldValues& init_values, ClusterNode::
694695
695696 auto on_error = [&] {
696697 throw KeyAlreadyUsed (
697- util::format (" When inserting key '%1' in '%2'" , k .value , get_owning_table ()->get_name ()));
698+ util::format (" When inserting key '%1' in '%2'" , row_key .value , get_owning_table ()->get_name ()));
698699 };
699700
700701 if (m_keys.is_attached ()) {
701702 sz = m_keys.size ();
702- ndx = m_keys.lower_bound (uint64_t (k .value ) );
703+ ndx = m_keys.lower_bound (row_key .value );
703704 if (ndx < sz) {
704705 current_key_value = m_keys.get (ndx);
705- if (k .value == current_key_value) {
706+ if (row_key .value == uint64_t ( current_key_value) ) {
706707 on_error ();
707708 }
708709 }
709710 }
710711 else {
711712 sz = size_t (Array::get (s_key_ref_or_size_index)) >> 1 ; // Size is stored as tagged integer
712- if (uint64_t (k .value ) < sz) {
713+ if (row_key .value < sz) {
713714 on_error ();
714715 }
715716 // Key value is bigger than all other values, should be put last
716717 ndx = sz;
717- if (uint64_t (k .value ) > sz && sz < cluster_node_size) {
718+ if (row_key .value > sz && sz < cluster_node_size) {
718719 ensure_general_form ();
719720 }
720721 }
721722
722723 REALM_ASSERT_DEBUG (sz <= cluster_node_size);
723724 if (REALM_LIKELY (sz < cluster_node_size)) {
724- insert_row (ndx, k , init_values); // Throws
725+ insert_row (ndx, row_key , init_values); // Throws
725726 state.mem = get_mem ();
726727 state.index = ndx;
727728 }
@@ -730,8 +731,8 @@ ref_type Cluster::insert(ObjKey k, const FieldValues& init_values, ClusterNode::
730731 Cluster new_leaf (0 , m_alloc, m_tree_top);
731732 new_leaf.create ();
732733 if (ndx == sz) {
733- new_leaf.insert_row (0 , ObjKey (0 ), init_values); // Throws
734- state.split_key = k .value ;
734+ new_leaf.insert_row (0 , RowKey (0 ), init_values); // Throws
735+ state.split_key = int64_t (row_key .value ) ;
735736 state.mem = new_leaf.get_mem ();
736737 state.index = 0 ;
737738 }
@@ -740,7 +741,7 @@ ref_type Cluster::insert(ObjKey k, const FieldValues& init_values, ClusterNode::
740741 REALM_ASSERT_DEBUG (m_keys.is_attached ());
741742 new_leaf.ensure_general_form ();
742743 move (ndx, &new_leaf, current_key_value);
743- insert_row (ndx, k , init_values); // Throws
744+ insert_row (ndx, row_key , init_values); // Throws
744745 state.mem = get_mem ();
745746 state.split_key = current_key_value;
746747 state.index = ndx;
@@ -751,15 +752,15 @@ ref_type Cluster::insert(ObjKey k, const FieldValues& init_values, ClusterNode::
751752 return ret;
752753}
753754
754- bool Cluster::try_get (ObjKey k, ClusterNode::State& state) const noexcept
755+ bool Cluster::try_get (RowKey k, ClusterNode::State& state) const noexcept
755756{
756757 state.mem = get_mem ();
757758 if (m_keys.is_attached ()) {
758- state.index = m_keys.lower_bound (uint64_t ( k.value ) );
759- return state.index != m_keys.size () && m_keys.get (state.index ) == uint64_t ( k.value ) ;
759+ state.index = m_keys.lower_bound (k.value );
760+ return state.index != m_keys.size () && m_keys.get (state.index ) == k.value ;
760761 }
761762 else {
762- if (uint64_t ( k.value ) < uint64_t (Array::get (s_key_ref_or_size_index) >> 1 )) {
763+ if (k.value < uint64_t (Array::get (s_key_ref_or_size_index) >> 1 )) {
763764 state.index = size_t (k.value );
764765 return true ;
765766 }
@@ -798,7 +799,7 @@ inline void Cluster::do_erase(size_t ndx, ColKey col_key)
798799 values.erase (ndx);
799800}
800801
801- inline void Cluster::do_erase_mixed (size_t ndx, ColKey col_key, ObjKey key, CascadeState& state)
802+ inline void Cluster::do_erase_mixed (size_t ndx, ColKey col_key, CascadeState& state)
802803{
803804 const Table* origin_table = m_tree_top.get_owning_table ();
804805 auto col_ndx = col_key.get_index ();
@@ -811,19 +812,16 @@ inline void Cluster::do_erase_mixed(size_t ndx, ColKey col_key, ObjKey key, Casc
811812 Mixed value = values.get (ndx);
812813 if (value.is_type (type_TypedLink)) {
813814 ObjLink link = value.get <ObjLink>();
814- auto target_obj = origin_table->get_parent_group ()->get_object (link);
815-
816- ColKey backlink_col_key = target_obj.get_table ()->find_backlink_column (col_key, origin_table->get_key ());
817- REALM_ASSERT (backlink_col_key);
818- target_obj.remove_one_backlink (backlink_col_key, get_real_key (ndx)); // Throws
815+ Obj obj (origin_table->m_own_ref , get_mem (), get_real_key (ndx), ndx);
816+ obj.remove_backlink (col_key, link, state);
819817 }
820818 if (value.is_type (type_List)) {
821- Obj obj (origin_table->m_own_ref , get_mem (), key , ndx);
819+ Obj obj (origin_table->m_own_ref , get_mem (), get_real_key (ndx) , ndx);
822820 Lst<Mixed> list (obj, col_key);
823821 list.remove_backlinks (state);
824822 }
825823 if (value.is_type (type_Dictionary)) {
826- Obj obj (origin_table->m_own_ref , get_mem (), key , ndx);
824+ Obj obj (origin_table->m_own_ref , get_mem (), get_real_key (ndx) , ndx);
827825 Dictionary dict (obj, col_key);
828826 dict.remove_backlinks (state);
829827 }
@@ -844,12 +842,12 @@ inline void Cluster::do_erase_key(size_t ndx, ColKey col_key, CascadeState& stat
844842 values.erase (ndx);
845843}
846844
847- size_t Cluster::get_ndx (ObjKey k, size_t ndx) const noexcept
845+ size_t Cluster::get_ndx (RowKey k, size_t ndx) const noexcept
848846{
849847 size_t index;
850848 if (m_keys.is_attached ()) {
851- index = m_keys.lower_bound (uint64_t ( k.value ) );
852- if (index == m_keys.size () || m_keys.get (index) != uint64_t ( k.value ) ) {
849+ index = m_keys.lower_bound (k.value );
850+ if (index == m_keys.size () || m_keys.get (index) != k.value ) {
853851 return realm::npos;
854852 }
855853 }
@@ -862,11 +860,14 @@ size_t Cluster::get_ndx(ObjKey k, size_t ndx) const noexcept
862860 return index + ndx;
863861}
864862
865- size_t Cluster::erase (ObjKey key , CascadeState& state)
863+ size_t Cluster::erase (RowKey row_key , CascadeState& state)
866864{
867- size_t ndx = get_ndx (key , 0 );
865+ size_t ndx = get_ndx (row_key , 0 );
868866 if (ndx == realm::npos)
869- throw KeyNotFound (util::format (" When erasing key '%1' in '%2'" , key.value , get_owning_table ()->get_name ()));
867+ throw KeyNotFound (util::format (" When erasing key '%1' (offset '%2') in '%3'" , row_key.value , m_offset,
868+ get_owning_table ()->get_name ()));
869+
870+ ObjKey real_key = get_real_key (ndx);
870871 std::vector<ColKey> backlink_column_keys;
871872
872873 auto erase_in_column = [&](ColKey col_key) {
@@ -883,7 +884,7 @@ size_t Cluster::erase(ObjKey key, CascadeState& state)
883884 const Table* origin_table = m_tree_top.get_owning_table ();
884885 if (attr.test (col_attr_Dictionary)) {
885886 if (col_type == col_type_Mixed || col_type == col_type_Link) {
886- Obj obj (origin_table->m_own_ref , get_mem (), key , ndx);
887+ Obj obj (origin_table->m_own_ref , get_mem (), real_key , ndx);
887888 Dictionary dict (obj, col_key);
888889 dict.remove_backlinks (state);
889890 }
@@ -892,7 +893,7 @@ size_t Cluster::erase(ObjKey key, CascadeState& state)
892893 BPlusTree<ObjKey> links (m_alloc);
893894 links.init_from_ref (ref);
894895 if (links.size () > 0 ) {
895- do_remove_backlinks (ObjKey (key. value + m_offset) , col_key, links.get_all (), state);
896+ do_remove_backlinks (real_key , col_key, links.get_all (), state);
896897 }
897898 }
898899 else if (col_type == col_type_TypedLink) {
@@ -903,11 +904,11 @@ size_t Cluster::erase(ObjKey key, CascadeState& state)
903904 auto target_obj = origin_table->get_parent_group ()->get_object (link);
904905 ColKey backlink_col_key =
905906 target_obj.get_table ()->find_backlink_column (col_key, origin_table->get_key ());
906- target_obj.remove_one_backlink (backlink_col_key, ObjKey (key. value + m_offset) );
907+ target_obj.remove_one_backlink (backlink_col_key, real_key );
907908 }
908909 }
909910 else if (col_type == col_type_Mixed) {
910- Obj obj (origin_table->m_own_ref , get_mem (), key , ndx);
911+ Obj obj (origin_table->m_own_ref , get_mem (), real_key , ndx);
911912 Lst<Mixed> list (obj, col_key);
912913 list.remove_backlinks (state);
913914 }
@@ -944,7 +945,7 @@ size_t Cluster::erase(ObjKey key, CascadeState& state)
944945 do_erase<ArrayBinary>(ndx, col_key);
945946 break ;
946947 case col_type_Mixed:
947- do_erase_mixed (ndx, col_key, key, state);
948+ do_erase_mixed (ndx, col_key, state);
948949 break ;
949950 case col_type_Timestamp:
950951 do_erase<ArrayTimestamp>(ndx, col_key);
@@ -1006,7 +1007,7 @@ size_t Cluster::erase(ObjKey key, CascadeState& state)
10061007 return node_size ();
10071008}
10081009
1009- void Cluster::nullify_incoming_links (ObjKey key, CascadeState& state)
1010+ void Cluster::nullify_incoming_links (RowKey key, CascadeState& state)
10101011{
10111012 size_t ndx = get_ndx (key, 0 );
10121013 if (ndx == realm::npos)
@@ -1574,7 +1575,7 @@ void Cluster::remove_backlinks(const Table* origin_table, ObjKey origin_key, Col
15741575 bool last_removed = target_obj.remove_one_backlink (backlink_col_key, origin_key); // Throws
15751576 if (is_unres) {
15761577 if (last_removed) {
1577- // Check is there are more backlinks
1578+ // Check if there are more backlinks
15781579 if (!target_obj.has_backlinks (false )) {
15791580 // Tombstones can be erased right away - there is no cascading effect
15801581 target_table->m_tombstones ->erase (link.get_obj_key (), state);
0 commit comments