From c3bfd3004b765af9ddae72266e61257a1080536f Mon Sep 17 00:00:00 2001
From: Matej Ferencevic <matej.ferencevic@memgraph.io>
Date: Wed, 15 Jan 2020 10:13:48 +0100
Subject: [PATCH] Reduce memory allocations in indices

Reviewers: teon.banek

Reviewed By: teon.banek

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D2621
---
 src/storage/v2/indices.cpp | 101 ++++++++++++++++++-------------------
 src/storage/v2/indices.hpp |   7 ---
 src/storage/v2/storage.hpp |   5 --
 3 files changed, 50 insertions(+), 63 deletions(-)

diff --git a/src/storage/v2/indices.cpp b/src/storage/v2/indices.cpp
index a056d585f..cc4936deb 100644
--- a/src/storage/v2/indices.cpp
+++ b/src/storage/v2/indices.cpp
@@ -83,12 +83,11 @@ bool AnyVersionHasLabel(const Vertex &vertex, LabelId label,
 /// Helper function for label-property index garbage collection. Returns true if
 /// there's a reachable version of the vertex that has the given label and
 /// property value.
-/// @throw std::bad_alloc if unable to copy the PropertyValue
 bool AnyVersionHasLabelProperty(const Vertex &vertex, LabelId label,
                                 PropertyId key, const PropertyValue &value,
                                 uint64_t timestamp) {
   bool has_label;
-  PropertyValue current_value;
+  bool current_value_equal_to_value = value.IsNull();
   bool deleted;
   const Delta *delta;
   {
@@ -96,20 +95,20 @@ bool AnyVersionHasLabelProperty(const Vertex &vertex, LabelId label,
     has_label = utils::Contains(vertex.labels, label);
     auto it = vertex.properties.find(key);
     if (it != vertex.properties.end()) {
-      current_value = it->second;
+      current_value_equal_to_value = it->second == value;
     }
     deleted = vertex.deleted;
     delta = vertex.delta;
   }
 
-  if (!deleted && has_label && current_value == value) {
+  if (!deleted && has_label && current_value_equal_to_value) {
     return true;
   }
 
   return AnyVersionSatisfiesPredicate(
       timestamp, delta,
-      [&has_label, &current_value, &deleted, label, key,
-       value](const Delta &delta) {
+      [&has_label, &current_value_equal_to_value, &deleted, label, key,
+       &value](const Delta &delta) {
         switch (delta.action) {
           case Delta::Action::ADD_LABEL:
             if (delta.label == label) {
@@ -125,7 +124,7 @@ bool AnyVersionHasLabelProperty(const Vertex &vertex, LabelId label,
             break;
           case Delta::Action::SET_PROPERTY:
             if (delta.property.key == key) {
-              current_value = delta.property.value;
+              current_value_equal_to_value = delta.property.value == value;
             }
             break;
           case Delta::Action::RECREATE_OBJECT: {
@@ -144,7 +143,7 @@ bool AnyVersionHasLabelProperty(const Vertex &vertex, LabelId label,
           case Delta::Action::REMOVE_OUT_EDGE:
             break;
         }
-        return !deleted && has_label && current_value == value;
+        return !deleted && has_label && current_value_equal_to_value;
       });
 }
 
@@ -203,13 +202,12 @@ bool CurrentVersionHasLabel(const Vertex &vertex, LabelId label,
 // Helper function for iterating through label-property index. Returns true if
 // this transaction can see the given vertex, and the visible version has the
 // given label and property.
-// @throw std::bad_alloc if unable to copy the PropertyValue
 bool CurrentVersionHasLabelProperty(const Vertex &vertex, LabelId label,
                                     PropertyId key, const PropertyValue &value,
                                     Transaction *transaction, View view) {
   bool deleted;
   bool has_label;
-  PropertyValue current_value;
+  bool current_value_equal_to_value = value.IsNull();
   const Delta *delta;
   {
     std::lock_guard<utils::SpinLock> guard(vertex.lock);
@@ -217,50 +215,51 @@ bool CurrentVersionHasLabelProperty(const Vertex &vertex, LabelId label,
     has_label = utils::Contains(vertex.labels, label);
     auto it = vertex.properties.find(key);
     if (it != vertex.properties.end()) {
-      current_value = it->second;
+      current_value_equal_to_value = it->second == value;
     }
     delta = vertex.delta;
   }
-  ApplyDeltasForRead(
-      transaction, delta, view,
-      [&deleted, &has_label, &current_value, key, label](const Delta &delta) {
-        switch (delta.action) {
-          case Delta::Action::SET_PROPERTY: {
-            if (delta.property.key == key) {
-              current_value = delta.property.value;
-            }
-            break;
-          }
-          case Delta::Action::DELETE_OBJECT: {
-            CHECK(!deleted) << "Invalid database state!";
-            deleted = true;
-            break;
-          }
-          case Delta::Action::RECREATE_OBJECT: {
-            CHECK(deleted) << "Invalid database state!";
-            deleted = false;
-            break;
-          }
-          case Delta::Action::ADD_LABEL:
-            if (delta.label == label) {
-              CHECK(!has_label) << "Invalid database state!";
-              has_label = true;
-            }
-            break;
-          case Delta::Action::REMOVE_LABEL:
-            if (delta.label == label) {
-              CHECK(has_label) << "Invalid database state!";
-              has_label = false;
-            }
-            break;
-          case Delta::Action::ADD_IN_EDGE:
-          case Delta::Action::ADD_OUT_EDGE:
-          case Delta::Action::REMOVE_IN_EDGE:
-          case Delta::Action::REMOVE_OUT_EDGE:
-            break;
-        }
-      });
-  return !deleted && has_label && current_value == value;
+  ApplyDeltasForRead(transaction, delta, view,
+                     [&deleted, &has_label, &current_value_equal_to_value, key,
+                      label, &value](const Delta &delta) {
+                       switch (delta.action) {
+                         case Delta::Action::SET_PROPERTY: {
+                           if (delta.property.key == key) {
+                             current_value_equal_to_value =
+                                 delta.property.value == value;
+                           }
+                           break;
+                         }
+                         case Delta::Action::DELETE_OBJECT: {
+                           CHECK(!deleted) << "Invalid database state!";
+                           deleted = true;
+                           break;
+                         }
+                         case Delta::Action::RECREATE_OBJECT: {
+                           CHECK(deleted) << "Invalid database state!";
+                           deleted = false;
+                           break;
+                         }
+                         case Delta::Action::ADD_LABEL:
+                           if (delta.label == label) {
+                             CHECK(!has_label) << "Invalid database state!";
+                             has_label = true;
+                           }
+                           break;
+                         case Delta::Action::REMOVE_LABEL:
+                           if (delta.label == label) {
+                             CHECK(has_label) << "Invalid database state!";
+                             has_label = false;
+                           }
+                           break;
+                         case Delta::Action::ADD_IN_EDGE:
+                         case Delta::Action::ADD_OUT_EDGE:
+                         case Delta::Action::REMOVE_IN_EDGE:
+                         case Delta::Action::REMOVE_OUT_EDGE:
+                           break;
+                       }
+                     });
+  return !deleted && has_label && current_value_equal_to_value;
 }
 
 }  // namespace
diff --git a/src/storage/v2/indices.hpp b/src/storage/v2/indices.hpp
index 111b11bb8..7c312bd23 100644
--- a/src/storage/v2/indices.hpp
+++ b/src/storage/v2/indices.hpp
@@ -165,12 +165,10 @@ class LabelPropertyIndex {
 
   std::vector<std::pair<LabelId, PropertyId>> ListIndices() const;
 
-  /// @throw std::bad_alloc if unable to copy a PropertyValue
   void RemoveObsoleteEntries(uint64_t oldest_active_start_timestamp);
 
   class Iterable {
    public:
-    /// @throw std::bad_alloc if unable to copy a PropertyValue
     Iterable(utils::SkipList<Entry>::Accessor index_accessor, LabelId label,
              PropertyId property,
              const std::optional<utils::Bound<PropertyValue>> &lower_bound,
@@ -180,7 +178,6 @@ class LabelPropertyIndex {
 
     class Iterator {
      public:
-      /// @throw std::bad_alloc raised in AdvanceUntilValid
       Iterator(Iterable *self, utils::SkipList<Entry>::Iterator index_iterator);
 
       VertexAccessor operator*() const { return current_vertex_accessor_; }
@@ -192,11 +189,9 @@ class LabelPropertyIndex {
         return index_iterator_ != other.index_iterator_;
       }
 
-      /// @throw std::bad_alloc raised in AdvanceUntilValid
       Iterator &operator++();
 
      private:
-      /// @throw std::bad_alloc if unable to copy a PropertyValue
       void AdvanceUntilValid();
 
       Iterable *self_;
@@ -221,7 +216,6 @@ class LabelPropertyIndex {
     Config::Items config_;
   };
 
-  /// @throw std::bad_alloc if unable to copy a PropertyValue
   Iterable Vertices(
       LabelId label, PropertyId property,
       const std::optional<utils::Bound<PropertyValue>> &lower_bound,
@@ -276,7 +270,6 @@ struct Indices {
 
 /// This function should be called from garbage collection to clean-up the
 /// index.
-/// @throw std::bad_alloc raised in LabelPropertyIndex::RemoveObsoleteEntries
 void RemoveObsoleteEntries(Indices *indices,
                            uint64_t oldest_active_start_timestamp);
 
diff --git a/src/storage/v2/storage.hpp b/src/storage/v2/storage.hpp
index 11f5804fb..dcdaae278 100644
--- a/src/storage/v2/storage.hpp
+++ b/src/storage/v2/storage.hpp
@@ -124,8 +124,6 @@ class VerticesIterable final {
 
     VertexAccessor operator*() const;
 
-    /// @throw std::bad_alloc raised in
-    ///        LabelPropertyIndex::Iterable::Iterator::operator++
     Iterator &operator++();
 
     bool operator==(const Iterator &other) const;
@@ -195,14 +193,11 @@ class Storage final {
 
     VerticesIterable Vertices(LabelId label, View view);
 
-    /// @throw std::bad_alloc raised in Index::Vertices
     VerticesIterable Vertices(LabelId label, PropertyId property, View view);
 
-    /// @throw std::bad_alloc raised in Index::Vertices
     VerticesIterable Vertices(LabelId label, PropertyId property,
                               const PropertyValue &value, View view);
 
-    /// @throw std::bad_alloc raised in Index::Vertices
     VerticesIterable Vertices(
         LabelId label, PropertyId property,
         const std::optional<utils::Bound<PropertyValue>> &lower_bound,