Advertisement
Guest User

Untitled

a guest
Jul 3rd, 2015
181
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.34 KB | None | 0 0
  1. template<typename K, class D>
  2. class PageManager {
  3. private:
  4. Node* first;
  5. Node* last;
  6. K nodecount = 0;
  7. K max_nodes = 0;
  8. std::hash_set<K, Node*> page_table;
  9. void* flusher = NULL; // The flusher is a callback function which is called when pages
  10. // fall off the tail of the LRU maintained by the PageManager.
  11. // The callback has a fucntion signature of:
  12. // bool flusher(PageManager::Node* n)
  13. //
  14. // You can set the default flusher with a member function. If,
  15. // after being invoked, the default flusher function returns false,
  16. // the PageManager will assert as the database is not in a
  17. // consistent state. You should probably retry at least once
  18. // after IO errors etc, to verify an error condition before
  19. // returning false.
  20. //
  21. // if data in node is a pointer and needs to be freed, free it
  22. // here. Note that nodes that require special handling can have
  23. // custom flushers. A custom flusher returns a boolean
  24. // return true. In this case, the default flusher (if any)
  25. // associated with the PageManager will not be called. If the
  26. // custom flusher returns false, then the node will be sent
  27. // to the default flusher (if any).
  28.  
  29. D loader = NULL; // The opposite of the flusher, the loader loads a page on a
  30. // miss of the LRU and puts the new data at the head.
  31. // Must return the same type as the second parameter to the
  32. // class template (D) and take an argument of the first type K.
  33. // For example if the nodes in the LRU store pointers to pages,
  34. // and the pages are identified by an __int128, then the loader
  35. // function would be defined like:
  36. // Page* load_page(__int128 page_no);
  37. // You must throw an exception if there is an error loading
  38. // the page.
  39.  
  40. class Node {
  41. Node* next=NULL;
  42. Node* prev=NULL;
  43. void* callback;
  44. K key;
  45.  
  46. public:
  47. D data=NULL;
  48.  
  49. // node has data but is not connected to linked list
  50. Node(K k, D d, void* flush_func= NULL) {
  51. key = k;
  52. data = d;
  53. callback = flush_func;
  54. prev = NULL;
  55. next = NULL;
  56. }
  57.  
  58. D get_data() {
  59. return data;
  60. }
  61.  
  62. K get_key() {
  63. return key;
  64. }
  65.  
  66. void set_callback(void *flush_func) {
  67. callback = flush_func;
  68. }
  69.  
  70. void exec_callback() {
  71. (*callback)(this);
  72. }
  73.  
  74. };
  75.  
  76. public:
  77. PageManager PageManager(K sz=2000, void* default_flusher=NULL) {
  78. set_size(sz);
  79. nodecount = 0;
  80. flusher = default_flusher;
  81. }
  82.  
  83. /* if this shrinks, the next addition to the LRU will rapidly prune
  84. * the LRU, flusing each of the removed nodes if a flusher is
  85. * defined. Minimum size is 128 and any value less than that is
  86. * adjusted up.
  87. */
  88. void set_size(K sz) {
  89. if(sz <128) sz=128;
  90. max_nodes = sz;
  91. }
  92.  
  93.  
  94.  
  95. /* when a page falls off the LRU it is flushed to disk */
  96. void flush_block(Node *n) {
  97. assert(n != NULL && n->data != NULL);
  98. if(flusher_func)
  99. return (*flusher_func)(n);
  100. }
  101.  
  102. /* Iterate the linked list trying to find the specified page number.
  103. * Also populates min/max values for min_page and max_page
  104. * if necessary. This scans the whole list, but this
  105. * single scan can save many successive scans so it is
  106. * worth it, besides we might be finding a page near
  107. * the tail anyway.
  108. */
  109. Node* find(K key) {
  110. Node *n;
  111. /* list is empty or invalid page requested */
  112. if(nodecount == 0) return NULL;
  113. assert(key > 0);
  114. if(!(tmp=page_table[key])) {
  115. if(loader) {
  116. D d;
  117. d = (*loader)(k);
  118. assert(n != NULL);
  119. add(k,d,false);
  120. }
  121. return NULL;
  122. }
  123. return tmp;
  124. }
  125. add(K k, D d) {
  126. return add(k,d, true);
  127. }
  128.  
  129. private:
  130. Node* add(K k, D d, bool search) {
  131. Node* tmp = NULL;
  132.  
  133. /* if search is false, then the node will be unconditionally added to the head,
  134. otherwise search to see if it already exists. This is dangerous, so only
  135. the find function uses this after loading a page on am miss. This is because
  136. such a page is guaranteed to go to the head, and if it called the add member
  137. without setting search=false, it would enter a recursive loop.
  138. */
  139. if(!no_search) tmp = find(k);
  140.  
  141. /* add the node at the head */
  142. if(tmp == NULL) {
  143. tmp = new Node(k, d);
  144.  
  145. /* this is the first node being added*/
  146. if(!nodecount) {
  147. last = first = tmp;
  148. }
  149. page_table[n->key] = n;
  150. ++nodecount;
  151. return tmp;
  152. /* Else update the page with the new data and moves it to head,
  153. unless sequential mode is on, in which case the page stays in
  154. place (it must for the file window optimization to work properly) */
  155. } else {
  156. /* update the previous node and set the pointer to the
  157. * next node on that page to be the pointer to the next
  158. * node on this page. This "unlinks" the page from the
  159. * middle of the LRU so that it can be repositioned as
  160. * the head */
  161. tmp->prev->next = tmp->next;
  162.  
  163. /* connect the new head to the current head by setting
  164. * the next pointer on the old head */
  165. tmp->next = first;
  166.  
  167. /* then update the old head prev pointer to point to
  168. * the new head */
  169. first->prev = tmp;
  170.  
  171. /* Finally replace the head pointer */
  172. first = tmp;
  173.  
  174. }
  175. tmp->data = p;
  176. /* first node was added */
  177. if(nodecount == 1) {
  178. page_table[n->key] = n;
  179. return(first = last = n);
  180. }
  181.  
  182. while(nodecount > max_blocks) {
  183. --nodecount;
  184. /*flush the buffer to disk,
  185. * then unlink the bottom page*/
  186. flush(last);
  187. last->prev->next = NULL;
  188. page_table->erase(last->key);
  189. delete last;
  190. if(nodecount == 0) {
  191. first = NULL;
  192. last = NULL;
  193. min_page = max_page = 0;
  194. }
  195. }
  196.  
  197. return tmp;
  198.  
  199. }
  200.  
  201. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement