Goddess of Justice DB, the database used for storage on IzaroDFS
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

222 lines
5.1 KiB

пре 5 година
пре 5 година
  1. #pragma once
  2. #include "fsized_map.h"
  3. #include <chrono>
  4. struct metadata_t{
  5. bitops::regulated<uint64_t> record_cnt;
  6. bitops::regulated<uint64_t> page_cnt;
  7. bitops::regulated<uint64_t> delete_cnt;
  8. bitops::regulated<uint64_t> last_page;
  9. bitops::regulated<uint64_t> last_delete;
  10. };
  11. class database {
  12. database(){}
  13. public:
  14. mmap_array<std::pair<bitops::regulated<uint64_t>, record>> records;
  15. mmap_array<db_page> pages;
  16. mmap_array<metadata_t> metadata;
  17. mmap_array<size_t> delete_table;
  18. database(
  19. const std::string& records,
  20. const std::string& pages,
  21. const std::string& deletions,
  22. const std::string& meta,
  23. const size_t& record_cnt = 4096,
  24. const size_t& page_cnt = 4096,
  25. const size_t& delete_cnt = 512
  26. )
  27. : records{record_cnt, records}
  28. , pages{page_cnt, pages}
  29. , metadata{(size_t)1, meta}
  30. , delete_table{delete_cnt, deletions}
  31. {}
  32. static database&& create(const std::string dir, size_t page_nb) {
  33. database ret{
  34. dir+"records",
  35. dir+"pages",
  36. dir+"deleted",
  37. dir+"meta",
  38. page_nb+page_nb/2,
  39. page_nb,
  40. page_nb/8
  41. };
  42. for(auto& n : ret.records)
  43. {
  44. n.second.timestamp = 0;
  45. n.second.offset = 0;
  46. }
  47. for(auto& n : ret.delete_table)
  48. {
  49. n = std::numeric_limits<size_t>::max();
  50. }
  51. (*ret.metadata).last_page = 0;
  52. (*ret.metadata).last_delete = 0;
  53. (*ret.metadata).record_cnt = page_nb+page_nb/2;
  54. (*ret.metadata).page_cnt = page_nb;
  55. (*ret.metadata).delete_cnt = page_nb/8;
  56. #pragma GCC diagnostic push
  57. #pragma GCC diagnostic ignored "-Wreturn-local-addr"
  58. return std::move(ret);
  59. #pragma GCC diagnostic pop
  60. }
  61. static database&& open(const std::string dir) {
  62. mmap_array<metadata_t> tmp{(size_t)1, dir+"meta"};
  63. database ret{
  64. dir+"records",
  65. dir+"pages",
  66. dir+"deleted",
  67. dir+"meta",
  68. (*tmp).record_cnt,
  69. (*tmp).page_cnt,
  70. (*tmp).delete_cnt
  71. };
  72. tmp.clear();
  73. ret.records.enforce_caching();
  74. #pragma GCC diagnostic push
  75. #pragma GCC diagnostic ignored "-Wreturn-local-addr"
  76. return std::move(ret);
  77. #pragma GCC diagnostic pop
  78. }
  79. void write(const record_identifier& target, const db_page& value){
  80. uint64_t page = std::numeric_limits<uint64_t>::max();;
  81. size_t off = std::numeric_limits<size_t>::max();
  82. if(metadata[0].last_delete>0)
  83. {
  84. off = (*metadata).last_delete;
  85. page = delete_table[off-1];
  86. } else {
  87. page = (*metadata).last_page;
  88. if(page>=pages.size()) {
  89. throw std::runtime_error("PAGE STARVATION! MUST EXIT NOW");
  90. }
  91. }
  92. if(page == std::numeric_limits<uint64_t>::max())
  93. {
  94. throw std::runtime_error("PAGE ERROR! MUST EXIT NOW");
  95. }
  96. pages[page] = value;
  97. uint64_t hashed = std::hash<record_identifier>{}(target);
  98. uint64_t hashed_roll = hashed;
  99. bool succeed = false;
  100. uint64_t ts = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
  101. std::pair<bitops::regulated<uint64_t>,record> tmp{0, record{}};
  102. tmp.first = hashed;
  103. tmp.second.record_head.split = target;
  104. tmp.second.timestamp = ts;
  105. tmp.second.offset = page;
  106. do{
  107. uint64_t pos = hashed_roll % records.size();
  108. switch (static_cast<uint64_t>(records[pos].second.timestamp)) {
  109. case 0:
  110. [[fallthrough]];
  111. case std::numeric_limits<uint64_t>::max():
  112. records[pos] = tmp;
  113. succeed = true;
  114. break;
  115. default:
  116. break;
  117. }
  118. hashed_roll++;
  119. }while(!succeed);
  120. if(off != std::numeric_limits<size_t>::max())
  121. {
  122. (*metadata).last_delete += -1;
  123. delete_table[off] = std::numeric_limits<size_t>::max();
  124. } else {
  125. (*metadata).last_page += (size_t)1;
  126. }
  127. }
  128. std::pair<uint64_t, db_page> read(const record_identifier& target) {
  129. std::pair<uint64_t, db_page> ret;
  130. ret.first = 0;
  131. ret.second.fill(0);
  132. uint64_t hashed = std::hash<record_identifier>{}(target);
  133. uint64_t hashed_roll = hashed;
  134. do{
  135. uint64_t pos = hashed_roll % records.size();
  136. auto& value = records[pos].second;
  137. switch (static_cast<uint64_t>(value.timestamp)) {
  138. case 0:
  139. return ret;
  140. case std::numeric_limits<uint64_t>::max():
  141. break;
  142. default:
  143. if(records[pos].first == hashed)
  144. if(std::hash<record_identifier>{}(value.record_head.split) == hashed)
  145. {
  146. if(ret.first<value.timestamp)
  147. {
  148. ret.first = value.timestamp;
  149. ret.second = pages[value.offset];
  150. }
  151. break;
  152. }
  153. }
  154. hashed_roll++;
  155. }while(true);
  156. return ret;
  157. }
  158. void remove(const record_identifier& target) {
  159. uint64_t hashed = std::hash<record_identifier>{}(target);
  160. uint64_t hashed_roll = hashed;
  161. do{
  162. uint64_t pos = hashed_roll % records.size();
  163. auto& value = records[pos].second;
  164. switch (static_cast<uint64_t>(value.timestamp)) {
  165. case 0:
  166. return;
  167. case std::numeric_limits<uint64_t>::max():
  168. break;
  169. default:
  170. if(records[pos].first == hashed)
  171. if(std::hash<record_identifier>{}(value.record_head.split) == hashed)
  172. {
  173. value.timestamp = std::numeric_limits<uint64_t>::max();
  174. (*metadata).last_delete+=1;
  175. delete_table[(*metadata).last_delete-1] = value.offset;
  176. value.offset = 0;
  177. break;
  178. }
  179. }
  180. hashed_roll++;
  181. }while(true); // return only happens on hitting a case 0
  182. }
  183. void rollback(const record_identifier&) {
  184. }
  185. };