Reformated code acording to format rules in .clang-format.

This commit is contained in:
Kruno Tomola Fabro 2016-07-31 13:56:13 +01:00
parent 246cf1fd78
commit bf174644de
20 changed files with 282 additions and 188 deletions

View File

@ -20,7 +20,7 @@ AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true AlwaysBreakTemplateDeclarations: true
BinPackArguments: true BinPackArguments: true
BinPackParameters: true BinPackParameters: true
BraceWrapping: BraceWrapping:
AfterClass: true AfterClass: true
AfterControlStatement: false AfterControlStatement: false
AfterEnum: true AfterEnum: true
@ -46,7 +46,7 @@ DerivePointerAlignment: false
DisableFormat: false DisableFormat: false
ExperimentalAutoDetectBinPacking: false ExperimentalAutoDetectBinPacking: false
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
IncludeCategories: IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/' - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2 Priority: 2
- Regex: '^(<|"(gtest|isl|json)/)' - Regex: '^(<|"(gtest|isl|json)/)'
@ -87,4 +87,3 @@ Standard: "C++11"
TabWidth: 8 TabWidth: 8
UseTab: Never UseTab: Never
... ...

1
.gitignore vendored
View File

@ -13,3 +13,4 @@ memgraph
*.session.yaml *.session.yaml
tags tags
.gdb_history .gdb_history
Testing/

View File

@ -5,37 +5,46 @@
using std::pair; using std::pair;
template <typename K, typename T> class ConcurrentMap { template <typename K, typename T>
class ConcurrentMap
{
class Item : public TotalOrdering<Item>, class Item : public TotalOrdering<Item>,
public TotalOrdering<K, Item>, public TotalOrdering<K, Item>,
public TotalOrdering<Item, K>, public TotalOrdering<Item, K>,
public pair<const K, T> { public pair<const K, T>
public: {
public:
using pair<const K, T>::pair; using pair<const K, T>::pair;
friend constexpr bool operator<(const Item &lhs, const Item &rhs) { friend constexpr bool operator<(const Item &lhs, const Item &rhs)
{
std::pair<const K, T> *a; std::pair<const K, T> *a;
return lhs.first < rhs.first; return lhs.first < rhs.first;
} }
friend constexpr bool operator==(const Item &lhs, const Item &rhs) { friend constexpr bool operator==(const Item &lhs, const Item &rhs)
{
return lhs.first == rhs.first; return lhs.first == rhs.first;
} }
friend constexpr bool operator<(const K &lhs, const Item &rhs) { friend constexpr bool operator<(const K &lhs, const Item &rhs)
{
return lhs < rhs.first; return lhs < rhs.first;
} }
friend constexpr bool operator==(const K &lhs, const Item &rhs) { friend constexpr bool operator==(const K &lhs, const Item &rhs)
{
return lhs == rhs.first; return lhs == rhs.first;
} }
friend constexpr bool operator<(const Item &lhs, const K &rhs) { friend constexpr bool operator<(const Item &lhs, const K &rhs)
{
return lhs.first < rhs; return lhs.first < rhs;
} }
friend constexpr bool operator==(const Item &lhs, const K &rhs) { friend constexpr bool operator==(const Item &lhs, const K &rhs)
{
return lhs.first == rhs; return lhs.first == rhs;
} }
}; };
@ -44,16 +53,17 @@ template <typename K, typename T> class ConcurrentMap {
typedef typename SkipList<Item>::Iterator list_it; typedef typename SkipList<Item>::Iterator list_it;
typedef typename SkipList<Item>::ConstIterator list_it_con; typedef typename SkipList<Item>::ConstIterator list_it_con;
public: public:
ConcurrentMap() {} ConcurrentMap() {}
friend class Accessor; friend class Accessor;
class Accessor { class Accessor
{
friend class ConcurrentMap; friend class ConcurrentMap;
Accessor(list *skiplist) : accessor(skiplist->access()) {} Accessor(list *skiplist) : accessor(skiplist->access()) {}
public: public:
Accessor(const Accessor &) = delete; Accessor(const Accessor &) = delete;
Accessor(Accessor &&other) : accessor(std::move(other.accessor)) {} Accessor(Accessor &&other) : accessor(std::move(other.accessor)) {}
@ -72,15 +82,18 @@ public:
list_it_con cend() const { return accessor.cend(); } list_it_con cend() const { return accessor.cend(); }
std::pair<list_it, bool> insert(const K &key, const T &data) { std::pair<list_it, bool> insert(const K &key, const T &data)
{
return accessor.insert(Item(key, data)); return accessor.insert(Item(key, data));
} }
std::pair<list_it, bool> insert(const K &key, T &&data) { std::pair<list_it, bool> insert(const K &key, T &&data)
{
return accessor.insert(Item(key, std::forward<T>(data))); return accessor.insert(Item(key, std::forward<T>(data)));
} }
std::pair<list_it, bool> insert(K &&key, T &&data) { std::pair<list_it, bool> insert(K &&key, T &&data)
{
return accessor.insert(Item(std::forward<K>(key), std::forward<T>(data))); return accessor.insert(Item(std::forward<K>(key), std::forward<T>(data)));
} }
@ -94,7 +107,7 @@ public:
size_t size() const { return accessor.size(); } size_t size() const { return accessor.size(); }
private: private:
typename list::Accessor accessor; typename list::Accessor accessor;
}; };
@ -102,6 +115,6 @@ public:
const Accessor access() const { return Accessor(&skiplist); } const Accessor access() const { return Accessor(&skiplist); }
private: private:
list skiplist; list skiplist;
}; };

View File

@ -94,8 +94,9 @@
* and deletion of nodes. * and deletion of nodes.
*/ */
template <class T, size_t H = 32, class lock_t = SpinLock> template <class T, size_t H = 32, class lock_t = SpinLock>
class SkipList : private Lockable<lock_t> { class SkipList : private Lockable<lock_t>
public: {
public:
// computes the height for the new node from the interval [1...H] // computes the height for the new node from the interval [1...H]
// with p(k) = (1/2)^k for all k from the interval // with p(k) = (1/2)^k for all k from the interval
static thread_local FastBinomial<H> rnd; static thread_local FastBinomial<H> rnd;
@ -106,8 +107,10 @@ public:
* FULLY_LINKED is used to mark the node as fully inserted, i.e. linked * FULLY_LINKED is used to mark the node as fully inserted, i.e. linked
* at all layers in the skiplist up to the node height * at all layers in the skiplist up to the node height
*/ */
struct Flags { struct Flags
enum node_flags : uint8_t { {
enum node_flags : uint8_t
{
MARKED = 0x01, MARKED = 0x01,
FULLY_LINKED = 0x10, FULLY_LINKED = 0x10,
}; };
@ -120,12 +123,13 @@ public:
void set_fully_linked() { flags.fetch_or(FULLY_LINKED); } void set_fully_linked() { flags.fetch_or(FULLY_LINKED); }
private: private:
std::atomic<uint8_t> flags{0}; std::atomic<uint8_t> flags{0};
}; };
class Node : Lockable<lock_t> { class Node : Lockable<lock_t>
public: {
public:
friend class SkipList; friend class SkipList;
const uint8_t height; const uint8_t height;
@ -135,17 +139,20 @@ public:
const T &value() const { return data.get(); } const T &value() const { return data.get(); }
static Node *sentinel(uint8_t height) { static Node *sentinel(uint8_t height)
{
// we have raw memory and we need to construct an object // we have raw memory and we need to construct an object
// of type Node on it // of type Node on it
return new (allocate(height)) Node(height); return new (allocate(height)) Node(height);
} }
static Node *create(const T &item, uint8_t height) { static Node *create(const T &item, uint8_t height)
{
return create(item, height); return create(item, height);
} }
static Node *create(T &&item, uint8_t height) { static Node *create(T &&item, uint8_t height)
{
auto node = allocate(height); auto node = allocate(height);
// we have raw memory and we need to construct an object // we have raw memory and we need to construct an object
@ -153,7 +160,8 @@ public:
return new (node) Node(std::forward<T>(item), height); return new (node) Node(std::forward<T>(item), height);
} }
static void destroy(Node *node) { static void destroy(Node *node)
{
node->~Node(); node->~Node();
std::free(node); std::free(node);
} }
@ -162,8 +170,9 @@ public:
void forward(size_t level, Node *next) { tower[level].store(next); } void forward(size_t level, Node *next) { tower[level].store(next); }
private: private:
Node(uint8_t height) : height(height) { Node(uint8_t height) : height(height)
{
// here we assume, that the memory for N towers (N = height) has // here we assume, that the memory for N towers (N = height) has
// been allocated right after the Node structure so we need to // been allocated right after the Node structure so we need to
// initialize that memory // initialize that memory
@ -171,16 +180,19 @@ public:
new (&tower[i]) std::atomic<Node *>{nullptr}; new (&tower[i]) std::atomic<Node *>{nullptr};
} }
Node(T &&data, uint8_t height) : Node(height) { Node(T &&data, uint8_t height) : Node(height)
{
this->data.set(std::forward<T>(data)); this->data.set(std::forward<T>(data));
} }
~Node() { ~Node()
{
for (auto i = 0; i < height; ++i) for (auto i = 0; i < height; ++i)
tower[i].~atomic(); tower[i].~atomic();
} }
static Node *allocate(uint8_t height) { static Node *allocate(uint8_t height)
{
// [ Node ][Node*][Node*][Node*]...[Node*] // [ Node ][Node*][Node*][Node*]...[Node*]
// | | | | | // | | | | |
// | 0 1 2 height-1 // | 0 1 2 height-1
@ -205,33 +217,39 @@ public:
std::atomic<Node *> tower[0]; std::atomic<Node *> tower[0];
}; };
public: public:
template <class It> class IteratorBase : public Crtp<It> { template <class It>
protected: class IteratorBase : public Crtp<It>
{
protected:
IteratorBase(Node *node) : node(node) {} IteratorBase(Node *node) : node(node) {}
Node *node{nullptr}; Node *node{nullptr};
public: public:
IteratorBase() = default; IteratorBase() = default;
IteratorBase(const IteratorBase &) = default; IteratorBase(const IteratorBase &) = default;
T &operator*() { T &operator*()
{
assert(node != nullptr); assert(node != nullptr);
return node->value(); return node->value();
} }
T *operator->() { T *operator->()
{
assert(node != nullptr); assert(node != nullptr);
return &node->value(); return &node->value();
} }
operator T &() { operator T &()
{
assert(node != nullptr); assert(node != nullptr);
return node->value(); return node->value();
} }
It &operator++() { It &operator++()
{
assert(node != nullptr); assert(node != nullptr);
node = node->forward(0); node = node->forward(0);
return this->derived(); return this->derived();
@ -239,18 +257,20 @@ public:
It &operator++(int) { return operator++(); } It &operator++(int) { return operator++(); }
friend bool operator==(const It &a, const It &b) { friend bool operator==(const It &a, const It &b)
{
return a.node == b.node; return a.node == b.node;
} }
friend bool operator!=(const It &a, const It &b) { return !(a == b); } friend bool operator!=(const It &a, const It &b) { return !(a == b); }
}; };
class ConstIterator : public IteratorBase<ConstIterator> { class ConstIterator : public IteratorBase<ConstIterator>
{
friend class SkipList; friend class SkipList;
ConstIterator(Node *node) : IteratorBase<ConstIterator>(node) {} ConstIterator(Node *node) : IteratorBase<ConstIterator>(node) {}
public: public:
ConstIterator() = default; ConstIterator() = default;
ConstIterator(const ConstIterator &) = default; ConstIterator(const ConstIterator &) = default;
@ -261,18 +281,20 @@ public:
operator const T &() { return IteratorBase<ConstIterator>::operator T &(); } operator const T &() { return IteratorBase<ConstIterator>::operator T &(); }
}; };
class Iterator : public IteratorBase<Iterator> { class Iterator : public IteratorBase<Iterator>
{
friend class SkipList; friend class SkipList;
Iterator(Node *node) : IteratorBase<Iterator>(node) {} Iterator(Node *node) : IteratorBase<Iterator>(node) {}
public: public:
Iterator() = default; Iterator() = default;
Iterator(const Iterator &) = default; Iterator(const Iterator &) = default;
}; };
SkipList() : header(Node::sentinel(H)) {} SkipList() : header(Node::sentinel(H)) {}
~SkipList() { ~SkipList()
{
// Someone could be using this map through an Accessor. // Someone could be using this map through an Accessor.
Node *now = header; Node *now = header;
header = nullptr; header = nullptr;
@ -286,25 +308,28 @@ public:
friend class Accessor; friend class Accessor;
class Accessor { class Accessor
{
friend class SkipList; friend class SkipList;
Accessor(SkipList *skiplist) : skiplist(skiplist) { Accessor(SkipList *skiplist) : skiplist(skiplist)
{
assert(skiplist != nullptr); assert(skiplist != nullptr);
skiplist->gc.add_ref(); skiplist->gc.add_ref();
} }
public: public:
Accessor(const Accessor &) = delete; Accessor(const Accessor &) = delete;
Accessor(Accessor &&other) : skiplist(other.skiplist) { Accessor(Accessor &&other) : skiplist(other.skiplist)
{
other.skiplist = nullptr; other.skiplist = nullptr;
} }
~Accessor() { ~Accessor()
if (skiplist == nullptr) {
return; if (skiplist == nullptr) return;
skiplist->gc.release_ref(); skiplist->gc.release_ref();
} }
@ -321,33 +346,43 @@ public:
ConstIterator cend() const { return skiplist->cend(); } ConstIterator cend() const { return skiplist->cend(); }
std::pair<Iterator, bool> insert(const T &item) { std::pair<Iterator, bool> insert(const T &item)
{
return skiplist->insert(item, preds, succs); return skiplist->insert(item, preds, succs);
} }
std::pair<Iterator, bool> insert(T &&item) { std::pair<Iterator, bool> insert(T &&item)
{
return skiplist->insert(std::forward<T>(item), preds, succs); return skiplist->insert(std::forward<T>(item), preds, succs);
} }
template <class K> ConstIterator find(const K &item) const { template <class K>
ConstIterator find(const K &item) const
{
return static_cast<const SkipList &>(*skiplist).find(item); return static_cast<const SkipList &>(*skiplist).find(item);
} }
template <class K> Iterator find(const K &item) { template <class K>
Iterator find(const K &item)
{
return skiplist->find(item); return skiplist->find(item);
} }
template <class K> bool contains(const K &item) const { template <class K>
bool contains(const K &item) const
{
return this->find(item) != this->end(); return this->find(item) != this->end();
} }
template <class K> bool remove(const K &item) { template <class K>
bool remove(const K &item)
{
return skiplist->remove(item, preds, succs); return skiplist->remove(item, preds, succs);
} }
size_t size() const { return skiplist->size(); } size_t size() const { return skiplist->size(); }
private: private:
SkipList *skiplist; SkipList *skiplist;
Node *preds[H], *succs[H]; Node *preds[H], *succs[H];
}; };
@ -356,7 +391,7 @@ public:
const Accessor access() const { return Accessor(this); } const Accessor access() const { return Accessor(this); }
private: private:
using guard_t = std::unique_lock<lock_t>; using guard_t = std::unique_lock<lock_t>;
Iterator begin() { return Iterator(header->forward(0)); } Iterator begin() { return Iterator(header->forward(0)); }
@ -373,23 +408,33 @@ private:
size_t size() const { return count.load(); } size_t size() const { return count.load(); }
template <class K> bool greater(const K &item, const Node *const node) { template <class K>
bool greater(const K &item, const Node *const node)
{
return node && item > node->value(); return node && item > node->value();
} }
template <class K> bool less(const K &item, const Node *const node) { template <class K>
bool less(const K &item, const Node *const node)
{
return (node == nullptr) || item < node->value(); return (node == nullptr) || item < node->value();
} }
template <class K> ConstIterator find(const K &item) const { template <class K>
ConstIterator find(const K &item) const
{
return const_cast<SkipList *>(this)->find_node<ConstIterator, K>(item); return const_cast<SkipList *>(this)->find_node<ConstIterator, K>(item);
} }
template <class K> Iterator find(const K &item) { template <class K>
Iterator find(const K &item)
{
return find_node<Iterator, K>(item); return find_node<Iterator, K>(item);
} }
template <class It, class K> It find_node(const K &item) { template <class It, class K>
It find_node(const K &item)
{
Node *node, *pred = header; Node *node, *pred = header;
int h = static_cast<int>(pred->height) - 1; int h = static_cast<int>(pred->height) - 1;
@ -399,8 +444,7 @@ private:
} }
// if we overshoot at every layer, item doesn't exist // if we overshoot at every layer, item doesn't exist
if (h < 0) if (h < 0) return It();
return It();
// the item is farther to the right, continue going right as long // the item is farther to the right, continue going right as long
// as the key is greater than the current node's key // as the key is greater than the current node's key
@ -408,14 +452,14 @@ private:
pred = node, node = node->forward(h); pred = node, node = node->forward(h);
// check if we have a hit. if not, we need to descend down again // check if we have a hit. if not, we need to descend down again
if (!less(item, node) && !node->flags.is_marked()) if (!less(item, node) && !node->flags.is_marked()) return It(node);
return It(node);
} }
} }
template <class K> template <class K>
int find_path(Node *from, int start, const K &item, Node *preds[], int find_path(Node *from, int start, const K &item, Node *preds[],
Node *succs[]) { Node *succs[])
{
int level_found = -1; int level_found = -1;
Node *pred = from; Node *pred = from;
@ -425,8 +469,7 @@ private:
while (greater(item, node)) while (greater(item, node))
pred = node, node = pred->forward(level); pred = node, node = pred->forward(level);
if (level_found == -1 && !less(item, node)) if (level_found == -1 && !less(item, node)) level_found = level;
level_found = level;
preds[level] = pred; preds[level] = pred;
succs[level] = node; succs[level] = node;
@ -437,7 +480,8 @@ private:
template <bool ADDING> template <bool ADDING>
bool lock_nodes(uint8_t height, guard_t guards[], Node *preds[], bool lock_nodes(uint8_t height, guard_t guards[], Node *preds[],
Node *succs[]) { Node *succs[])
{
Node *prepred, *pred, *succ = nullptr; Node *prepred, *pred, *succ = nullptr;
bool valid = true; bool valid = true;
@ -456,7 +500,8 @@ private:
return valid; return valid;
} }
std::pair<Iterator, bool> insert(T &&data, Node *preds[], Node *succs[]) { std::pair<Iterator, bool> insert(T &&data, Node *preds[], Node *succs[])
{
while (true) { while (true) {
// TODO: before here was data.first // TODO: before here was data.first
auto level = find_path(header, H - 1, data, preds, succs); auto level = find_path(header, H - 1, data, preds, succs);
@ -464,8 +509,7 @@ private:
if (level != -1) { if (level != -1) {
auto found = succs[level]; auto found = succs[level];
if (found->flags.is_marked()) if (found->flags.is_marked()) continue;
continue;
while (!found->flags.is_fully_linked()) while (!found->flags.is_fully_linked())
usleep(250); usleep(250);
@ -479,8 +523,7 @@ private:
// try to acquire the locks for predecessors up to the height of // try to acquire the locks for predecessors up to the height of
// the new node. release the locks and try again if someone else // the new node. release the locks and try again if someone else
// has the locks // has the locks
if (!lock_nodes<true>(height, guards, preds, succs)) if (!lock_nodes<true>(height, guards, preds, succs)) continue;
continue;
// you have the locks, create a new node // you have the locks, create a new node
auto new_node = Node::create(std::forward<T>(data), height); auto new_node = Node::create(std::forward<T>(data), height);
@ -503,12 +546,15 @@ private:
} }
} }
bool ok_delete(Node *node, int level) { bool ok_delete(Node *node, int level)
{
return node->flags.is_fully_linked() && node->height - 1 == level && return node->flags.is_fully_linked() && node->height - 1 == level &&
!node->flags.is_marked(); !node->flags.is_marked();
} }
template <class K> bool remove(const K &item, Node *preds[], Node *succs[]) { template <class K>
bool remove(const K &item, Node *preds[], Node *succs[])
{
Node *node = nullptr; Node *node = nullptr;
guard_t node_guard; guard_t node_guard;
bool marked = false; bool marked = false;
@ -525,8 +571,7 @@ private:
height = node->height; height = node->height;
node_guard = node->acquire_unique(); node_guard = node->acquire_unique();
if (node->flags.is_marked()) if (node->flags.is_marked()) return false;
return false;
node->flags.set_marked(); node->flags.set_marked();
marked = true; marked = true;
@ -534,8 +579,7 @@ private:
guard_t guards[H]; guard_t guards[H];
if (!lock_nodes<false>(height, guards, preds, succs)) if (!lock_nodes<false>(height, guards, preds, succs)) continue;
continue;
for (int level = height - 1; level >= 0; --level) for (int level = height - 1; level >= 0; --level)
preds[level]->forward(level, node->forward(level)); preds[level]->forward(level, node->forward(level));

View File

@ -8,8 +8,9 @@
#include "threading/sync/spinlock.hpp" #include "threading/sync/spinlock.hpp"
template <class T, class lock_t = SpinLock> template <class T, class lock_t = SpinLock>
class SkiplistGC : public LazyGC<SkiplistGC<T, lock_t>, lock_t> { class SkiplistGC : public LazyGC<SkiplistGC<T, lock_t>, lock_t>
public: {
public:
// release_ref method should be called by a thread // release_ref method should be called by a thread
// when the thread finish it job over object // when the thread finish it job over object
// which has to be lazy cleaned // which has to be lazy cleaned
@ -17,7 +18,8 @@ public:
// are going to be deleted // are going to be deleted
// the only problem with this approach is that // the only problem with this approach is that
// GC may never be called, but for now we can deal with that // GC may never be called, but for now we can deal with that
void release_ref() { void release_ref()
{
std::vector<T *> local_freelist; std::vector<T *> local_freelist;
// take freelist if there is no more threads // take freelist if there is no more threads
@ -47,6 +49,6 @@ public:
void collect(T *node) { freelist.add(node); } void collect(T *node) { freelist.add(node); }
private: private:
FreeList<T> freelist; FreeList<T> freelist;
}; };

View File

@ -8,17 +8,19 @@
#include "utils/crtp.hpp" #include "utils/crtp.hpp"
template <class Derived, class lock_t = SpinLock> template <class Derived, class lock_t = SpinLock>
class LazyGC : public Crtp<Derived>, public Lockable<lock_t> { class LazyGC : public Crtp<Derived>, public Lockable<lock_t>
public: {
public:
// add_ref method should be called by a thread // add_ref method should be called by a thread
// when the thread has to do something over // when the thread has to do something over
// object which has to be lazy cleaned when // object which has to be lazy cleaned when
// the thread finish it job // the thread finish it job
void add_ref() { void add_ref()
{
auto lock = this->acquire_unique(); auto lock = this->acquire_unique();
++count; ++count;
} }
protected: protected:
size_t count{0}; size_t count{0};
}; };

View File

@ -4,25 +4,26 @@
#include "data_structures/concurrent/concurrent_map.hpp" #include "data_structures/concurrent/concurrent_map.hpp"
#include "edge_accessor.hpp" #include "edge_accessor.hpp"
class Edges { class Edges
public: {
Edge::Accessor find(tx::Transaction &t, const Id &id) { public:
Edge::Accessor find(tx::Transaction &t, const Id &id)
{
auto edges_accessor = edges.access(); auto edges_accessor = edges.access();
auto edges_iterator = edges_accessor.find(id); auto edges_iterator = edges_accessor.find(id);
if (edges_iterator == edges_accessor.end()) if (edges_iterator == edges_accessor.end()) return Edge::Accessor();
return Edge::Accessor();
// find edge // find edge
auto edge = edges_iterator->second.find(t); auto edge = edges_iterator->second.find(t);
if (edge == nullptr) if (edge == nullptr) return Edge::Accessor();
return Edge::Accessor();
return Edge::Accessor(edge, &edges_iterator->second, this); return Edge::Accessor(edge, &edges_iterator->second, this);
} }
Edge::Accessor insert(tx::Transaction &t) { Edge::Accessor insert(tx::Transaction &t)
{
// get next vertex id // get next vertex id
auto next = counter.next(std::memory_order_acquire); auto next = counter.next(std::memory_order_acquire);
@ -40,7 +41,7 @@ public:
return Edge::Accessor(edge, &inserted_edge_record->second, this); return Edge::Accessor(edge, &inserted_edge_record->second, this);
} }
private: private:
ConcurrentMap<uint64_t, EdgeRecord> edges; ConcurrentMap<uint64_t, EdgeRecord> edges;
AtomicCounter<uint64_t> counter; AtomicCounter<uint64_t> counter;
}; };

View File

@ -7,13 +7,16 @@
#include "storage/indexes/index_record_collection.hpp" #include "storage/indexes/index_record_collection.hpp"
#include "storage/label/label.hpp" #include "storage/label/label.hpp"
template <class Key, class Item> class Index { template <class Key, class Item>
public: class Index
{
public:
using container_t = ConcurrentMap<Key, Item>; using container_t = ConcurrentMap<Key, Item>;
Index() : index(std::make_unique<container_t>()) {} Index() : index(std::make_unique<container_t>()) {}
auto update(const Label &label, VertexIndexRecord &&index_record) { auto update(const Label &label, VertexIndexRecord &&index_record)
{
auto accessor = index->access(); auto accessor = index->access();
auto label_ref = label_ref_t(label); auto label_ref = label_ref_t(label);
@ -27,7 +30,8 @@ public:
record_collection.add(std::forward<VertexIndexRecord>(index_record)); record_collection.add(std::forward<VertexIndexRecord>(index_record));
} }
VertexIndexRecordCollection &find(const Label &label) { VertexIndexRecordCollection &find(const Label &label)
{
// TODO: accessor should be outside? // TODO: accessor should be outside?
// bacause otherwise GC could delete record that has just be returned // bacause otherwise GC could delete record that has just be returned
auto label_ref = label_ref_t(label); auto label_ref = label_ref_t(label);
@ -35,6 +39,6 @@ public:
return (*accessor.find(label_ref)).second; return (*accessor.find(label_ref)).second;
} }
private: private:
std::unique_ptr<container_t> index; std::unique_ptr<container_t> index;
}; };

View File

@ -1,22 +1,22 @@
#include "storage/vertices.hpp" #include "storage/vertices.hpp"
const Vertex::Accessor Vertices::find(tx::Transaction &t, const Id &id) { const Vertex::Accessor Vertices::find(tx::Transaction &t, const Id &id)
{
auto vertices_accessor = vertices.access(); auto vertices_accessor = vertices.access();
auto vertices_iterator = vertices_accessor.find(id); auto vertices_iterator = vertices_accessor.find(id);
if (vertices_iterator == vertices_accessor.end()) if (vertices_iterator == vertices_accessor.end()) return Vertex::Accessor();
return Vertex::Accessor();
// find vertex // find vertex
auto vertex = vertices_iterator->second.find(t); auto vertex = vertices_iterator->second.find(t);
if (vertex == nullptr) if (vertex == nullptr) return Vertex::Accessor();
return Vertex::Accessor();
return Vertex::Accessor(vertex, &vertices_iterator->second, this); return Vertex::Accessor(vertex, &vertices_iterator->second, this);
} }
Vertex::Accessor Vertices::insert(tx::Transaction &t) { Vertex::Accessor Vertices::insert(tx::Transaction &t)
{
// get next vertex id // get next vertex id
auto next = counter.next(); auto next = counter.next();
@ -36,10 +36,12 @@ Vertex::Accessor Vertices::insert(tx::Transaction &t) {
} }
void Vertices::update_label_index(const Label &label, void Vertices::update_label_index(const Label &label,
VertexIndexRecord &&index_record) { VertexIndexRecord &&index_record)
{
label_index.update(label, std::forward<VertexIndexRecord>(index_record)); label_index.update(label, std::forward<VertexIndexRecord>(index_record));
} }
VertexIndexRecordCollection &Vertices::find_label_index(const Label &label) { VertexIndexRecordCollection &Vertices::find_label_index(const Label &label)
{
return label_index.find(label); return label_index.find(label);
} }

View File

@ -1,19 +1,25 @@
#pragma once #pragma once
template <class Derived, class Other = Derived> struct TotalOrdering { template <class Derived, class Other = Derived>
friend constexpr bool operator!=(const Derived &a, const Other &b) { struct TotalOrdering
{
friend constexpr bool operator!=(const Derived &a, const Other &b)
{
return !(a == b); return !(a == b);
} }
friend constexpr bool operator<=(const Derived &a, const Other &b) { friend constexpr bool operator<=(const Derived &a, const Other &b)
{
return a < b || a == b; return a < b || a == b;
} }
friend constexpr bool operator>(const Derived &a, const Other &b) { friend constexpr bool operator>(const Derived &a, const Other &b)
{
return !(a <= b); return !(a <= b);
} }
friend constexpr bool operator>=(const Derived &a, const Other &b) { friend constexpr bool operator>=(const Derived &a, const Other &b)
{
return !(a < b); return !(a < b);
} }
}; };

View File

@ -19,26 +19,30 @@ using skiplist_t = ConcurrentMap<int, int>;
using namespace std::chrono_literals; using namespace std::chrono_literals;
// Returns uniform random size_t generator from range [0,n> // Returns uniform random size_t generator from range [0,n>
auto rand_gen(size_t n) { auto rand_gen(size_t n)
{
std::default_random_engine generator; std::default_random_engine generator;
std::uniform_int_distribution<size_t> distribution(0, n - 1); std::uniform_int_distribution<size_t> distribution(0, n - 1);
return std::bind(distribution, generator); return std::bind(distribution, generator);
} }
// Returns random bool generator with distribution of 1 true for n false. // Returns random bool generator with distribution of 1 true for n false.
auto rand_gen_bool(size_t n = 1) { auto rand_gen_bool(size_t n = 1)
{
auto gen = rand_gen(n + 1); auto gen = rand_gen(n + 1);
return [=]() mutable { return gen() == 0; }; return [=]() mutable { return gen() == 0; };
} }
// Checks for all owned.second keys if there data is owned.first. // Checks for all owned.second keys if there data is owned.first.
void check_present_same(skiplist_t::Accessor &acc, void check_present_same(skiplist_t::Accessor &acc,
std::pair<size_t, std::vector<size_t>> &owned) { std::pair<size_t, std::vector<size_t>> &owned)
{
check_present_same(acc, owned.first, owned.second); check_present_same(acc, owned.first, owned.second);
} }
// Checks for all owned keys if there data is data. // Checks for all owned keys if there data is data.
void check_present_same(skiplist_t::Accessor &acc, size_t data, void check_present_same(skiplist_t::Accessor &acc, size_t data,
std::vector<size_t> &owned) { std::vector<size_t> &owned)
{
for (auto num : owned) { for (auto num : owned) {
permanent_assert(acc.find(num)->second == data, permanent_assert(acc.find(num)->second == data,
"My data is present and my"); "My data is present and my");
@ -46,7 +50,8 @@ void check_present_same(skiplist_t::Accessor &acc, size_t data,
} }
// Checks if reported size and traversed size are equal to given size. // Checks if reported size and traversed size are equal to given size.
void check_size(const skiplist_t::Accessor &acc, long long size) { void check_size(const skiplist_t::Accessor &acc, long long size)
{
// check size // check size
permanent_assert(acc.size() == size, permanent_assert(acc.size() == size,
@ -70,7 +75,8 @@ void check_size(const skiplist_t::Accessor &acc, long long size) {
template <class R> template <class R>
std::vector<std::future<std::pair<size_t, R>>> std::vector<std::future<std::pair<size_t, R>>>
run(size_t threads_no, skiplist_t &skiplist, run(size_t threads_no, skiplist_t &skiplist,
std::function<R(skiplist_t::Accessor, size_t)> f) { std::function<R(skiplist_t::Accessor, size_t)> f)
{
std::vector<std::future<std::pair<size_t, R>>> futures; std::vector<std::future<std::pair<size_t, R>>> futures;
for (size_t thread_i = 0; thread_i < threads_no; ++thread_i) { for (size_t thread_i = 0; thread_i < threads_no; ++thread_i) {
@ -84,7 +90,9 @@ run(size_t threads_no, skiplist_t &skiplist,
} }
// Collects all data from futures. // Collects all data from futures.
template <class R> auto collect(std::vector<std::future<R>> &collect) { template <class R>
auto collect(std::vector<std::future<R>> &collect)
{
std::vector<R> collection; std::vector<R> collection;
for (auto &fut : collect) { for (auto &fut : collect) {
collection.push_back(fut.get()); collection.push_back(fut.get());
@ -96,7 +104,8 @@ template <class R> auto collect(std::vector<std::future<R>> &collect) {
// downcounts. // downcounts.
template <class K, class D> template <class K, class D>
auto insert_try(skiplist_t::Accessor &acc, size_t &downcount, auto insert_try(skiplist_t::Accessor &acc, size_t &downcount,
std::vector<K> &owned) { std::vector<K> &owned)
{
return [&](K key, D data) mutable { return [&](K key, D data) mutable {
if (acc.insert(key, data).second) { if (acc.insert(key, data).second) {
downcount--; downcount--;
@ -106,7 +115,8 @@ auto insert_try(skiplist_t::Accessor &acc, size_t &downcount,
} }
// Helper function. // Helper function.
int parseLine(char *line) { int parseLine(char *line)
{
// This assumes that a digit will be found and the line ends in " Kb". // This assumes that a digit will be found and the line ends in " Kb".
int i = strlen(line); int i = strlen(line);
const char *p = line; const char *p = line;
@ -118,7 +128,8 @@ int parseLine(char *line) {
} }
// Returns currentlz used memory in kB. // Returns currentlz used memory in kB.
int currently_used_memory() { // Note: this value is in KB! int currently_used_memory()
{ // Note: this value is in KB!
FILE *file = fopen("/proc/self/status", "r"); FILE *file = fopen("/proc/self/status", "r");
int result = -1; int result = -1;
char line[128]; char line[128];
@ -137,7 +148,8 @@ int currently_used_memory() { // Note: this value is in KB!
// function // function
// is aproximately equal to memory usage after function. Memory usage is thread // is aproximately equal to memory usage after function. Memory usage is thread
// senstive so no_threads spawned in function is necessary. // senstive so no_threads spawned in function is necessary.
void memory_check(size_t no_threads, std::function<void()> f) { void memory_check(size_t no_threads, std::function<void()> f)
{
long long start = currently_used_memory(); long long start = currently_used_memory();
f(); f();
long long leaked = long long leaked =

View File

@ -10,51 +10,51 @@ using std::endl;
template <typename list_type> template <typename list_type>
void test_concurrent_list_access(list_type &list, std::size_t size) void test_concurrent_list_access(list_type &list, std::size_t size)
{ {
// test concurrent access // test concurrent access
for (int i = 0; i < 1000000; ++i) { for (int i = 0; i < 1000000; ++i) {
std::thread t1([&list] { std::thread t1([&list] {
list.push_front(1); list.push_front(1);
list.pop_front(); list.pop_front();
}); });
std::thread t2([&list] { std::thread t2([&list] {
list.push_front(2); list.push_front(2);
list.pop_front(); list.pop_front();
}); });
t1.join(); t1.join();
t2.join(); t2.join();
assert(list.size() == size); assert(list.size() == size);
} }
} }
int main() int main()
{ {
LinkedList<int> list; LinkedList<int> list;
// push & pop operations // push & pop operations
list.push_front(10); list.push_front(10);
list.push_front(20); list.push_front(20);
auto a = list.front(); auto a = list.front();
assert(a == 20); assert(a == 20);
list.pop_front(); list.pop_front();
a = list.front(); a = list.front();
assert(a == 10); assert(a == 10);
list.pop_front(); list.pop_front();
assert(list.size() == 0); assert(list.size() == 0);
// concurrent test // concurrent test
LinkedList<int> concurrent_list; LinkedList<int> concurrent_list;
concurrent_list.push_front(1); concurrent_list.push_front(1);
concurrent_list.push_front(1); concurrent_list.push_front(1);
std::list<int> no_concurrent_list; std::list<int> no_concurrent_list;
no_concurrent_list.push_front(1); no_concurrent_list.push_front(1);
no_concurrent_list.push_front(1); no_concurrent_list.push_front(1);
test_concurrent_list_access(concurrent_list, 2);
// test_concurrent_list_access(no_concurrent_list, 2);
return 0; test_concurrent_list_access(concurrent_list, 2);
// test_concurrent_list_access(no_concurrent_list, 2);
return 0;
} }

View File

@ -3,7 +3,8 @@
#define THREADS_NO 1 #define THREADS_NO 1
constexpr size_t elems_per_thread = 16e5; constexpr size_t elems_per_thread = 16e5;
int main() { int main()
{
memory_check(THREADS_NO, [&] { memory_check(THREADS_NO, [&] {
ds::static_array<std::thread, THREADS_NO> threads; ds::static_array<std::thread, THREADS_NO> threads;
skiplist_t skiplist; skiplist_t skiplist;
@ -33,15 +34,15 @@ int main() {
} }
for (size_t thread_i = 0; thread_i < THREADS_NO; ++thread_i) { for (size_t thread_i = 0; thread_i < THREADS_NO; ++thread_i) {
threads[thread_i] = std::thread( threads[thread_i] = std::thread(
[&skiplist](size_t start, size_t end) { [&skiplist](size_t start, size_t end) {
auto accessor = skiplist.access(); auto accessor = skiplist.access();
for (size_t elem_i = 0; elem_i < elems_per_thread; ++elem_i) { for (size_t elem_i = 0; elem_i < elems_per_thread; ++elem_i) {
permanent_assert(accessor.remove(elem_i) == true, ""); permanent_assert(accessor.remove(elem_i) == true, "");
} }
}, },
thread_i * elems_per_thread, thread_i * elems_per_thread,
thread_i * elems_per_thread + elems_per_thread); thread_i * elems_per_thread + elems_per_thread);
} }
// wait all threads // wait all threads
for (auto &thread : threads) { for (auto &thread : threads) {

View File

@ -7,7 +7,8 @@ constexpr size_t key_range = elems_per_thread * THREADS_NO * 2;
// This test checks insert_unique method under pressure. // This test checks insert_unique method under pressure.
// Test checks for missing data and changed/overwriten data. // Test checks for missing data and changed/overwriten data.
int main() { int main()
{
memory_check(THREADS_NO, [] { memory_check(THREADS_NO, [] {
skiplist_t skiplist; skiplist_t skiplist;

View File

@ -8,7 +8,8 @@ constexpr size_t key_range = elems_per_thread * THREADS_NO * 2;
// Threads will try to insert keys in the same order. // Threads will try to insert keys in the same order.
// This will force threads to compete intensly with each other. // This will force threads to compete intensly with each other.
// Test checks for missing data and changed/overwriten data. // Test checks for missing data and changed/overwriten data.
int main() { int main()
{
memory_check(THREADS_NO, [] { memory_check(THREADS_NO, [] {
skiplist_t skiplist; skiplist_t skiplist;

View File

@ -5,7 +5,8 @@
constexpr size_t elements = 2e6; constexpr size_t elements = 2e6;
// Test for simple memory leaks // Test for simple memory leaks
int main() { int main()
{
memory_check(THREADS_NO, [] { memory_check(THREADS_NO, [] {
skiplist_t skiplist; skiplist_t skiplist;

View File

@ -10,7 +10,8 @@ constexpr size_t no_insert_for_one_delete = 2;
// Threads will try to insert and remove keys aproximetly in the same order. // Threads will try to insert and remove keys aproximetly in the same order.
// This will force threads to compete intensly with each other. // This will force threads to compete intensly with each other.
// Calls of remove method are interleaved with insert calls. // Calls of remove method are interleaved with insert calls.
int main() { int main()
{
memory_check(THREADS_NO, [] { memory_check(THREADS_NO, [] {
skiplist_t skiplist; skiplist_t skiplist;

View File

@ -8,7 +8,8 @@ constexpr size_t no_insert_for_one_delete = 1;
// This test checks remove method under pressure. // This test checks remove method under pressure.
// Each thread removes it's own data. So removes are disjoint. // Each thread removes it's own data. So removes are disjoint.
// Calls of remove method are interleaved with insert calls. // Calls of remove method are interleaved with insert calls.
int main() { int main()
{
memory_check(THREADS_NO, [] { memory_check(THREADS_NO, [] {
skiplist_t skiplist; skiplist_t skiplist;

View File

@ -10,7 +10,8 @@ constexpr size_t no_insert_for_one_delete = 2;
// This test checks remove method under pressure. // This test checks remove method under pressure.
// Each thread removes random data. So removes are joint. // Each thread removes random data. So removes are joint.
// Calls of remove method are interleaved with insert calls. // Calls of remove method are interleaved with insert calls.
int main() { int main()
{
memory_check(THREADS_NO, [] { memory_check(THREADS_NO, [] {
skiplist_t skiplist; skiplist_t skiplist;

View File

@ -12,7 +12,8 @@ constexpr size_t no_insert_for_one_delete = 1;
// Each thread makes a series of finds interleaved with method which change. // Each thread makes a series of finds interleaved with method which change.
// Exact ratio of finds per change and insert per delete can be regulated with // Exact ratio of finds per change and insert per delete can be regulated with
// no_find_per_change and no_insert_for_one_delete. // no_find_per_change and no_insert_for_one_delete.
int main() { int main()
{
memory_check(THREADS_NO, [] { memory_check(THREADS_NO, [] {
skiplist_t skiplist; skiplist_t skiplist;