PageRenderTime 51ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/b_tree/Node.cpp

https://bitbucket.org/alexander_schiendorfer/microdb-se
C++ | 464 lines | 282 code | 47 blank | 135 comment | 40 complexity | 617f1831b465e2c295e59890d59bea5d MD5 | raw file
Possible License(s): BSD-3-Clause
  1. #ifndef DBS_NODE_CPP
  2. #define DBS_NODE_CPP
  3. #include "TreeStructs.h"
  4. #include "../util/tid.h"
  5. #include "../buffer/BufferFrame.h"
  6. #include "../buffer/BufferManager.h"
  7. #include <iostream>
  8. #include <sstream>
  9. #include <stdexcept>
  10. #include <cstring>
  11. //TODO - replace this const
  12. #define DEBUGSIZE 85
  13. using namespace std;
  14. template <class K>
  15. class Node {
  16. private:
  17. NodeData* data;
  18. K* keyOffset;
  19. void* valueOffset;
  20. bool dirty = false;
  21. BufferFrame& bufferFrame;
  22. unsigned int totalSpace;
  23. /**
  24. * Binary search within the node
  25. */
  26. K* binaryLookup(K* from, K* to, K key) {
  27. //TODO - compare
  28. return lower_bound(from, to, key);
  29. }
  30. /**
  31. * Returns the position where to insert the new key
  32. */
  33. unsigned int insertionOffset(K key) {
  34. K* keyPos = binaryLookup(keyOffset, keyOffset + data->entryCount - 1, key);
  35. return keyPos - keyOffset;
  36. }
  37. /**
  38. * Removes the given key and handles the memory
  39. */
  40. void removeKey(K key) {
  41. //Delete the key
  42. K* to = binaryLookup(keyOffset, keyOffset + data->entryCount - 1, key);
  43. //TODO - compare
  44. if (*to != key) {
  45. cout << "Could not remove key: " << key << " there is no such key" << endl;
  46. return;
  47. }
  48. K* from = to + 1;
  49. unsigned moveAmount = (keyOffset + data->entryCount - (to + 1)) * sizeof(K);
  50. //Move the memory and overwrite the old key
  51. memmove(to, from, moveAmount);
  52. }
  53. /**
  54. * toString method for booleans
  55. */
  56. string printBool(bool val) {
  57. if (val) {
  58. return "true";
  59. } else {
  60. return "false";
  61. }
  62. }
  63. /**
  64. * Calculate the value and key offset
  65. */
  66. void refreshValueOffset() {
  67. //The total amount of tuples is the size minus the header minus the first value
  68. //divided by the size of the key,value pairs
  69. if (data->isLeaf) {
  70. totalSpace = (PAGESIZE - sizeof(NodeData)) / (sizeof(K) + sizeof(TID));
  71. } else {
  72. totalSpace = (PAGESIZE - sizeof(NodeData)) / (sizeof(K) + sizeof(unsigned int));
  73. }
  74. valueOffset = keyOffset + totalSpace;
  75. }
  76. public:
  77. /**
  78. * Housing for this node is a given BufferFrame
  79. */
  80. Node(BufferFrame& bf) : bufferFrame(bf) {
  81. data = static_cast<NodeData *>(bf.getData());
  82. keyOffset = reinterpret_cast<K *>(static_cast<NodeData *>(data) + 1);
  83. refreshValueOffset();
  84. }
  85. ~Node() {
  86. cout << "Node destructor called" << endl;
  87. //TODO clean up
  88. }
  89. /**
  90. * Returns the offset for a given key
  91. */
  92. K* getKeyOffsetForKey(K key) {
  93. cout << "Looking for TID of key:" << key << endl;
  94. K* it = binaryLookup(keyOffset, keyOffset + data->entryCount - 1, key);
  95. //TODO - compare
  96. if (*it != key) {
  97. return NULL;
  98. } else {
  99. return it;
  100. }
  101. }
  102. /**
  103. * Sets the leaf property of this node to val
  104. */
  105. void setLeaf(bool val) {
  106. dirty = true;
  107. data->isLeaf = val;
  108. refreshValueOffset();
  109. }
  110. /**
  111. * Returns the next sibling and throws an exception if the node is no leaf
  112. */
  113. unsigned int getNextSibling() {
  114. if (isLeaf()) {
  115. return data->rightMostEntry;
  116. } else {
  117. throw new runtime_error("Get next sibling is called on an inner node");
  118. }
  119. }
  120. /**
  121. * Sets the next sibling and throws an exception if the node is no leaf
  122. */
  123. void setNextSibling(unsigned int val) {
  124. if (isLeaf()) {
  125. data->rightMostEntry = val;
  126. } else {
  127. throw new runtime_error("Set next sibling is called on an inner node");
  128. }
  129. }
  130. /**
  131. * Returns the keyOffset
  132. */
  133. K* getKeyOffset() {
  134. return keyOffset;
  135. }
  136. /**
  137. * Returns the valueOffset
  138. */
  139. void* getValueOffset() {
  140. return valueOffset;
  141. }
  142. /**
  143. * retuns the dirty property
  144. */
  145. bool isDirty() {
  146. return dirty;
  147. }
  148. /**
  149. * Returns the amount of free space in this node
  150. */
  151. unsigned int getFreeSpace() {
  152. return (totalSpace - data->entryCount);
  153. }
  154. /**
  155. * Returns whether there is space for more key, value pairs or not
  156. */
  157. bool isSpaceFree() {
  158. return ((totalSpace - data->entryCount) > 0);
  159. }
  160. /**
  161. * Returns the capacity of the node
  162. */
  163. unsigned int getCapacity() {
  164. return totalSpace;
  165. }
  166. /**
  167. * Returns the amount of entries in the node
  168. */
  169. unsigned int getEntryCount() {
  170. return data->entryCount;
  171. }
  172. /**
  173. * Returns the value at a hgiven index and throws an exception if the node is no leaf
  174. */
  175. unsigned int getValueAt(unsigned int index) {
  176. if (isLeaf()) {
  177. throw runtime_error("GetValueAt is called for a leaf node");
  178. }
  179. return *(static_cast<unsigned int*>(valueOffset) + index);
  180. }
  181. /**
  182. * Checks whether this node is a leaf or not
  183. */
  184. bool isLeaf() {
  185. return data->isLeaf;
  186. }
  187. /**
  188. * Splits the node by moving key value pairs to the given newNode
  189. */
  190. Node<K>* splitNode(Node<K>* newNode) {
  191. unsigned int mid = data->entryCount / 2;
  192. K* keyMiddle = keyOffset + mid;
  193. unsigned int newNodeCount = data->entryCount - mid;
  194. unsigned int oldNodeCount = mid;
  195. //Set the counts for old and new node
  196. newNode->setEntryCount(newNodeCount);
  197. setEntryCount(oldNodeCount);
  198. //Set the leaf property depending on the split node
  199. newNode->setLeaf(isLeaf());
  200. //Rearange the next pointer
  201. if (isLeaf()) {
  202. newNode->setNextSibling(getNextSibling());
  203. setNextSibling(newNode->getBufferFrame().getPageNo());
  204. } else {
  205. newNode->setUpper(getUpper());
  206. setUpper(0);
  207. }
  208. //Copy the keys to the new node
  209. memcpy(newNode->getKeyOffset(), keyMiddle, newNodeCount * sizeof(K));
  210. if (isLeaf()) {
  211. memcpy(newNode->getValueOffset(), static_cast<TID*>(valueOffset) + oldNodeCount, newNodeCount * sizeof(TID));
  212. //Clear old values
  213. memset(static_cast<TID*>(valueOffset) + oldNodeCount, 0, newNodeCount * sizeof(TID));
  214. } else {
  215. memcpy(newNode->getValueOffset(), static_cast<unsigned int*>(valueOffset) + oldNodeCount, newNodeCount * sizeof(unsigned int));
  216. //Clear old values
  217. memset(static_cast<unsigned int*>(valueOffset) + oldNodeCount, 0, newNodeCount * sizeof(unsigned int));
  218. }
  219. //Clear the old key data
  220. memset(keyMiddle, 0, newNodeCount * sizeof(K));
  221. return newNode;
  222. }
  223. /**
  224. * Removes a key, value pair specified by the Key key
  225. */
  226. void remove(K key) {
  227. K* to = binaryLookup(keyOffset, keyOffset + data->entryCount - 1, key);
  228. //TODO - compare
  229. if (*to != key) {
  230. cout << "Could not remove key " << key << " cause there is none" << endl;
  231. return;
  232. }
  233. //Delete the value
  234. if (isLeaf()) {
  235. TID* to = findTidValue(key);
  236. TID* from = to + 1;
  237. unsigned int moveAmount = ((static_cast<TID*>(valueOffset) + data->entryCount) - (to + 1)) * sizeof(TID);
  238. //Move the memory and overwrite the old value
  239. memmove(to, from, moveAmount);
  240. } else {
  241. unsigned int* to = findPageIdValuePtr(key);
  242. unsigned int* from = to + 1;
  243. unsigned int moveAmount = ((static_cast<unsigned int*>(valueOffset) + data->entryCount) - (to + 1)) * sizeof(unsigned int);
  244. //Move the memory and overwrite the old value
  245. memmove(to, from, moveAmount);
  246. }
  247. removeKey(key);
  248. --data->entryCount;
  249. dirty = true;
  250. }
  251. /**
  252. * Inserts a given key, value pair into the node and ensures the order within the node
  253. */
  254. void insert(K key, void* val) {
  255. //Get the offset of the next smaller key in this node
  256. unsigned int offset = insertionOffset(key);
  257. //Declare variables for insertionpoints
  258. K* insertKey = keyOffset + offset;
  259. cout << "Offset is: " << offset << endl;
  260. //Calculate how many bytes we have to move
  261. unsigned int moveAmount = (data->entryCount - offset) * sizeof(K);
  262. //Move the key by one slot
  263. K * from = insertKey;
  264. K * to = from + 1;
  265. memmove(to, from, moveAmount);
  266. if (isLeaf()) {
  267. //Calculate the position where we have to insert the TID
  268. TID * insertTID = reinterpret_cast<TID *>(valueOffset) + offset;
  269. //Calculate how many bytes we have to move
  270. moveAmount = (data->entryCount - offset) * sizeof(TID);
  271. TID * to = insertTID + 1;
  272. //Move the values by one slot
  273. memmove(to, insertTID, moveAmount);
  274. //Insert the value for the TID
  275. *insertTID = *static_cast<TID *>(val);
  276. } else {
  277. //Calculate the position where we have to insert the pageNo
  278. unsigned int * insertPageNo = reinterpret_cast<unsigned int *>(valueOffset) + offset;
  279. //Calculate how many bytes we have to move
  280. moveAmount = (data->entryCount - offset) * sizeof(unsigned int);
  281. unsigned int * to = insertPageNo + 1;
  282. //Move the values by one slot
  283. memmove(to, from, moveAmount);
  284. //Insert the value for the pageNo
  285. *insertPageNo = *static_cast<unsigned int*>(val);
  286. }
  287. *insertKey = key;
  288. ++data->entryCount;
  289. dirty = true;
  290. }
  291. /**
  292. * Prints the content of the node
  293. */
  294. string print() {
  295. ostringstream oss;
  296. oss << "node" << getBufferFrame().getPageNo() << "[shape=record, label=\"";
  297. oss << "<pageId> " << bufferFrame.getPageNo() << " | <isLeaf> " << printBool(isLeaf()) << " | ";
  298. for(unsigned int i = 1; i <= data->entryCount; i++) {
  299. oss << "<key" << i << "> " << *(keyOffset + (i-1)) << " | ";
  300. }
  301. for(unsigned int i = 1; i <= data->entryCount; i++) {
  302. oss << "<val" << i << "> ";
  303. if (isLeaf()) {
  304. TID* tid = (static_cast<TID *>(valueOffset) + (i-1));
  305. oss << tid->pageId << "/" << tid->slotId << " | ";
  306. } else {
  307. oss << "* | ";
  308. }
  309. }
  310. oss << "<next> *\"];";
  311. return oss.str();
  312. }
  313. /**
  314. * Retrieves the TID for the given key
  315. */
  316. TID* findTidValue(K key) {
  317. cout << "Looking for TID of key:" << key << endl;
  318. K* it = binaryLookup(keyOffset, keyOffset + data->entryCount - 1, key);
  319. //TODO - compare
  320. if (*it != key) {
  321. return NULL;
  322. } else {
  323. int pos = it - keyOffset;
  324. return static_cast<TID *>(valueOffset) + pos;
  325. }
  326. }
  327. /**
  328. * Retrieves the pageId for the given key
  329. */
  330. unsigned int findPageIdValue(K key) {
  331. cout << "Looking for pageId of key:" << key << endl;
  332. K* it = binaryLookup(keyOffset, keyOffset + data->entryCount - 1, key);
  333. //TODO - compare
  334. if (*it < key) {
  335. return data->rightMostEntry;
  336. }
  337. int pos = it - keyOffset;
  338. unsigned int pageId = *(static_cast<unsigned int *>(valueOffset) + pos);
  339. return pageId;
  340. }
  341. /**
  342. * Returns a pointer to the value of a given key
  343. */
  344. unsigned int* findPageIdValuePtr(K key) {
  345. cout << "Looking for pageId of key:" << key << endl;
  346. K* it = binaryLookup(keyOffset, keyOffset + data->entryCount - 1, key);
  347. //TODO - compare
  348. if (*it < key) {
  349. return &data->rightMostEntry;
  350. }
  351. int pos = it - keyOffset;
  352. unsigned int* pageId = static_cast<unsigned int *>(valueOffset) + pos;
  353. return pageId;
  354. }
  355. /**
  356. * Updates the pageId(value) for a given key and throws an exception if the node is a leaf
  357. */
  358. void updatePageIdForInsertKey(K key, unsigned int newVal) {
  359. if (isLeaf()) {
  360. throw runtime_error("Calling updatePageIdForInsertKey on a leaf");
  361. }
  362. cout << "Updating pageId for key:" << key << endl;
  363. K* it = binaryLookup(keyOffset, keyOffset + data->entryCount - 1, key);
  364. //TODO - compare
  365. if (*it < key) {
  366. data->rightMostEntry = newVal;
  367. } else {
  368. int pos = it - keyOffset;
  369. *(static_cast<unsigned int *>(valueOffset) + pos) = newVal;
  370. }
  371. }
  372. /**
  373. * Returns the maximum key of this node
  374. */
  375. K getMaxKey() {
  376. return *(keyOffset + data->entryCount - 1);
  377. }
  378. /**
  379. * Returns the minimum key of this node
  380. */
  381. K getMinKey() {
  382. return *keyOffset;
  383. }
  384. /**
  385. * Returns the bufferframe of this node
  386. */
  387. BufferFrame& getBufferFrame() {
  388. return bufferFrame;
  389. }
  390. /**
  391. * Sets the entry count for this node
  392. */
  393. void setEntryCount(unsigned int cnt) {
  394. data->entryCount = cnt;
  395. }
  396. /**
  397. * Sets the upper value of the node and throws an exception if the node is a leaf
  398. */
  399. void setUpper(unsigned int val) {
  400. if (!isLeaf()) {
  401. data->rightMostEntry = val;
  402. } else {
  403. throw runtime_error("Set upper is called on an inner node");
  404. }
  405. }
  406. /**
  407. * Returns the upper value of the node and throws an exception if the node is a leaf
  408. */
  409. unsigned int getUpper() {
  410. if (!isLeaf()) {
  411. return data->rightMostEntry;
  412. } else {
  413. throw runtime_error("Get upper is called on an inner node");
  414. }
  415. }
  416. };
  417. #endif