|
|
- #pragma once
- #include "fsized_map.h"
- #include <chrono>
- #include <random>
-
-
- enum class data_mode {
- A,
- B,
- AB
- };
-
- struct metadata_t{
- bitops::regulated<uint64_t> record_cnt;
- bitops::regulated<uint64_t> page_cnt;
- bitops::regulated<uint64_t> delete_cnt;
- bitops::regulated<uint64_t> last_page;
- bitops::regulated<uint64_t> last_delete;
- };
-
- class database {
-
- database(){}
-
- public:
- mmap_array<std::pair<bitops::regulated<uint64_t>, record>> records;
-
- mmap_array<db_page> pages;
-
- mmap_array<metadata_t> metadata;
-
- mmap_array<size_t> delete_table;
-
- database(
- const std::string& records,
- const std::string& pages,
- const std::string& deletions,
- const std::string& meta,
- const size_t& record_cnt = 4096,
- const size_t& page_cnt = 4096,
- const size_t& delete_cnt = 512
- )
- : records{record_cnt, records}
- , pages{page_cnt, pages}
- , metadata{(size_t)1, meta}
- , delete_table{delete_cnt, deletions}
- {}
-
- static void mark_empty_page(db_page& gojp, size_t idx)
- {
- auto& gojmark = *(std::array<bitops::regulated<uint32_t>, db_page_size/sizeof(uint32_t)>*)&gojp;
- bitops::regulated<uint32_t> mark = 0;
- std::array<char,4> mark_array = {'G', 'o', 'J', '@'};
- mark.internal = *(uint32_t*)&mark_array;
- uint32_t slice = static_cast<uint32_t>(idx);
-
- for(size_t mpos = 0; mpos < gojmark.size(); mpos+=2)
- {
- gojmark[mpos] = mark;
- gojmark[mpos+1] = slice++;
- }
- }
-
- static database&& create(const std::string dir, size_t page_nb) {
- database ret{
- dir+"records",
- dir+"pages",
- dir+"deleted",
- dir+"meta",
- page_nb+page_nb/2,
- page_nb,
- page_nb/8
- };
-
- std::cout << "Record table: ";
- for(auto& n : ret.records)
- {
- n.second.timestamp = 0;
- n.second.offset = 0;
- n.second.flags = 0;
- }
- std::cout << "DONE" << std::endl;
-
- std::cout << "Delete table: ";
- for(auto& n : ret.delete_table)
- {
- n = std::numeric_limits<size_t>::max();
- }
- std::cout << "DONE" << std::endl;
-
- for(size_t idx = 0; idx < ret.pages.size(); idx++)
- {
- mark_empty_page(ret.pages[idx], idx);
- if(idx % 120000 == 0)
- {
- std::cout << "Page markings: " << uint16_t(100.0f*float(idx)/float(ret.pages.size())) << "%" << std::endl;
- }
- }
- std::cout << "Page markings: DONE" << std::endl;
-
- (*ret.metadata).last_page = 0;
- (*ret.metadata).last_delete = 0;
- (*ret.metadata).record_cnt = page_nb+page_nb/2;
- (*ret.metadata).page_cnt = page_nb;
- (*ret.metadata).delete_cnt = page_nb/8;
-
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wreturn-local-addr"
- return std::move(ret);
- #pragma GCC diagnostic pop
- }
-
- static database&& open(const std::string dir) {
- mmap_array<metadata_t> tmp{(size_t)1, dir+"meta"};
-
- database ret{
- dir+"records",
- dir+"pages",
- dir+"deleted",
- dir+"meta",
- (*tmp).record_cnt,
- (*tmp).page_cnt,
- (*tmp).delete_cnt
- };
-
- tmp.clear();
-
- ret.records.enforce_caching();
-
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wreturn-local-addr"
- return std::move(ret);
- #pragma GCC diagnostic pop
- }
-
- /**************************************************************************
- * *
- * NO CONFIRM OPS *
- * *
- * *
- *************************************************************************/
-
- record write(const record_identifier& target, const db_page& value){
- uint64_t page = std::numeric_limits<uint64_t>::max();;
- size_t off = std::numeric_limits<size_t>::max();
- if(metadata[0].last_delete>0)
- {
- off = (*metadata).last_delete;
- page = delete_table[off-1];
- } else {
- page = (*metadata).last_page;
- if(page>=pages.size()) {
- throw std::runtime_error("PAGE STARVATION! MUST EXIT NOW");
- }
- }
-
- if(page == std::numeric_limits<uint64_t>::max())
- {
- throw std::runtime_error("PAGE ERROR! MUST EXIT NOW");
- }
-
- pages[page] = value;
-
- uint64_t hashed = std::hash<record_identifier>{}(target);
- uint64_t hashed_roll = hashed;
- bool succeed = false;
-
-
- uint64_t ts = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
- std::pair<bitops::regulated<uint64_t>,record> tmp{0, record{}};
- tmp.first = hashed;
- tmp.second.record_head.split = target;
- tmp.second.timestamp = ts;
- tmp.second.offset = page;
- tmp.second.flags = (uint32_t)record_flags::confirmation;
- do{
- uint64_t pos = hashed_roll % records.size();
-
- switch (static_cast<uint64_t>(records[pos].second.timestamp)) {
- case 0:
- [[fallthrough]];
- case std::numeric_limits<uint64_t>::max():
- records[pos] = tmp;
- succeed = true;
- break;
- default:
- break;
- }
-
- hashed_roll++;
- }while(!succeed);
-
- if(off != std::numeric_limits<size_t>::max())
- {
- (*metadata).last_delete += -1;
- delete_table[off] = std::numeric_limits<size_t>::max();
- } else {
- (*metadata).last_page += (size_t)1;
- }
- return tmp.second;
- }
-
- std::pair<record, db_page> read(const record_identifier& target) {
- std::pair<record, db_page> ret;
- ret.second.fill(0);
-
- uint64_t hashed = std::hash<record_identifier>{}(target);
- uint64_t hashed_roll = hashed;
-
- do{
- uint64_t pos = hashed_roll % records.size();
-
- auto& value = records[pos].second;
- switch (static_cast<uint64_t>(value.timestamp)) {
- case 0:
- return ret;
- case std::numeric_limits<uint64_t>::max():
- break;
- default:
- if(records[pos].first == hashed)
- if(std::hash<record_identifier>{}(value.record_head.split) == hashed)
- {
- if(ret.first.timestamp<value.timestamp)
- {
- ret.first = value;
- ret.second = pages[value.offset];
- }
- break;
- }
- }
-
- hashed_roll++;
- }while(true);
- return ret;
- }
-
- void remove(const record_identifier& target) {
- uint64_t hashed = std::hash<record_identifier>{}(target);
- uint64_t hashed_roll = hashed;
-
- do{
- uint64_t pos = hashed_roll % records.size();
-
- auto& value = records[pos].second;
- switch (static_cast<uint64_t>(value.timestamp)) {
- case 0:
- return;
- case std::numeric_limits<uint64_t>::max():
- break;
- default:
- if(records[pos].first == hashed)
- if(std::hash<record_identifier>{}(value.record_head.split) == hashed)
- {
- value.timestamp = std::numeric_limits<uint64_t>::max();
- (*metadata).last_delete+=1;
- delete_table[(*metadata).last_delete-1] = value.offset;
- mark_empty_page(pages[value.offset], value.offset);
- value.offset = 0;
- }
- break;
- }
-
- hashed_roll++;
- }while(true); // return only happens on hitting a case 0
- }
-
- void rollback(const record_identifier&) {
-
- }
-
- /**************************************************************************
- * *
- * CONFIRM OPS *
- * *
- * *
- *************************************************************************/
-
- record stepped_write(const record_identifier& target, const db_page& value){
- uint64_t page = std::numeric_limits<uint64_t>::max();;
- size_t off = std::numeric_limits<size_t>::max();
- if(metadata[0].last_delete>0)
- {
- off = (*metadata).last_delete;
- page = delete_table[off-1];
- } else {
- page = (*metadata).last_page;
- if(page>=pages.size()) {
- throw std::runtime_error("PAGE STARVATION! MUST EXIT NOW");
- }
- }
-
- if(page == std::numeric_limits<uint64_t>::max())
- {
- throw std::runtime_error("PAGE ERROR! MUST EXIT NOW");
- }
-
- pages[page] = value;
-
- uint64_t hashed = std::hash<record_identifier>{}(target);
- uint64_t hashed_roll = hashed;
- bool succeed = false;
-
-
- uint64_t ts = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
- std::pair<bitops::regulated<uint64_t>,record> tmp{0, record{}};
- tmp.first = hashed;
- tmp.second.record_head.split = target;
- tmp.second.timestamp = ts;
- tmp.second.offset = page;
- tmp.second.flags = 0;
- do{
- uint64_t pos = hashed_roll % records.size();
-
- switch (static_cast<uint64_t>(records[pos].second.timestamp)) {
- case 0:
- [[fallthrough]];
- case std::numeric_limits<uint64_t>::max():
- records[pos] = tmp;
- succeed = true;
- break;
- default:
- break;
- }
-
- hashed_roll++;
- }while(!succeed);
-
- if(off != std::numeric_limits<size_t>::max())
- {
- (*metadata).last_delete += -1;
- delete_table[off] = std::numeric_limits<size_t>::max();
- } else {
- (*metadata).last_page += (size_t)1;
- }
- return tmp.second;
- }
-
- record try_allocate(const record_identifier& target)
- {
- auto attempt = read(target);
- if(attempt.first.timestamp == 0)
- {
- db_page rnd_page;
- {
- std::random_device dev;
- std::minstd_rand temprng(dev());
-
- auto tmp = (std::array<uint32_t, sizeof(db_page)/sizeof(uint32_t)>*)&rnd_page;
- std::generate(tmp->begin(), tmp->end(), temprng);
- }
-
- return write(target, rnd_page);
- }
-
- return record{};
- }
-
- std::pair<record, db_page> stepped_read(const record_identifier& target) {
- std::pair<record, db_page> ret;
- ret.second.fill(0);
-
- uint64_t hashed = std::hash<record_identifier>{}(target);
- uint64_t hashed_roll = hashed;
-
- do{
- uint64_t pos = hashed_roll % records.size();
-
- auto& value = records[pos].second;
- switch (static_cast<uint64_t>(value.timestamp)) {
- case 0:
- return ret;
- case std::numeric_limits<uint64_t>::max():
- break;
- default:
- if(records[pos].first == hashed)
- if(std::hash<record_identifier>{}(value.record_head.split) == hashed)
- {
- if(static_cast<uint32_t>(value.flags) & (uint32_t)record_flags::confirmation)
- if(ret.first.timestamp<value.timestamp)
- {
- ret.first = value;
- ret.second = pages[value.offset];
- }
- break;
- }
- }
-
- hashed_roll++;
- }while(true);
- return ret;
- }
-
- void stepped_remove(const record_identifier& target) {
- remove(target);
- }
-
- void confirm(const record_identifier& target, const bitops::regulated<uint64_t>& timestamp) {
- uint64_t hashed = std::hash<record_identifier>{}(target);
- uint64_t hashed_roll = hashed;
-
- do{
- uint64_t pos = hashed_roll % records.size();
-
- auto& value = records[pos].second;
- switch (static_cast<uint64_t>(value.timestamp)) {
- case 0:
- return;
- case std::numeric_limits<uint64_t>::max():
- break;
- default:
- if(records[pos].first == hashed)
- if(std::hash<record_identifier>{}(value.record_head.split) == hashed)
- {
- if(timestamp == value.timestamp)
- {
- value.flags = (uint32_t)value.flags | (uint32_t)record_flags::confirmation;
- }
- break;
- }
- }
-
- hashed_roll++;
- }while(true);
- }
- };
|