X Tutup
#include"PageCache.h" //类内声明,类外初始化 PageCache PageCache::_sInst; // 向系统申请k页内存 void* PageCache::SystemAllocPage(size_t k) { return ::SystemAlloc(k); } //申请num页的内存 Span* PageCache::NewSpan(size_t num) { std::lock_guard lock(_mtx); //针对直接申请大于128页的内存,直接向系统要 if (num >= 128) { //在系统申请 void* ptr = SystemAllocPage(num); Span* span = new Span; span->_pageId = (ADDRES_INT)ptr >> PAGE_SHIFT; span->_n = num; { //std::lock_guard lock(_map_mtx); _idSpanMap[span->_pageId] = span; } return span; } else { if (!_spanList[num - 1].isEmpty()) _spanList[num - 1].isEmpty(); //走到这里说明没有内存,需要向后判断是否有num页的内存 //向后找 for (int i = num; i < 128; i++) { if (!_spanList[i].isEmpty()) { //切num页给_spanList[num - 1] Span* span = _spanList[i].PopFront(); //切出来的内存---采用尾切 Span* split = new Span; split->_n = num; split->_next = nullptr; //span中有多页,它存储的页号是第一页的页号,因此这里的页号应该是切出来的页数+初始页号 split->_pageId = span->_pageId+span->_n-num; // 改变切出来span的页号和span的映射关系 { //std::lock_guard lock(_map_mtx); for (PageID i = 0; i < num; ++i) { _idSpanMap[split->_pageId + i] = split; } } //将Span剩余的页挂在对应的位置 span->_n -= num; _spanList[span->_n - 1].PushFront(span); return split; } } //走到这里说明page cache中没有内存,向系统申请 Span* bigSpan = new Span; void* memory = SystemAllocPage(MAX_PAGE); //计算出页号 bigSpan->_pageId = (size_t)memory >> 12; bigSpan->_n = MAX_PAGE; // 按页号和span映射关系建立,也就是这么多个页都映射在这个span中 { //std::lock_guard lock(_map_mtx); for (PageID i = 0; i < bigSpan->_n; ++i) { PageID id = bigSpan->_pageId + i; _idSpanMap[id] = bigSpan; } } //将内存链接到spanlist中 _spanList[MAX_PAGE - 1].Insert(_spanList[MAX_PAGE - 1].Begin(), bigSpan); //重新切割 return NewSpan(num); } } //通过内存地址在map中查找对应的span Span* PageCache::GetSpanToMap(void* mem) { //根据内存计算页号 PageID id = (ADDRES_INT)mem >> PAGE_SHIFT; //在map中查找 auto ret = _idSpanMap.get(id); if (ret != nullptr) { return ret; } else { assert(false); return nullptr; } } // 释放空闲span回到Pagecache,并合并相邻的span void PageCache::ReleaseSpanToPageCache(Span* span) { if (span->_n >= MAX_PAGE) { //大于128页的内存直接还给系统内存 _idSpanMap.erase(span->_pageId); //根据页号计算地址 void* ptr = (void*)(span->_pageId << PAGE_SHIFT); SystemFree(ptr); delete span; return; } std::lock_guard lock(_mtx); // 检查前后空闲span页,进行合并,解决内存碎片问题 // 向前合并 while (1) { PageID preId = span->_pageId - 1; Span* preSpan = _idSpanMap.get(preId); if (preSpan == nullptr) { break; } // 如果前一个页的span还在使用中,结束向前合并 if (preSpan->_usecount != 0) { break; } // 开始合并... // 超过128页,不需要合并了 if (preSpan->_n + span->_n >= MAX_PAGE) { break; } // 从对应的span链表中解下来,再合并 _spanList[preSpan->_n].Erase(preSpan); span->_pageId = preSpan->_pageId; span->_n += preSpan->_n; // 更新页之间映射关系 { //std::lock_guard lock(_map_mtx); for (PageID i = 0; i < preSpan->_n; ++i) { _idSpanMap[preSpan->_pageId + i] = span; } } delete preSpan; } // 向后合并 while (1) { PageID nextId = span->_pageId + span->_n; Span* nextSpan = _idSpanMap.get(nextId); if (nextSpan == nullptr) { break; } //Span* nextSpan = ret->second; if (nextSpan->_usecount != 0) { break; } // 超过128页,不需要合并了 if (nextSpan->_n + span->_n >= MAX_PAGE) { break; } _spanList[nextSpan->_n].Erase(nextSpan); span->_n += nextSpan->_n; { //std::lock_guard lock(_map_mtx); for (PageID i = 0; i < nextSpan->_n; ++i) { _idSpanMap[nextSpan->_pageId + i] = span; } } delete nextSpan; } // 合并出的大span,插入到对应的链表中 _spanList[span->_n].PushFront(span); }
X Tutup