From e7953fc7e0068e44eef9705d05f40d726bae4ed7 Mon Sep 17 00:00:00 2001
From: Marko Budiselic <mbudiselicbuda@gmail.com>
Date: Sat, 21 Nov 2015 16:08:23 +0100
Subject: [PATCH 1/3] TotalOrdering and Id implementations, related to T28

---
 examples/.gitignore      |  1 +
 examples/id.cpp          | 41 ++++++++++++++++++++++++++++++++++++++++
 mvcc/id.hpp              | 29 ++++++++++++++++++++++++++++
 utils/total_ordering.hpp | 13 +++++++++++--
 4 files changed, 82 insertions(+), 2 deletions(-)
 create mode 100644 examples/.gitignore
 create mode 100644 examples/id.cpp
 create mode 100644 mvcc/id.hpp

diff --git a/examples/.gitignore b/examples/.gitignore
new file mode 100644
index 000000000..f47cb2045
--- /dev/null
+++ b/examples/.gitignore
@@ -0,0 +1 @@
+*.out
diff --git a/examples/id.cpp b/examples/id.cpp
new file mode 100644
index 000000000..9919109e9
--- /dev/null
+++ b/examples/id.cpp
@@ -0,0 +1,41 @@
+#include <iostream>
+
+#include "mvcc/id.hpp"
+
+using std::cout;
+using std::endl;
+
+int main() {
+    
+    Id id0(0);
+    Id id1(1);
+    Id id2(1);
+    Id id3(id2);
+    Id id4 = id3;
+    Id id5(5);
+
+    cout << id5 << " " << id0 << endl;
+
+    if (id0 < id5)
+        cout << "id0 < id5" << endl;
+
+    if (id1 == id2)
+        cout << "are equal" << endl;
+
+    if (id3 == id4)
+        cout << "id3 == id4" << endl;
+
+    if (id5 > id0)
+        cout << "id5 > id0" << endl;
+
+    if (id5 != id3)
+        cout << "id5 != id3" << endl;
+
+    if (id1 >= id2)
+        cout << "id1 >= id2" << endl;
+
+    if (id3 <= id4)
+        cout << "id3 <= id4" << endl;
+
+    return 0;
+}
diff --git a/mvcc/id.hpp b/mvcc/id.hpp
new file mode 100644
index 000000000..4d5e6d23a
--- /dev/null
+++ b/mvcc/id.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <ostream>
+#include <stdint.h>
+#include "utils/total_ordering.hpp"
+
+class Id : public TotalOrdering<Id>
+{
+public:
+    Id(uint64_t id) : id(id) {}
+
+    friend bool operator<(const Id& a, const Id& b)
+    {
+        return a.id < b.id;
+    }
+
+    friend bool operator==(const Id& a, const Id& b)
+    {
+        return a.id == b.id;
+    }
+
+    friend std::ostream& operator<<(std::ostream& stream, const Id& id)
+    {
+        return stream << id.id;
+    }
+    
+private:
+    uint64_t id;
+};
diff --git a/utils/total_ordering.hpp b/utils/total_ordering.hpp
index 6272c56a9..09651cf23 100644
--- a/utils/total_ordering.hpp
+++ b/utils/total_ordering.hpp
@@ -8,9 +8,18 @@ struct TotalOrdering
         return !(a == b);
     }
 
-    friend bool operator>(const Derived& a, const Derived& b)
+    friend bool operator<=(const Derived& a, const Derived& b)
     {
-        return !(a == b);
+        return a < b || a == b;
     }
 
+    friend bool operator>(const Derived& a, const Derived& b)
+    {
+        return !(a <= b);
+    }
+
+    friend bool operator>=(const Derived& a, const Derived& b)
+    {
+        return !(a < b);
+    }
 };

From aeb8586bfd3e4b0a5ca6273edc13c957fcae0429 Mon Sep 17 00:00:00 2001
From: Marko Budiselic <mbudiselicbuda@gmail.com>
Date: Sat, 21 Nov 2015 19:16:19 +0100
Subject: [PATCH 2/3] uint64_t was replaced with the Id object. Fixes T28.

---
 api/resources/node.hpp       |  2 +-
 cypher/lexer.hpp             |  5 +----
 mvcc/atom.hpp                | 11 ++++-------
 mvcc/id.hpp                  |  9 ++++++++-
 mvcc/mvcc.hpp                | 15 ++++++---------
 storage/graph.hpp            |  7 ++-----
 storage/vertex.hpp           |  4 +---
 transactions/commit_log.hpp  | 13 +++++++------
 transactions/engine.hpp      | 20 +++++++-------------
 transactions/snapshot.hpp    | 29 +++++++++++++++++++++++++----
 transactions/transaction.hpp | 12 +++++-------
 11 files changed, 67 insertions(+), 60 deletions(-)

diff --git a/api/resources/node.hpp b/api/resources/node.hpp
index 3d8fd5034..3f1a1fa69 100644
--- a/api/resources/node.hpp
+++ b/api/resources/node.hpp
@@ -69,7 +69,7 @@ public:
     {
         task->run([this, &req]() -> Vertex* {
             // read id param
-            uint64_t id = std::stoull(req.params[0]); 
+            Id id(std::stoull(req.params[0])); 
             // TODO: transaction?
             return db->graph.find_vertex(id);
         },
diff --git a/cypher/lexer.hpp b/cypher/lexer.hpp
index cec017f5b..82481f470 100644
--- a/cypher/lexer.hpp
+++ b/cypher/lexer.hpp
@@ -1,5 +1,4 @@
-#ifndef MEMGRAPH_CYPHER_LEXER_HPP
-#define MEMGRAPH_CYPHER_LEXER_HPP
+#pragma once
 
 #include <cstdint>
 
@@ -59,5 +58,3 @@ protected:
     lexertl::rules rules;
     lexertl::state_machine sm;
 };
-
-#endif
diff --git a/mvcc/atom.hpp b/mvcc/atom.hpp
index b19b38b8b..75f20dadc 100644
--- a/mvcc/atom.hpp
+++ b/mvcc/atom.hpp
@@ -1,8 +1,7 @@
-#ifndef MEMGRAPH_MVCC_ATOM_HPP
-#define MEMGRAPH_MVCC_ATOM_HPP
+#pragma once
 
+#include "mvcc/id.hpp"
 #include "threading/sync/lockable.hpp"
-
 #include "transactions/transaction.hpp"
 #include "version.hpp"
 
@@ -14,7 +13,7 @@ class Atom : public Version<T>,
              public Lockable<SpinLock>
 {
 public:
-    Atom(uint64_t id, T* first) : Version<T>(first), id(id)
+    Atom(const Id& id, T* first) : Version<T>(first), id(id)
     {
         // it's illegal that the first version is nullptr. there should be at
         // least one version of a record
@@ -36,11 +35,9 @@ public:
     // every record has a unique id. 2^64 = 1.8 x 10^19. that should be enough
     // for a looong time :) but keep in mind that some vacuuming would be nice
     // to reuse indices for deleted nodes.
-    uint64_t id;
+    Id id;
 
     std::atomic<Atom<T>*> next;
 };
 
 }
-
-#endif
diff --git a/mvcc/id.hpp b/mvcc/id.hpp
index 4d5e6d23a..f0aaaf252 100644
--- a/mvcc/id.hpp
+++ b/mvcc/id.hpp
@@ -7,6 +7,8 @@
 class Id : public TotalOrdering<Id>
 {
 public:
+    Id() = default;
+
     Id(uint64_t id) : id(id) {}
 
     friend bool operator<(const Id& a, const Id& b)
@@ -23,7 +25,12 @@ public:
     {
         return stream << id.id;
     }
+
+    operator uint64_t() const
+    {
+        return id;
+    }
     
 private:
-    uint64_t id;
+    uint64_t id {0};
 };
diff --git a/mvcc/mvcc.hpp b/mvcc/mvcc.hpp
index 5c5ad007f..c35248ad0 100644
--- a/mvcc/mvcc.hpp
+++ b/mvcc/mvcc.hpp
@@ -1,11 +1,10 @@
-#ifndef MEMGRAPH_STORAGE_MODEL_UTILS_MVCC_HPP
-#define MEMGRAPH_STORAGE_MODEL_UTILS_MVCC_HPP
+#pragma once
 
 #include <atomic>
 
 #include "transactions/transaction.hpp"
 #include "transactions/commit_log.hpp"
-
+#include "mvcc/id.hpp"
 #include "minmax.hpp"
 #include "version.hpp"
 #include "hints.hpp"
@@ -26,7 +25,7 @@ public:
     // and tx.max is the id of the transaction that deleted the record
     // these values are used to determine the visibility of the record
     // to the current transaction
-    MinMax<uint64_t> tx;
+    MinMax<Id> tx;
 
     // cmd.min is the id of the command in this transaction that created the
     // record and cmd.max is the id of the command in this transaction that
@@ -94,18 +93,18 @@ public:
 protected:
     Hints hints;
 
-    bool max_committed(uint64_t id, const tx::Transaction& t)
+    bool max_committed(const Id& id, const tx::Transaction& t)
     {
         return committed(hints.max, id, t);
     }
 
-    bool min_committed(uint64_t id, const tx::Transaction& t)
+    bool min_committed(const Id& id, const tx::Transaction& t)
     {
         return committed(hints.min, id, t);
     }
 
     template <class U>
-    bool committed(U& hints, uint64_t id, const tx::Transaction& t)
+    bool committed(U& hints, const Id& id, const tx::Transaction& t)
     {
         auto hint_bits = hints.load();
 
@@ -135,5 +134,3 @@ protected:
 };
 
 }
-
-#endif
diff --git a/storage/graph.hpp b/storage/graph.hpp
index a2377fb58..18e81b12b 100644
--- a/storage/graph.hpp
+++ b/storage/graph.hpp
@@ -1,5 +1,4 @@
-#ifndef MEMGRAPH_STORAGE_GRAPH_HPP
-#define MEMGRAPH_STORAGE_GRAPH_HPP
+#pragma once
 
 #include <list>
 
@@ -39,7 +38,7 @@ public:
     }
 
     // TODO: this should probably return mvcc::Atom<Vertex>*
-    Vertex* find_vertex(uint64_t id)
+    Vertex* find_vertex(const Id& id)
     {
         // get atom iterator
         auto atom_it = vertices.begin();
@@ -62,5 +61,3 @@ public:
     VertexStore vertices;
     EdgeStore edges;
 };
-
-#endif
diff --git a/storage/vertex.hpp b/storage/vertex.hpp
index bcf3ad7b3..372c0d1a3 100644
--- a/storage/vertex.hpp
+++ b/storage/vertex.hpp
@@ -1,5 +1,4 @@
-#ifndef MEMGRAPH_STORAGE_VERTEX_HPP
-#define MEMGRAPH_STORAGE_VERTEX_HPP
+#pragma once
 
 #include <vector>
 
@@ -42,4 +41,3 @@ inline std::string properties_to_string(Vertex* vertex)
     // respond to the use with the buffer
     return std::move(buffer.str());
 }
-#endif
diff --git a/transactions/commit_log.hpp b/transactions/commit_log.hpp
index b5f6b5373..0f5b08d25 100644
--- a/transactions/commit_log.hpp
+++ b/transactions/commit_log.hpp
@@ -1,6 +1,7 @@
 #ifndef MEMGRAPH_TRANSACTIONS_COMMIT_LOG_HPP
 #define MEMGRAPH_TRANSACTIONS_COMMIT_LOG_HPP
 
+#include "mvcc/id.hpp"
 #include "data_structures/bitset/dynamic_bitset.hpp"
 
 namespace tx
@@ -53,32 +54,32 @@ public:
         return log;
     }
 
-    Info fetch_info(uint64_t id)
+    Info fetch_info(const Id& id)
     {
         return Info { log.at(2 * id, 2) };
     }
 
-    bool is_active(uint64_t id)
+    bool is_active(const Id& id)
     {
         return fetch_info(id).is_active();
     }
 
-    bool is_committed(uint64_t id)
+    bool is_committed(const Id& id)
     {
         return fetch_info(id).is_committed();
     }
 
-    void set_committed(uint64_t id)
+    void set_committed(const Id& id)
     {
         log.set(2 * id);
     }
 
-    bool is_aborted(uint64_t id)
+    bool is_aborted(const Id& id)
     {
         return fetch_info(id).is_aborted();
     }
 
-    void set_aborted(uint64_t id)
+    void set_aborted(const Id& id)
     {
         log.set(2 * id + 1);
     }
diff --git a/transactions/engine.hpp b/transactions/engine.hpp
index a7929bc29..efe8be1ad 100644
--- a/transactions/engine.hpp
+++ b/transactions/engine.hpp
@@ -1,5 +1,4 @@
-#ifndef MEMGRAPH_TRANSACTIONS_ENGINE_HPP
-#define MEMGRAPH_TRANSACTIONS_ENGINE_HPP
+#pragma once
 
 #include <atomic>
 #include <vector>
@@ -33,16 +32,16 @@ public:
     {
         auto guard = this->acquire_unique();
 
-        auto id = counter.next();
+        auto id = Id(counter.next());
         auto t = new Transaction(id, active);
 
-        active.push_back(id);
+        active.insert(id);
         cache.put(id, t);
 
         return *t;
     }
 
-    const Transaction& advance(uint64_t id)
+    const Transaction& advance(const Id& id)
     {
         auto guard = this->acquire_unique();
 
@@ -73,7 +72,7 @@ public:
         finalize(t);
     }
 
-    uint64_t last_known_active()
+    Id last_known_active()
     {
         auto guard = this->acquire_unique();
         return active.front();
@@ -96,20 +95,15 @@ public:
 private:
     void finalize(const Transaction& t)
     {
-        // remove transaction from the active transactions list
-        auto last = std::remove(active.begin(), active.end(), t.id);
-        active.erase(last, active.end());
+        active.remove(t.id);
 
         // remove transaction from cache
         cache.del(t.id);
     }
 
     SimpleCounter<uint64_t> counter;
-
-    std::vector<uint64_t> active;
+    Snapshot<Id> active;
     TransactionCache<uint64_t> cache;
 };
 
 }
-
-#endif
diff --git a/transactions/snapshot.hpp b/transactions/snapshot.hpp
index 7c72e8882..8c558b3e6 100644
--- a/transactions/snapshot.hpp
+++ b/transactions/snapshot.hpp
@@ -1,5 +1,4 @@
-#ifndef MEMGRAPH_TRANSACTIONS_SNAPSHOT_HPP
-#define MEMGRAPH_TRANSACTIONS_SNAPSHOT_HPP
+#pragma once
 
 #include <vector>
 #include <algorithm>
@@ -11,6 +10,8 @@ template <class id_t>
 class Snapshot
 {
 public:
+    Snapshot() = default;
+
     Snapshot(std::vector<id_t> active) : active(std::move(active)) {}
 
     Snapshot(const Snapshot& other)
@@ -28,10 +29,30 @@ public:
         return std::binary_search(active.begin(), active.end(), xid);
     }
 
+    void insert(const id_t& id)
+    {
+        active.push_back(id);
+    }
+
+    void remove(const id_t& id)
+    {
+        // remove transaction from the active transactions list
+        auto last = std::remove(active.begin(), active.end(), id);
+        active.erase(last, active.end());
+    }
+
+    const id_t& front()
+    {
+        return active.front();
+    }
+
+    size_t size()
+    {
+        return active.size();
+    }
+
 private:
     std::vector<id_t> active;
 };
 
 }
-
-#endif
diff --git a/transactions/transaction.hpp b/transactions/transaction.hpp
index 5133d0341..1e67efb90 100644
--- a/transactions/transaction.hpp
+++ b/transactions/transaction.hpp
@@ -1,10 +1,10 @@
-#ifndef MEMGRAPH_MVCC_TRANSACTION_HPP
-#define MEMGRAPH_MVCC_TRANSACTION_HPP
+#pragma once
 
 #include <cstdlib>
 #include <cstdint>
 #include <vector>
 
+#include "mvcc/id.hpp"
 #include "snapshot.hpp"
 
 namespace tx
@@ -12,19 +12,17 @@ namespace tx
 
 struct Transaction
 {
-    Transaction(uint64_t id, Snapshot<uint64_t> snapshot)
+    Transaction(const Id& id, Snapshot<Id> snapshot)
         : id(id), cid(1), snapshot(std::move(snapshot)) {}
 
     // index of this transaction
-    uint64_t id;
+    Id id;
 
     // index of the current command in the current transaction;
     uint8_t cid;
 
     // a snapshot of currently active transactions
-    Snapshot<uint64_t> snapshot;
+    Snapshot<Id> snapshot;
 };
 
 }
-
-#endif

From 9685ac3cb6fcfc9a8f7cf306c0a18089b4bacb5d Mon Sep 17 00:00:00 2001
From: Marko Budiselic <mbudiselicbuda@gmail.com>
Date: Sat, 21 Nov 2015 20:34:10 +0100
Subject: [PATCH 3/3] Initial code on crashes and exceptions logging. Related
 to T31.

---
 memgraph.cpp | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/memgraph.cpp b/memgraph.cpp
index 2d4255777..036e96cb7 100644
--- a/memgraph.cpp
+++ b/memgraph.cpp
@@ -12,8 +12,41 @@
 #include "threading/pool.hpp"
 #include "threading/task.hpp"
 
+#include <execinfo.h>
+
+// TODO: move to separate header or source file
+// TODO: log to local file or remote database
+void stacktrace() noexcept
+{
+    void *array[50];
+    int size = backtrace(array, 50);    
+    std::cout << __FUNCTION__ << " backtrace returned " << size << " frames\n\n";
+    char **messages = backtrace_symbols(array, size);
+    for (int i = 0; i < size && messages != NULL; ++i) {
+        std::cout << "[bt]: (" << i << ") " << messages[i] << std::endl;
+    }
+    std::cout << std::endl;
+    free(messages);
+}
+
+// TODO: log to local file or remote database
+void on_terminate() noexcept
+{
+    if (auto exc = std::current_exception()) { 
+        try {
+            std::rethrow_exception(exc);
+        } catch (std::exception &ex) {
+            std::cout << ex.what() << std::endl << std::endl;
+            stacktrace();
+        }
+    }
+    std::_Exit(EXIT_FAILURE);
+}
+
 int main()
 {
+    std::set_terminate(&on_terminate);
+
     ioc::Container container;
 
     container.singleton<Db>();