Goddess of Justice DB, the database used for storage on IzaroDFS
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

202 linhas
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);
}
}
};