#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 = *(uint32_t*)&value.x.internal;
|
|
|
|
v <<= 4;
|
|
v += *(uint32_t*)&value.y.internal;
|
|
v ^= *(uint64_t*)&value.uuid;
|
|
v ^= *(((uint64_t*)&value.uuid)+1);
|
|
|
|
return v;
|
|
}
|
|
};
|
|
|
|
struct record{
|
|
record()
|
|
{}
|
|
union{
|
|
std::array<uint8_t, 24> full;
|
|
record_identifier split = record_identifier();
|
|
} record_head;
|
|
bitops::regulated<uint64_t> timestamp = 0;
|
|
size_t offset = 0;
|
|
};
|
|
|
|
using db_page = std::array<uint8_t, 16384>;
|
|
|
|
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);
|
|
}
|
|
|
|
constexpr size_t size() {
|
|
return item_size;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
};
|
|
|