MDList
mdlist.h
Go to the documentation of this file.
1 
11 #ifndef _mdlist_h_
12 #define _mdlist_h_
13 
14 #include <vector>
15 #include <mutex>
16 #include <cmath>
17 #include <exception>
18 #include <iostream>
19 
20 #define ULL unsigned long long
21 
22 using namespace std;
23 
24 // Hepler Functions
25 
32 long nthRoot (ULL X, int n)
33 {
34  long nth_root = trunc(std::pow(X, 1.0 / n));
35  // because of rounding error,
36  // it's possible that nth_root + 1
37  // is what we actually want; let's check
38  if (std::pow(nth_root + 1, n) <= X) {
39  return nth_root + 1;
40  }
41  return nth_root;
42 }
43 
51 vector<int> keyToCoordinates (ULL key, int D, ULL N)
52 {
53  int M = nthRoot(N, D);
54  vector<int> coordinates(D);
55  int i = D-1;
56  while (key > 0 && i >= 0) {
57  coordinates[i--] = key % M;
58  key /= M;
59  }
60  return coordinates;
61 }
62 
69 template <class T>
70 class Node
71 {
79  T val;
84  vector<int> COORDINATES;
88  vector<Node*> child;
92  std::mutex mutex;
96  std::mutex child_mutex;
100  std::mutex val_mutex;
101 
102  public:
103  Node(ULL, int, ULL, T val = NULL);
104  void lock();
105  bool try_lock();
106  void unlock();
107  ULL getKey();
108  void setValue(T);
109  T getValue();
110  void setChild(int, Node*);
111  Node<T>* getChild(int);
112  vector<int> getCoordinates();
113 };
114 
122 template <class T>
123 Node<T>::Node (ULL key, int D, ULL N, T val)
124 {
125  this->key = key;
126  this->val = val;
127  this->COORDINATES = keyToCoordinates(key, D, N);
128  this->child.assign(D, NULL);
129 }
130 
134 template <class T>
136 {
137  this->mutex.lock();
138 }
139 
144 template <class T>
146 {
147  return this->mutex.try_lock();
148 }
149 
153 template <class T>
155 {
156  this->mutex.unlock();
157 }
158 
163 template <class T>
165 {
166  // Constant so no need for lock
167  return this->key;
168 }
169 
174 template <class T>
175 void Node<T>::setValue (T val)
176 {
177  this->val_mutex.lock();
178  this->val = val;
179  this->val_mutex.unlock();
180 }
181 
186 template <class T>
188 {
189  this->val_mutex.lock();
190  T t = this->val;
191  this->val_mutex.unlock();
192  return t;
193 }
194 
200 template <class T>
201 void Node<T>::setChild (int index, Node* childNode)
202 {
203  if (index < 0 && index >= this->child.size())
204  throw "Index out of bounds";
205  this->child_mutex.lock();
206  this->child[index] = childNode;
207  this->child_mutex.unlock();
208 }
209 
215 template <class T>
217 {
218  if (index < 0 && index >= this->child.size())
219  throw "Index out of bounds";
220  this->child_mutex.lock();
221  Node<T>* node = this->child[index];
222  this->child_mutex.unlock();
223  return node;
224 }
225 
230 template <class T>
232 {
233  return this->COORDINATES;
234 }
235 
236 
244 template <class T>
245 class MDList
246 {
250  int D;
259  pair<Node<T>*, Node<T>*> locatePredecessor(vector<int>);
260  public:
261  MDList(int, ULL);
262  void insert(ULL, T);
263  T find(ULL);
264  T remove(ULL);
265  template <class _T>
266  friend void printMDList(MDList<_T>);
267  template <class _T>
268  friend void findAndPrint(MDList<_T>, ULL);
269 };
270 
276 template <class T>
278 {
279  this->D = D;
280  this->N = N;
281  this->root = new Node<T>(0, D, N);
282 }
283 
290 template <class T>
291 pair<Node<T>*, Node<T>*> MDList<T>::locatePredecessor (vector<int> coordinates)
292 {
293  Node<T>* current = this->root;
294  Node<T>* predecessor = NULL;
295  int d = 0;
296  while (d < this->D)
297  {
298  while (current != NULL && coordinates[d] > current->getCoordinates()[d]){
299  predecessor = current;
300  current = current->getChild(d);
301  }
302  // Check if we found the predecessor.
303  if (current == NULL || coordinates[d] < current->getCoordinates()[d])
304  break;
305  else
306  d++;
307  }
308  return make_pair(predecessor, current);
309 }
310 
316 template <class T>
317 void MDList<T>::insert (ULL key, T val)
318 {
319  if (key < 0 || key >= N)
320  return;
321  start:
322  vector<int> coordinates = keyToCoordinates(key, this->D, this->N);
323  pair<Node<T>*, Node<T>*> p = locatePredecessor(coordinates);
324  Node<T>* predecessor = p.first;
325  Node<T>* current = p.second;
326  // Lock for thread safety
327  if (predecessor != NULL && !predecessor->try_lock())
328  goto start;
329  if (current != NULL && !current->try_lock())
330  {
331  if (predecessor != NULL)
332  predecessor->unlock();
333  goto start;
334  }
335  // Check predecessor and current are still valid
336  p = locatePredecessor(coordinates);
337  if (predecessor != p.first || current != p.second)
338  {
339  if (predecessor != NULL)
340  predecessor->unlock();
341  if (current != NULL)
342  current->unlock();
343  goto start;
344  }
345  // Check if key already exists.
346  if (current != NULL && key == current->getKey())
347  {
348  // Update value and return.
349  current->setValue(val);
350  if (predecessor != NULL)
351  predecessor->unlock();
352  current->unlock();
353  return;
354  }
355  // Key doesn't exits, create new Node.
356  Node<T>* node = new Node<T>(key, this->D, this->N, val);
357  // Find position of node in predecessor
358  int d = 0;
359  while (d < this->D && coordinates[d] <= predecessor->getCoordinates()[d])
360  d++;
361  if (d >= this->D)
362  throw "Given key is out of key space";
363  int _d = d;
364  // If current is NULL, then node is _dth child of predecessor.
365  if (current == NULL)
366  {
367  predecessor->setChild(_d, node);
368  predecessor->unlock();
369  return;
370  }
371  // Assign appropriate childrens to node.
372  while (d < this->D)
373  {
374  // Check if current can be dth child of node.
375  if (node->getCoordinates()[d] < current->getCoordinates()[d]){
376  node->setChild(d, current);
377  break;
378  }
379  // Else dth child of current is dth child of node
380  node->setChild(d, current->getChild(d));
381  current->setChild(d, NULL);
382  d++;
383  }
384  // Assign predecessor as parent to node.
385  predecessor->setChild(_d, node);
386  predecessor->unlock();
387  current->unlock();
388 }
389 
395 template <class T>
397 {
398  if (key < 0 || key >= N)
399  return NULL;
400  vector<int> coordinates = keyToCoordinates(key, this->D, this->N);
401  pair<Node<T>*, Node<T>*> p = locatePredecessor(coordinates);
402  Node<T>* current = p.second;
403  if (current != NULL && current->getKey() == key)
404  return current->getValue();
405  return NULL;
406 }
407 
413 template <class T>
415 {
416  if (key < 0 || key >= N)
417  return NULL;
418  // If given key is root
419  // just remove the value
420  // because root cannot be deleted.
421  if (key == 0)
422  {
423  T val = root->getValue();
424  this->root->setValue(NULL);
425  return val;
426  }
427  start_r:
428  vector<int> coordinates = keyToCoordinates(key, this->D, this->N);
429  pair<Node<T>*, Node<T>*> p = locatePredecessor(coordinates);
430  Node<T>* predecessor = p.first;
431  Node<T>* current = p.second;
432  // Lock for thread safety
433  if (predecessor != NULL && !predecessor->try_lock())
434  goto start_r;
435  if (current != NULL && !current->try_lock())
436  {
437  if (predecessor != NULL)
438  predecessor->unlock();
439  goto start_r;
440  }
441  if (current == NULL || current->getKey() != key)
442  {
443  print.lock();
444  // cout<<key<<" = "<<current->getKey()<<endl;
445  print.unlock();
446  // printMDList(*this);
447  return NULL;
448  }
449 
450  // Find the index of current in predecessor
451  int d = 0;
452  while (d < this->D && predecessor->getChild(d) != current)
453  d++;
454  if (d >= this->D)
455  throw "Given key is out of key space";
456  // The last indexed child of current will be the new current
457  Node<T>* new_current = NULL;
458  int _d = this->D;
459  while (_d > 0 && new_current == NULL) {
460  _d--;
461  new_current = current->getChild(_d);
462  }
463  // Try lock for new_current
464  if (new_current != NULL && !new_current->try_lock())
465  {
466  if (predecessor != NULL)
467  predecessor->unlock();
468  if (current != NULL)
469  current->unlock();
470  goto start_r;
471  }
472  // Check predecessor and current are still valid
473  p = locatePredecessor(coordinates);
474  if (predecessor != p.first || current != p.second ||
475  (current != NULL && current->getKey() != key))
476  {
477  if (predecessor != NULL)
478  predecessor->unlock();
479  if (current != NULL)
480  current->unlock();
481  if (new_current != NULL)
482  new_current->unlock();
483  goto start_r;
484  }
485  // Transer children of current to new current
486  _d--;
487  while (_d >= 0) {
488  new_current->setChild(_d, current->getChild(_d));
489  _d--;
490  }
491  // Update predecessor pointer
492  predecessor->setChild(d, new_current);
493  if (predecessor)
494  predecessor->unlock();
495  if (new_current)
496  new_current->unlock();
497  T val = current->getValue();
498  delete current;
499  return val;
500 }
501 
502 
508 template <class T>
509 void printMDList (MDList<T> mdList)
510 {
511  vector< Node<T>* > stack;
512  stack.push_back(mdList.root);
513  while(stack.size() > 0)
514  {
515  Node<T>* node = stack.back();
516  stack.pop_back();
517  cout<<node->getKey()<<" ";
518  vector<int> coordinates = node->getCoordinates();
519  cout<<"[";
520  for (int d = 0; d < mdList.D; d++)
521  {
522  cout<<coordinates[d]<<", ";
523  }
524  cout<<"] : ";
525  if (node->getValue() != NULL)
526  cout<<node->getValue()<<"\n\t";
527  else
528  cout<<"NULL\n\t";
529  for (int d = 0; d < mdList.D; d++)
530  {
531  Node<T>* child = node->getChild(d);
532  cout<<d<<" : ";
533  if (child == NULL)
534  cout<<"NULL , ";
535  else
536  {
537  stack.push_back(child);
538  vector<int> coordinates = child->getCoordinates();
539  cout<<"[";
540  for (int d = 0; d < mdList.D; d++)
541  {
542  cout<<coordinates[d]<<", ";
543  }
544  cout<<"] , ";
545  }
546  }
547  cout<<endl;
548  }
549 }
550 
557 template <class T>
558 void findAndPrint (MDList<T> mdlist, ULL key)
559 {
560  vector<int> coordinates = keyToCoordinates(key, mdlist.D, mdlist.N);
561  pair<Node<T>*, Node<T>*> p = mdlist.locatePredecessor(coordinates);
562  Node<T>* node = p.second;
563  if (node->getKey() == key)
564  {
565  cout<<node->getKey()<<" ";
566  vector<int> coordinates = node->getCoordinates();
567  cout<<"[";
568  for (int d = 0; d < mdlist.D; d++)
569  {
570  cout<<coordinates[d]<<", ";
571  }
572  cout<<"] : ";
573  if (node->getValue() != NULL)
574  cout<<node->getValue()<<"\n\t";
575  else
576  cout<<"NULL\n\t";
577  for (int d = 0; d < mdlist.D; d++)
578  {
579  Node<T>* child = node->getChild(d);
580  cout<<d<<" : ";
581  if (child == NULL)
582  cout<<"NULL , ";
583  else
584  {
585  vector<int> coordinates = child->getCoordinates();
586  cout<<"[";
587  for (int d = 0; d < mdlist.D; d++)
588  {
589  cout<<coordinates[d]<<", ";
590  }
591  cout<<"] , ";
592  }
593  }
594  cout<<endl;
595  }
596  else
597  {
598  cout << key << " Not found!\n";
599  }
600 }
601 
602 #endif
MDList(int, ULL)
MDList constructor.
Definition: mdlist.h:277
T remove(ULL)
Removes the given key.
Definition: mdlist.h:414
Node class.
Definition: mdlist.h:70
std::mutex val_mutex
Mutex lock for value.
Definition: mdlist.h:100
bool try_lock()
Non blocking lock operation on node mutex.
Definition: mdlist.h:145
void printMDList(MDList< T > mdList)
Prints MDList.
Definition: mdlist.h:509
std::mutex mutex
Mutex lock for this Node.
Definition: mdlist.h:92
void insert(ULL, T)
Insert (key, value) to MDList.
Definition: mdlist.h:317
Node< T > * root
Head or Root of the MDList.
Definition: mdlist.h:258
std::mutex child_mutex
Mutex lock for children.
Definition: mdlist.h:96
int D
The D value of MDList.
Definition: mdlist.h:250
Node(ULL, int, ULL, T val=NULL)
Node Class Constructor.
Definition: mdlist.h:123
void setValue(T)
Setter for value.
Definition: mdlist.h:175
Node< T > * getChild(int)
Getter for Child.
Definition: mdlist.h:216
ULL key
The key.
Definition: mdlist.h:75
vector< int > keyToCoordinates(ULL key, int D, ULL N)
Converts key to node coordinates.
Definition: mdlist.h:51
vector< Node * > child
The vector of children of this Node.
Definition: mdlist.h:88
T find(ULL)
Searches for given key.
Definition: mdlist.h:396
long nthRoot(ULL X, int n)
Finds nth root of given number.
Definition: mdlist.h:32
ULL N
The key space.
Definition: mdlist.h:254
ULL getKey()
Getter for key.
Definition: mdlist.h:164
void unlock()
Unlocks the node mutex.
Definition: mdlist.h:154
T val
The value.
Definition: mdlist.h:79
vector< int > COORDINATES
The Node coordinates.
Definition: mdlist.h:84
void lock()
Locks the node mutex.
Definition: mdlist.h:135
void setChild(int, Node *)
Setter for child Node.
Definition: mdlist.h:201
T getValue()
Getter for Value.
Definition: mdlist.h:187
void findAndPrint(MDList< T > mdlist, ULL key)
Finds and prints node for given key.
Definition: mdlist.h:558
MDList class MDList is a dictionary based datastruture which stores (key, value) pairs.
Definition: mdlist.h:245
vector< int > getCoordinates()
Getter for Node coordinates.
Definition: mdlist.h:231
pair< Node< T > *, Node< T > * > locatePredecessor(vector< int >)
Locate Predecessor/Parent of given coordinates.
Definition: mdlist.h:291
#define ULL
Definition: mdlist.h:20