From dee88fd7a310dcd77f6e27f3a5a66674ee27aa2c Mon Sep 17 00:00:00 2001
From: jbajic <jure.bajic@memgraph.com>
Date: Thu, 26 Jan 2023 14:26:24 +0100
Subject: [PATCH] Fix delta not cloning id

---
 src/storage/v3/delta.hpp              | 54 ++++++++++++---------------
 src/storage/v3/mvcc.hpp               |  6 +--
 src/storage/v3/splitter.cpp           |  9 +++--
 src/storage/v3/transaction.hpp        | 19 +++++-----
 tests/unit/storage_v3_shard_split.cpp | 50 +++++++++++++++++--------
 5 files changed, 76 insertions(+), 62 deletions(-)

diff --git a/src/storage/v3/delta.hpp b/src/storage/v3/delta.hpp
index 40bbb521d..c4ffc33e1 100644
--- a/src/storage/v3/delta.hpp
+++ b/src/storage/v3/delta.hpp
@@ -28,6 +28,11 @@ struct Edge;
 struct Delta;
 struct CommitInfo;
 
+inline uint64_t GetNextDeltaUUID() noexcept {
+  static uint64_t uuid{0};
+  return ++uuid;
+}
+
 // This class stores one of three pointers (`Delta`, `Vertex` and `Edge`)
 // without using additional memory for storing the type. The type is stored in
 // the pointer itself in the lower bits. All of those structures contain large
@@ -130,11 +135,6 @@ inline bool operator==(const PreviousPtr::Pointer &a, const PreviousPtr::Pointer
 
 inline bool operator!=(const PreviousPtr::Pointer &a, const PreviousPtr::Pointer &b) { return !(a == b); }
 
-inline uint64_t GetNextDeltaUUID() noexcept {
-  static uint64_t uuid{0};
-  return ++uuid;
-}
-
 struct Delta {
   enum class Action : uint8_t {
     // Used for both Vertex and Edge
@@ -164,62 +164,54 @@ struct Delta {
   struct RemoveInEdgeTag {};
   struct RemoveOutEdgeTag {};
 
-  Delta(DeleteObjectTag /*unused*/, CommitInfo *commit_info, uint64_t command_id)
-      : action(Action::DELETE_OBJECT), uuid(GetNextDeltaUUID()), commit_info(commit_info), command_id(command_id) {}
+  Delta(DeleteObjectTag /*unused*/, CommitInfo *commit_info, uint64_t delta_id, uint64_t command_id)
+      : action(Action::DELETE_OBJECT), uuid(delta_id), commit_info(commit_info), command_id(command_id) {}
 
-  Delta(RecreateObjectTag /*unused*/, CommitInfo *commit_info, uint64_t command_id)
-      : action(Action::RECREATE_OBJECT), uuid(GetNextDeltaUUID()), commit_info(commit_info), command_id(command_id) {}
+  Delta(RecreateObjectTag /*unused*/, CommitInfo *commit_info, uint64_t delta_id, uint64_t command_id)
+      : action(Action::RECREATE_OBJECT), uuid(delta_id), commit_info(commit_info), command_id(command_id) {}
 
-  Delta(AddLabelTag /*unused*/, LabelId label, CommitInfo *commit_info, uint64_t command_id)
-      : action(Action::ADD_LABEL),
-        uuid(GetNextDeltaUUID()),
-        commit_info(commit_info),
-        command_id(command_id),
-        label(label) {}
+  Delta(AddLabelTag /*unused*/, LabelId label, CommitInfo *commit_info, uint64_t delta_id, uint64_t command_id)
+      : action(Action::ADD_LABEL), uuid(delta_id), commit_info(commit_info), command_id(command_id), label(label) {}
 
-  Delta(RemoveLabelTag /*unused*/, LabelId label, CommitInfo *commit_info, uint64_t command_id)
-      : action(Action::REMOVE_LABEL),
-        uuid(GetNextDeltaUUID()),
-        commit_info(commit_info),
-        command_id(command_id),
-        label(label) {}
+  Delta(RemoveLabelTag /*unused*/, LabelId label, CommitInfo *commit_info, uint64_t delta_id, uint64_t command_id)
+      : action(Action::REMOVE_LABEL), uuid(delta_id), commit_info(commit_info), command_id(command_id), label(label) {}
 
   Delta(SetPropertyTag /*unused*/, PropertyId key, const PropertyValue &value, CommitInfo *commit_info,
-        uint64_t command_id)
+        uint64_t delta_id, uint64_t command_id)
       : action(Action::SET_PROPERTY),
-        uuid(GetNextDeltaUUID()),
+        uuid(delta_id),
         commit_info(commit_info),
         command_id(command_id),
         property({key, value}) {}
 
   Delta(AddInEdgeTag /*unused*/, EdgeTypeId edge_type, VertexId vertex_id, EdgeRef edge, CommitInfo *commit_info,
-        uint64_t command_id)
+        uint64_t delta_id, uint64_t command_id)
       : action(Action::ADD_IN_EDGE),
-        uuid(GetNextDeltaUUID()),
+        uuid(delta_id),
         commit_info(commit_info),
         command_id(command_id),
         vertex_edge({edge_type, std::move(vertex_id), edge}) {}
 
   Delta(AddOutEdgeTag /*unused*/, EdgeTypeId edge_type, VertexId vertex_id, EdgeRef edge, CommitInfo *commit_info,
-        uint64_t command_id)
+        uint64_t delta_id, uint64_t command_id)
       : action(Action::ADD_OUT_EDGE),
-        uuid(GetNextDeltaUUID()),
+        uuid(delta_id),
         commit_info(commit_info),
         command_id(command_id),
         vertex_edge({edge_type, std::move(vertex_id), edge}) {}
 
   Delta(RemoveInEdgeTag /*unused*/, EdgeTypeId edge_type, VertexId vertex_id, EdgeRef edge, CommitInfo *commit_info,
-        uint64_t command_id)
+        uint64_t delta_id, uint64_t command_id)
       : action(Action::REMOVE_IN_EDGE),
-        uuid(GetNextDeltaUUID()),
+        uuid(delta_id),
         commit_info(commit_info),
         command_id(command_id),
         vertex_edge({edge_type, std::move(vertex_id), edge}) {}
 
   Delta(RemoveOutEdgeTag /*unused*/, EdgeTypeId edge_type, VertexId vertex_id, EdgeRef edge, CommitInfo *commit_info,
-        uint64_t command_id)
+        uint64_t delta_id, uint64_t command_id)
       : action(Action::REMOVE_OUT_EDGE),
-        uuid(GetNextDeltaUUID()),
+        uuid(delta_id),
         commit_info(commit_info),
         command_id(command_id),
         vertex_edge({edge_type, std::move(vertex_id), edge}) {}
diff --git a/src/storage/v3/mvcc.hpp b/src/storage/v3/mvcc.hpp
index 6ce058d62..f4e4cb81e 100644
--- a/src/storage/v3/mvcc.hpp
+++ b/src/storage/v3/mvcc.hpp
@@ -1,4 +1,4 @@
-// Copyright 2022 Memgraph Ltd.
+// Copyright 2023 Memgraph Ltd.
 //
 // Use of this software is governed by the Business Source License
 // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -108,7 +108,7 @@ inline bool PrepareForWrite(Transaction *transaction, TObj *object) {
 /// a `DELETE_OBJECT` delta).
 /// @throw std::bad_alloc
 inline Delta *CreateDeleteObjectDelta(Transaction *transaction) {
-  return &transaction->deltas.emplace_back(Delta::DeleteObjectTag(), transaction->commit_info.get(),
+  return &transaction->deltas.emplace_back(Delta::DeleteObjectTag(), transaction->commit_info.get(), GetNextDeltaUUID(),
                                            transaction->command_id);
 }
 
@@ -119,7 +119,7 @@ template <typename TObj, class... Args>
 requires utils::SameAsAnyOf<TObj, Edge, Vertex>
 inline void CreateAndLinkDelta(Transaction *transaction, TObj *object, Args &&...args) {
   auto delta = &transaction->deltas.emplace_back(std::forward<Args>(args)..., transaction->commit_info.get(),
-                                                 transaction->command_id);
+                                                 GetNextDeltaUUID(), transaction->command_id);
   auto *delta_holder = GetDeltaHolder(object);
 
   // The operations are written in such order so that both `next` and `prev`
diff --git a/src/storage/v3/splitter.cpp b/src/storage/v3/splitter.cpp
index c57de0f6e..375d3aa60 100644
--- a/src/storage/v3/splitter.cpp
+++ b/src/storage/v3/splitter.cpp
@@ -181,16 +181,19 @@ void Splitter::AdjustClonedTransaction(Transaction &cloned_transaction, const Tr
   // NOTE It is important that the order of delta lists is in same order
   auto delta_it = transaction.deltas.begin();
   auto cloned_delta_it = cloned_transaction.deltas.begin();
-  while (delta_it != transaction.deltas.end() && cloned_delta_it != cloned_transaction.deltas.end()) {
+  while (delta_it != transaction.deltas.end()) {
     const auto *delta = &*delta_it;
     auto *cloned_delta = &*cloned_delta_it;
     while (delta != nullptr) {
       // Align deltas which belong to cloned transaction, skip others
       if (cloned_transactions.contains(delta->commit_info->start_or_commit_timestamp.logical_id)) {
-        auto *found_delta_it = &*std::ranges::find_if(
+        const auto end_it =
+            cloned_transactions.at(delta->commit_info->start_or_commit_timestamp.logical_id)->deltas.end();
+        auto found_delta_it = std::ranges::find_if(
             cloned_transactions.at(delta->commit_info->start_or_commit_timestamp.logical_id)->deltas,
             [delta](const auto &elem) { return elem.uuid == delta->uuid; });
-        MG_ASSERT(found_delta_it, "Delta with given uuid must exist!");
+        MG_ASSERT(found_delta_it != end_it, "Delta with given uuid must exist!");
+
         cloned_delta->next = &*found_delta_it;
       } else {
         delta = delta->next;
diff --git a/src/storage/v3/transaction.hpp b/src/storage/v3/transaction.hpp
index 9b13d9c7b..66269e935 100644
--- a/src/storage/v3/transaction.hpp
+++ b/src/storage/v3/transaction.hpp
@@ -69,36 +69,37 @@ struct Transaction {
     for (const auto &delta : deltas) {
       switch (delta.action) {
         case Delta::Action::DELETE_OBJECT:
-          copied_deltas.emplace_back(Delta::DeleteObjectTag{}, commit_info, command_id);
+          copied_deltas.emplace_back(Delta::DeleteObjectTag{}, commit_info, delta.uuid, command_id);
           break;
         case Delta::Action::RECREATE_OBJECT:
-          copied_deltas.emplace_back(Delta::RecreateObjectTag{}, commit_info, command_id);
+          copied_deltas.emplace_back(Delta::RecreateObjectTag{}, commit_info, delta.uuid, command_id);
           break;
         case Delta::Action::ADD_LABEL:
-          copied_deltas.emplace_back(Delta::AddLabelTag{}, delta.label, commit_info, command_id);
+          copied_deltas.emplace_back(Delta::AddLabelTag{}, delta.label, commit_info, delta.uuid, command_id);
           break;
         case Delta::Action::REMOVE_LABEL:
-          copied_deltas.emplace_back(Delta::RemoveLabelTag{}, delta.label, commit_info, command_id);
+          copied_deltas.emplace_back(Delta::RemoveLabelTag{}, delta.label, commit_info, delta.uuid, command_id);
           break;
         case Delta::Action::ADD_IN_EDGE:
           copied_deltas.emplace_back(Delta::AddInEdgeTag{}, delta.vertex_edge.edge_type, delta.vertex_edge.vertex_id,
-                                     delta.vertex_edge.edge, commit_info, command_id);
+                                     delta.vertex_edge.edge, commit_info, delta.uuid, command_id);
           break;
         case Delta::Action::ADD_OUT_EDGE:
           copied_deltas.emplace_back(Delta::AddOutEdgeTag{}, delta.vertex_edge.edge_type, delta.vertex_edge.vertex_id,
-                                     delta.vertex_edge.edge, commit_info, command_id);
+                                     delta.vertex_edge.edge, commit_info, delta.uuid, command_id);
           break;
         case Delta::Action::REMOVE_IN_EDGE:
           copied_deltas.emplace_back(Delta::RemoveInEdgeTag{}, delta.vertex_edge.edge_type, delta.vertex_edge.vertex_id,
-                                     delta.vertex_edge.edge, commit_info, command_id);
+                                     delta.vertex_edge.edge, commit_info, delta.uuid, command_id);
           break;
         case Delta::Action::REMOVE_OUT_EDGE:
           copied_deltas.emplace_back(Delta::RemoveOutEdgeTag{}, delta.vertex_edge.edge_type,
-                                     delta.vertex_edge.vertex_id, delta.vertex_edge.edge, commit_info, command_id);
+                                     delta.vertex_edge.vertex_id, delta.vertex_edge.edge, commit_info, delta.uuid,
+                                     command_id);
           break;
         case Delta::Action::SET_PROPERTY:
           copied_deltas.emplace_back(Delta::SetPropertyTag{}, delta.property.key, delta.property.value, commit_info,
-                                     command_id);
+                                     delta.uuid, command_id);
           break;
       }
     }
diff --git a/tests/unit/storage_v3_shard_split.cpp b/tests/unit/storage_v3_shard_split.cpp
index fd32eb0ef..5878ec0ce 100644
--- a/tests/unit/storage_v3_shard_split.cpp
+++ b/tests/unit/storage_v3_shard_split.cpp
@@ -83,7 +83,9 @@ void AssertEqVertexContainer(const VertexContainer &actual, const VertexContaine
     auto *expected_delta = expected_it->second.delta;
     auto *actual_delta = actual_it->second.delta;
     while (expected_delta != nullptr) {
+      // TODO Enable this then fix delta id generator
       EXPECT_EQ(actual_delta->action, expected_delta->action);
+      // EXPECT_EQ(actual_delta->uuid, expected_delta->uuid);
       switch (expected_delta->action) {
         case Delta::Action::ADD_LABEL:
         case Delta::Action::REMOVE_LABEL: {
@@ -146,18 +148,19 @@ TEST_F(ShardSplitTest, TestBasicSplitWithVertices) {
   EXPECT_EQ(splitted_data.label_property_indices.size(), 0);
 
   CommitInfo commit_info{.start_or_commit_timestamp = current_hlc};
-  Delta delta_delete1{Delta::DeleteObjectTag{}, &commit_info, 1};
-  Delta delta_delete2{Delta::DeleteObjectTag{}, &commit_info, 2};
-  Delta delta_delete3{Delta::DeleteObjectTag{}, &commit_info, 3};
-  Delta delta_add_label{Delta::RemoveLabelTag{}, secondary_label, &commit_info, 4};
-  Delta delta_add_property{Delta::SetPropertyTag{}, secondary_property, PropertyValue(), &commit_info, 4};
+  Delta delta_delete1{Delta::DeleteObjectTag{}, &commit_info, 5, 1};
+  Delta delta_delete2{Delta::DeleteObjectTag{}, &commit_info, 6, 2};
+  Delta delta_remove_label{Delta::RemoveLabelTag{}, secondary_label, &commit_info, 8, 4};
+  Delta delta_set_property{Delta::SetPropertyTag{}, secondary_property, PropertyValue(), &commit_info, 7, 4};
+  Delta delta_delete3{Delta::DeleteObjectTag{}, &commit_info, 9, 3};
+
   VertexContainer expected_vertices;
   expected_vertices.emplace(PrimaryKey{PropertyValue{4}}, VertexData(&delta_delete1));
   auto [it, inserted] = expected_vertices.emplace(PrimaryKey{PropertyValue{5}}, VertexData(&delta_delete2));
   expected_vertices.emplace(PrimaryKey{PropertyValue{6}}, VertexData(&delta_delete3));
   it->second.labels.push_back(secondary_label);
-  AddDeltaToDeltaChain(&*it, &delta_add_property);
-  AddDeltaToDeltaChain(&*it, &delta_add_label);
+  AddDeltaToDeltaChain(&*it, &delta_set_property);
+  AddDeltaToDeltaChain(&*it, &delta_remove_label);
 
   AssertEqVertexContainer(splitted_data.vertices, expected_vertices);
 }
@@ -189,15 +192,30 @@ TEST_F(ShardSplitTest, TestBasicSplitVerticesAndEdges) {
   EXPECT_EQ(splitted_data.label_property_indices.size(), 0);
 
   CommitInfo commit_info{.start_or_commit_timestamp = current_hlc};
-  Delta delta_delete1{Delta::DeleteObjectTag{}, &commit_info, 1};
-  Delta delta_delete2{Delta::DeleteObjectTag{}, &commit_info, 1};
-  Delta delta_delete3{Delta::DeleteObjectTag{}, &commit_info, 1};
-  Delta delta_add_in_edge1{Delta::RemoveInEdgeTag{},  edge_type_id, VertexId{primary_label, {PropertyValue(1)}},
-                           EdgeRef{Gid::FromUint(1)}, &commit_info, 1};
-  Delta delta_add_out_edge2{Delta::RemoveOutEdgeTag{}, edge_type_id, VertexId{primary_label, {PropertyValue(6)}},
-                            EdgeRef{Gid::FromUint(2)}, &commit_info, 1};
-  Delta delta_add_in_edge2{Delta::RemoveInEdgeTag{},  edge_type_id, VertexId{primary_label, {PropertyValue(4)}},
-                           EdgeRef{Gid::FromUint(2)}, &commit_info, 1};
+  Delta delta_delete1{Delta::DeleteObjectTag{}, &commit_info, 3, 1};
+  Delta delta_delete2{Delta::DeleteObjectTag{}, &commit_info, 4, 1};
+  Delta delta_delete3{Delta::DeleteObjectTag{}, &commit_info, 5, 1};
+  Delta delta_add_in_edge1{Delta::RemoveInEdgeTag{},
+                           edge_type_id,
+                           VertexId{primary_label, {PropertyValue(1)}},
+                           EdgeRef{Gid::FromUint(1)},
+                           &commit_info,
+                           13,
+                           1};
+  Delta delta_add_out_edge2{Delta::RemoveOutEdgeTag{},
+                            edge_type_id,
+                            VertexId{primary_label, {PropertyValue(6)}},
+                            EdgeRef{Gid::FromUint(2)},
+                            &commit_info,
+                            20,
+                            1};
+  Delta delta_add_in_edge2{Delta::RemoveInEdgeTag{},
+                           edge_type_id,
+                           VertexId{primary_label, {PropertyValue(4)}},
+                           EdgeRef{Gid::FromUint(2)},
+                           &commit_info,
+                           15,
+                           1};
   VertexContainer expected_vertices;
   auto [vtx4, inserted4] = expected_vertices.emplace(PrimaryKey{PropertyValue{4}}, VertexData(&delta_delete1));
   auto [vtx5, inserted5] = expected_vertices.emplace(PrimaryKey{PropertyValue{5}}, VertexData(&delta_delete2));