#ifndef _PAGECACHE_HH_ #define _PAGECACHE_HH_ #include #include #include "interfaces.hh" #include "mtprim.hh" class PageCache { private: struct _allocInfo; public: class Handle { public: Handle() : alloc_(nullptr) { } Handle(Handle const& copy); ~Handle(); Handle& operator=(Handle const& copy); char *data() { return alloc_->virtMem + ofs_*4096; } void setDirty(); void flush(); private: Handle(_allocInfo* alloc, int ofs); _allocInfo *alloc_; int ofs_; friend class PageCache; }; PageCache(int maxPages = -1); ~PageCache(); // Allocate memory in the cache and fill it with data from dev // If the data already exists in the cache a Handle to that entry may be returned Handle readAllocate(IBlockDevice& dev, unsigned pos, unsigned count); // Allocate memory in the cache without reading from device // This prevents useless reads if you're going to overwrite the entire range anyways // If the data already exists in the cache a Handle to that entry may be returned Handle writeAllocate(IBlockDevice& dev, unsigned pos, unsigned count); // Flush all dirty cached pages to their block devices void sync(); // Eject pages from cache. If lengthHint is > 0, try to free at least that many pages void eject(int lengthHint); private: int maxPages_, curPages_; Mutex mutex_; struct _allocInfo { IBlockDevice *dev; unsigned start; unsigned len; uintptr_t physMem; char *virtMem; bool dirty; int refs; }; std::map > allocs_; void freeAlloc(_allocInfo& alloc); void buildAlloc(_allocInfo& alloc, unsigned len); _allocInfo* searchAlloc(IBlockDevice* dev, unsigned start, unsigned len); void _eject(int lengthHint); }; #endif