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.
 
 
 

202 lines
3.8 KiB

#pragma once
#include <stdint.h>
#include <endian.hpp>
#include <string>
#include <iostream>
#include <assert.h>
// Unix-y stuff
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
struct errno_exception : public std::runtime_error {
errno_exception(int err)
: runtime_error{std::string{"errno with value "}+std::to_string(err)}
{}
};
void throw_errno_if(bool pred)
{
if(pred)
{
throw errno_exception{errno};
}
}
constexpr size_t page_size = 4096;
struct [[gnu::packed]] record_identifier{
bitops::regulated<uint32_t> x = 0;
bitops::regulated<uint32_t> y = 0;
std::array<uint8_t, 16> uuid = {0};
};
template<>
struct std::hash<record_identifier> {
uint64_t operator() (const record_identifier& value) {
uint64_t v = static_cast<uint32_t>(value.x);
v <<= 4;
v += static_cast<uint32_t>(value.y);
v ^= *(uint64_t*)&value.uuid;
v ^= *(((uint64_t*)&value.uuid)+1);
return v;
}
};
enum class record_flags : uint32_t {
confirmation = 1
};
struct [[gnu::packed]] record{
record()
{}
union [[gnu::packed]] {
std::array<uint8_t, 24> full;
record_identifier split = record_identifier();
} record_head;
bitops::regulated<uint64_t> timestamp = 0;
bitops::regulated<uint64_t> offset = 0;
bitops::regulated<uint32_t> flags = 0;
};
constexpr size_t db_page_size = 16384;
using db_page = std::array<uint8_t, db_page_size>;
template<typename T>
struct mmap_ptr{
T* start = nullptr;
size_t offset = 0;
T& operator*(){
return start[offset];
}
T& operator[](const size_t& n){
return start[offset+n];
}
mmap_ptr operator+(size_t offset) {
mmap_ptr ret;
ret.start = start;
ret.offset = offset + this->offset;
return ret;
}
mmap_ptr operator++() {
offset+=1;
mmap_ptr ret = *this;
return ret;
}
mmap_ptr operator++(int) {
mmap_ptr ret = *this;
offset+=1;
return ret;
}
bool operator==(const mmap_ptr& oth) {
return (start == oth.start) && (offset == oth.offset);
}
bool operator!=(const mmap_ptr& oth) {
return !(*this == oth);
}
};
template<typename T>
class mmap_array : public mmap_ptr<T>
{
size_t mapping_size = 0;
int fd = 0;
size_t item_size = 0;
public:
mmap_array() = default;
mmap_array(size_t nb_elem, const std::string& filename)
: mmap_ptr<T>() {
const size_t expected_size = nb_elem*sizeof(T);
const size_t expected_size_mod = expected_size + (
(expected_size%page_size != 0)?
page_size - expected_size%page_size
: 0
);
fd = open(
filename.c_str(),
O_RDWR | O_CREAT,
S_ISUID + S_ISGID + S_IRUSR + S_IWUSR + S_IRGRP + S_IWGRP
);
throw_errno_if(fd < 0);
struct stat data;
int status = fstat(fd, &data);
throw_errno_if(status < 0);
if((size_t)data.st_size < expected_size_mod)
{
status = ftruncate(fd, expected_size_mod);
throw_errno_if(status < 0);
}
this->start = (T*)mmap(NULL, expected_size_mod, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
throw_errno_if(this->start == nullptr);
mapping_size = expected_size_mod;
item_size = mapping_size / sizeof(T);
auto map_access = MADV_RANDOM;
if(expected_size_mod <= 1 << 20) {
map_access |= MADV_WILLNEED;
}
#ifdef MADV_DONTDUMP
map_access |= MADV_DONTDUMP;
#endif
this->offset = 0;
posix_madvise(this->start, mapping_size, map_access);
}
void enforce_caching() {
posix_madvise(this->start, mapping_size, MADV_WILLNEED);
}
constexpr size_t size() {
return item_size;
}
int fd_v() const {
return fd;
}
constexpr mmap_ptr<T> begin() const {
mmap_ptr<T> ret = *this;
return ret;
}
constexpr mmap_ptr<T> end() const {
mmap_ptr<T> ret = *this;
return ret+item_size;
}
void clear() {
munmap(this->start, mapping_size);
close(fd);
}
~mmap_array() {
//std::cerr << "unmapping disabled" << std::endl;
if(false)//this->start != nullptr)
{
munmap(this->start, mapping_size);
close(fd);
}
}
};