#ifndef qEzyOXbTTD6KlhKDUsawdWmx6c0 #define qEzyOXbTTD6KlhKDUsawdWmx6c0 #include #include #include #include #include #include #include #include using std::string; struct MemPool : boost::noncopyable { explicit MemPool(size_t size); // anonymous in-memory-pool MemPool(size_t size, int fd); // mmap()ed memory pool MemPool(size_t size, const string filename); // mmap()ed memory pool MemPool(MemPool &&src); // move ctor MemPool& operator=(MemPool&&); MemPool& operator=(MemPool&) = delete; MemPool& operator=(MemPool) = delete; ~MemPool(); inline void* operator() () const; // return memory region; TODO: pure attr inline size_t getSize() const; void sync() const; // call msync() void advise(size_t start, size_t len, int adv); protected: void *base; size_t size; bool isMMap; void doMMap(int fd, size_t size); int openMMappableFile(const string filename, size_t size); private: static char* global_offset; MemPool() = delete; MemPool(const MemPool&) = delete; }; char* MemPool::global_offset = (char*) (void*) 0x2fffff000000; inline void* MemPool::operator() () const { return base; } inline size_t MemPool::getSize() const { return size; } MemPool::MemPool(size_t size) : size(size), isMMap(false) { if (size == 0) { base = NULL; }else{ base = malloc(size); assert(base != NULL); } } MemPool::MemPool(size_t size, int fd) : size(size),isMMap(true) { if (size == 0) { base = NULL; }else{ doMMap(fd, size); } } MemPool::MemPool(size_t size, const string filename) : size(size), isMMap(true) { if (size == 0) { base = NULL; }else{ doMMap(openMMappableFile(filename, size), size); } } MemPool::MemPool(MemPool &&src) : base(src.base), size(src.size), isMMap(src.isMMap) { // std::cout << "Mempool " << base << " moved via copy" << std::endl; src.base = NULL; src.size = 0; } MemPool& MemPool::operator= (MemPool &&src) { // std::cout << "Mempool " << base << " moved via assignment" << std::endl; base = src.base; size = src.size; isMMap = src.isMMap; src.base = NULL; src.size = 0; return *this; } MemPool::~MemPool() { // std::cout << "Mempool " << base << " terminated"; if (size == 0 or base == NULL) { // std::cout << " from move" << std::endl; return; }else{ // std::cout << std::endl; } if (isMMap) { sync(); munmap(base, size); }else{ free(base); } } void MemPool::sync() const { if (isMMap) msync(base, size, MS_SYNC); } void MemPool::advise(size_t start, size_t len, int adv) { // adjust region to page boundary (defensive) if (start & 4095) { len -= 4096 - (start & 4095); len &= ~4095; start &= 4095; start +=1; } // detect underflow and to large len if (len < size) { assert(madvise((char*) base + start, len, adv) == 0); } } void MemPool::doMMap(int fd, size_t size) { base = (void*) mmap((void*) global_offset, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NONBLOCK, fd, 0); assert(base != MAP_FAILED); assert(base == (void*) global_offset); global_offset += ((size / 4096 + 1) * 4096) + 1024 * 4096; } int MemPool::openMMappableFile(const string filename, size_t size) { int fd = open(filename.c_str(), O_RDWR | O_CREAT | O_LARGEFILE | O_NOATIME, 0644); assert(fd != -1); // check if the file size is correct struct stat st; fstat(fd, &st); if ((size_t) st.st_size < size) { // write one byte at the end of the file to make it big enough for the later mmap call (mmap does not increase file size) assert(lseek64(fd, size-1, SEEK_SET) != (off_t) -1); char c(0); assert(write(fd, &c, 1) == 1); } return fd; } #endif // qEzyOXbTTD6KlhKDUsawdWmx6c0