#pragma once #include #include #include #include #include // Unix-y stuff #include #include #include #include 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 x = 0; bitops::regulated y = 0; std::array uuid = {0}; }; template<> struct std::hash { uint64_t operator() (const record_identifier& value) { uint64_t v = static_cast(value.x); v <<= 4; v += static_cast(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 full; record_identifier split = record_identifier(); } record_head; bitops::regulated timestamp = 0; bitops::regulated offset = 0; bitops::regulated flags = 0; }; constexpr size_t db_page_size = 16384; using db_page = std::array; template 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 class mmap_array : public mmap_ptr { 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() { 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 begin() const { mmap_ptr ret = *this; return ret; } constexpr mmap_ptr end() const { mmap_ptr 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); } } };